#!/usr/bin/env python
# coding: utf-8
# # 07 [補充] Jupyter 裡的 Widgets
#
# 有很多同學問到, 我們用 `ipywidgets` 的 `interact` 或 `interact_manual` 可以做得更漂亮、更客制化我們想要的功能嗎?
#
# 答案是肯定的。
#
# 這就要用到眾多很酷的 widgets。雖然每次設定麻煩一點點, 但不管是種類還是自由度都高很多。
# ## 1. Widgets 概念
#
# 我們先來引入一個 `widget`, 然後大概介紹這有可能可以做什麼。
# In[1]:
from ipywidgets.widgets import *
from IPython.display import display
# 這裡要注意, 有個 `widget` 叫 `HTML`, 但這和之前我們引入的
#
# ```python
# from IPython.display import HTML
# ```
#
# 是不同的!
# In[2]:
html = HTML('
Hi
')
# In[3]:
display(html)
# 這目前看來一樣? 不一樣是我們可以 display 很多次, 而且你可以之後修改顯示內容。
# In[4]:
display(html)
# In[5]:
html.value = '你好
'
# 你會發現, 兩次的 display 都改了!! 這有什麼好處呢? 這就是我們放上一個在網頁上的 widget, 我們可以去改變它呈現的樣子。
#
# 為了示範一個「小動畫」例子, 我們做一隻會跑的蟲。為了不要讓蟲蟲「瞬間移動」, 我們引入 `sleep`。
# In[6]:
from time import sleep
# In[7]:
worm = HTML('oooo
')
# In[8]:
display(worm)
for i in range(80):
htmlbase = '%s
'
html = htmlbase % (" " * (i+1) + "oooo")
worm.value = html
sleep(0.2)
# 這裡說明一下, 我們用到的
#
#
#
# 是 HTML 的空白。直接打空白你會發現 HTML 不理你, 當然你也可以直接打「全型的空白」, 因為 HTML 基本上當成一個文字, 所以會乖乖顯示。
#
# 而
#
# sleep(0.2)
#
# 是說讓 Python 「睡」 0.2 秒, 再繼繼下一個動作。
# #### [練習] 讓蟲蟲爬回來
#
# 有同學問到, 可以自動讓蟲蟲爬回來可以嗎? 當然可以啊, 試試看吧 :)
# ## 2. 進度條
#
# 進度條就是像我們下載大型檔案時, 電腦會出現目前已進行多少百分比的進度那個指示條。你可以看到反正每次要使用一個 widget, 就是先宣告一個 widget, 然後用 `display` 顯示出來。再來就是可以改一些裡面的設定, 最常改的就是 `value`。
# In[9]:
p = IntProgress()
# In[10]:
display(p)
# 這空空的進度條當然沒什麼好看的, 我們可以設任一個 0 到 100 的數字給它, 比如說:
# In[11]:
p.value=55
# 當然會動的進度表更有感覺 :)
#
# 為了看清楚, 我們再一次顯示同一個進度表, 注意和之前的進度表是完全連動的!
# In[12]:
display(p)
for i in range(101):
p.value = i
sleep(0.1)
# ## 3. 老朋友, 數值滑桿
#
# 我們回來看看之前用 `interact` 就會出現的數值滑桿。我們為何要自已呼叫呢? 因為更可以完全客制化, 更彈性的運用。
# In[13]:
s = IntSlider(min=1, max=10)
s.style.handle_color="#44AF69"
#s.style.background_color="#1FDE91"
#s.color="#44AF69"
#s.slider_color="#FCAB10"
#s.background_color="#1FDE91"
# In[14]:
display(s)
# 倒底有什麼參數可以改呢? 我們可以列出來看看。
# In[15]:
s.keys
# 而且, 我們還可以客制化的精美數值滑桿用到之前的 `interact` 中。
# In[16]:
from ipywidgets import interact
# In[17]:
def f(x):
print(x)
# In[18]:
interact(f, x=s);
# ## 4. 應該有個叫按鈕的東西
#
# 互動介面中, 我們常常用到的按鈕, 應該有個吧? 那是當然的。按鈕和之前的應用有點不一樣的是, 按下去應該要執行一個動作, 這個動作我們通常會寫成一個函數。
# In[19]:
b = Button(
description='按我',
button_style='info', # 這風格還有 'success', 'warning', 'danger' 等等
width='100px'
)
# In[20]:
display(b)
# 目前按一按沒有什麼特別效果, 我們為了示範, 先來寫個耍寶小程式。
#
# 首先我們用 `HTML` 讀入一張圖。
# In[21]:
img_html = HTML("")
# In[22]:
display(img_html)
# 試著讓圖動一下。
# In[23]:
display(img_html)
for i in range(60):
img_html.value = " " * i + ""
sleep(0.1)
# 接下來我們想按按鈕, 就讓這隻熊熊開始動。我們再度顯示按鈕和熊熊。
# In[24]:
display(b)
display(img_html)
def on_button_clicked(b):
for i in range(60):
img_html.value = " " * i + ""
sleep(0.1)
b.on_click(on_button_clicked)
# ## 5. 文字框輸入後...
#
# 大家還記得我們要做「拍拍機器人」。這就要用文字框輸入, 然後 `submit` 後機器人會回話。如下圖。
#
#
#
# 首先, 我們先弄個文字框。
# In[25]:
me = Text("輸入訊息...")
me.description = "輸入"
# 再來用盡洪荒之力, 把所有會的 CSS 都弄上去。一個風格是準備給自己的發言 (`style1`), 一個是給拍拍機器人 (`style2`)。
# In[26]:
style1 = ""
style2 = "
"
# 我們「高級」對話程式來了, 當文字框被 `submit`, 我們就要把我們說的話、拍拍機器人的回話顯示出來。
# In[27]:
def pipi(sender):
display(HTML(style1 + me.value + '
'))
display(HTML(style2 + '拍拍' + '
'))
me.value = ''
# 告訴我們的文字輸入框, 如果按下 enter, 也就是 `submit`, 就執行 `pipi` 這個函數。
# In[28]:
me.on_submit(pipi)
# 最後 display 我們的輸入框就好了!
# In[29]:
display(me)
# #### [練習]
# 其實這拍拍機器人還有很多不完美的地方 (當然包括 AI, 但現在我們說的是界面上的問題), 想辦法改善它!
# ## 6. 連結兩個 widgets
#
# 有時我們想同時可以用文字對話框輸入數字, 也可以用數值滑桿輸同一個數字, 這要怎麼做到呢? 這就要新開啟一個神秘套件叫 `
# In[30]:
from traitlets import link
# 設個數字輸入框、數值滑桿。
# In[31]:
ftxt = FloatText()
fsld = FloatSlider()
# 設好連結, 把兩個 widgets 的物件同步。
# In[32]:
mylink = link((ftxt, 'value'), (fsld, 'value'))
# 顯示出來試試是不是真的同步了。
# In[33]:
display(ftxt, fsld)
# 我們也可以取消同步。
# In[34]:
mylink.unlink()
# ## 7. Layout
#
# 我們想排一排我們的 widgets, 可以用 `HBox`, `VBox`, `Tabs` 等等來達成。
#
#
#
# In[35]:
buttons = [Button(description=str(i)) for i in range(1,10)]
# 稍稍設一下 9 個按鈕的風格。
# In[36]:
for b in buttons:
b.button_style = "info"
b.width = "50px"
# 顯示出來!
# In[37]:
groups = [buttons[3*i:3*i+3] for i in range(3)]
# In[38]:
layout = VBox([HBox(groups[0]), HBox(groups[1]), HBox(groups[2])])
# In[39]:
display(layout)
# #### [練習]
#
# 試試可不可以寫出一個 Jupyter 計算機!
# ## 8. 延伸活動
#
# 在哪裡還可以找到一些 `ipywidgets` 更深入的資訊、範例呢? 這裡介紹一些, 都是很適合閃電秀的主題哦。
# #### `ipywidgets` 官方文件
#
# 通常官方文件都不是聽來很令人振奮的東西, 不過 `ipywidgets` 的官方文件目前還是大概包含最多資訊、包括一些基礎教學的地方。
#
# [`ipywidgets` 官方文件](http://ipywidgets.readthedocs.io/)
#
# 比如說, 我們可以在這找到[所有可以用的 widgets 列表](http://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html)。
# #### 進階應用
#
# 這麼炫的工具當然也有人寫了進階應用的套件。我們來看三個例子:
#
# * [bqplot](https://github.com/bloomberg/bqplot): 可以做 2D 互動畫圖的函式庫。
# * [pythreejs](https://github.com/jovyan/pythreejs): 讓你在 Jupyter 中使用 [three.js](https://threejs.org/) 這個 JavaScript 3D 函式庫!
# * [ipyleaflet](https://github.com/ellisonbg/ipyleaflet): 在 Jupyter 中用 [Leaflet](http://leafletjs.com/) 個互動地圖!