ipywidgets
Notes
Jupyter-flex doc example 裡有所有 ipywidgets demo
ipysheet
實測沒辦法當 user input 用
[9]:
import ipysheet
import numpy as np
from ipysheet import to_dataframe
from pandas import DataFrame
sheet = ipysheet.sheet(rows=3, columns=2)
df = DataFrame(np.zeros((3, 2)))
def record(change):
for i in range(3):
for j in range(2):
df.iloc[i, j] = cell(i, j).value
for i in range(3):
for j in range(2):
ipysheet.cell(i, j).observe(record, 'value')
sheet
Math Formula Generator
這裡有在討論怎麼把 widgets 轉成 static image
[4]:
import ipywidgets as widgets
txt = widgets.Textarea(
value='Hello World',
placeholder='Type something',
description='String:',
disabled=False
)
import numpy as np
txt.on_msg?
Signature: txt.on_msg(callback, remove=False)
Docstring:
(Un)Register a custom msg receive callback.
Parameters
----------
callback: callable
callback will be passed three arguments when a message arrives::
callback(widget, content, buffers)
remove: bool
True if the callback should be unregistered.
File: /srv/conda/envs/notebook/lib/python3.7/site-packages/ipywidgets/widgets/widget.py
Type: method
[1]:
# mathurl
import ipywidgets as widgets
from IPython.display import display, clear_output
formulaInput = widgets.Textarea()
button = widgets.Button(description='Convert')
output = widgets.Output()
def test(f):
with output:
clear_output()
display(widgets.HTMLMath(formulaInput.value))
button.on_click(test)
display(formulaInput, button, output)
matplotlib 就可以 render 數學式了
[2]:
# https://stackoverflow.com/questions/14110709/creating-images-of-mathematical-expressions-from-tex-using-matplotlib
import pylab
formula = r'$x=3^2, y = \frac{1}{\frac{2}{3}}}$'
fig = pylab.figure()
text = fig.text(0, 0, formula)
# Saving the figure will render the text.
dpi = 300
fig.savefig('formula.png', dpi=dpi)
# Now we can work with text's bounding box.
bbox = text.get_window_extent()
width, height = bbox.size / float(dpi) + 0.005
# Adjust the figure size so it can hold the entire text.
fig.set_size_inches((width, height))
# Adjust text's vertical position.
dy = (bbox.ymin/float(dpi))/height
text.set_position((0, -dy))
# Save the adjusted text.
fig.savefig('formula.png', dpi=dpi)
<Figure size 58.2375x18.8461 with 0 Axes>
這裡有一個 open source JS 版本
Notebook to PDF Converter Without Callback
FileLink 可以改。同一個 issue,有人示範了 download button,不需要知道 file encoding。下面這個版本可以成功佈署到 Voila 上
GridspecLayout 不好用,試了半天還是用 HBox 和 VBox
[2]:
from ipywidgets import FileUpload, Button, Output
from IPython.display import display, HTML
import subprocess, os, base64
output = Output()
fileInput = FileUpload()
convertButton = Button(description='Convert')
def convert(b):
with output:
print('Your PDF will be ready in a few seconds. ')
nbName = list(fileInput.value.keys())[0]
pdfName = nbName.replace('ipynb', 'pdf')
with open(nbName, 'w+b') as f:
f.write(fileInput.data[0])
proc = subprocess.run(['jupyter', 'nbconvert', nbName, '--to', 'pdf'])
if proc.returncode == 1:
print('LaTeX compiling error!')
else:
with open(pdfName, "rb") as f:
data = f.read()
b64 = base64.b64encode(data)
payload = b64.decode()
display(HTML(f'''<a download="{pdfName}" href="data:text/csv;base64,{payload}" target="_blank">
<button class="p-Widget jupyter-widgets jupyter-button widget-button"> Download PDF </button>
</a>'''))
convertButton.on_click(convert)
display(fileInput, convertButton, output)
Notebook to PDF Converter
用 Javascript window.location.href 可以知道當前 server url。下面這個 app 在 JupyterLab 是完全可以跑的,不過 Volia 一遇到 Javascript 會有很多問題,所以用 Voila 佈署失敗。如果把 alert("aaa"); 插在 callback 的最前面,實驗顯示 Voila 根本完全沒有執行 callback。這個 issue 提到 Voila 遇到 callback 會失敗的問題。目前還沒有修好
[8]:
from ipywidgets import FileUpload, Button, Output
from IPython.display import display, FileLink, HTML, Javascript
import subprocess, os
env = 'lab' # change to 'voila' before deploying
output = Output()
fileInput = FileUpload()
convertButton = Button(description='Convert')
def convert(b):
with output:
print('Your PDF will be ready in a few seconds. ')
nbName = list(fileInput.value.keys())[0]
pdfName = nbName.replace('ipynb', 'pdf')
with open(nbName, 'w+b') as f:
f.write(fileInput.data[0])
proc = subprocess.run(['jupyter', 'nbconvert', nbName, '--to', 'pdf'])
if proc.returncode == 1:
print('LaTeX compiling error!')
else:
pdfPath = '/'.join(['tree'] + str(FileLink(pdfName)).split('/')[3:])
display(HTML('''
<html>
<body>
<script type="text/javascript">
function setHref() {
var server = window.location.href;
var homeIdx = server.indexOf("%s");
server = server.slice(0, homeIdx);
var href = server + "%s";
open(href);
}
</script>
<form name="buttonForm">
<button class="p-Widget jupyter-widgets jupyter-button widget-button" onClick="setHref();return true;">
Download PDF
</button>
</form>
</body>
</html>
'''% (env, pdfPath)))
convertButton.on_click(convert)
display(fileInput, convertButton, output)
Download Button Example in ipywidgets
This works in Voila, but to download PDF this way one needs to know the encoding of the PDF.
[2]:
from ipywidgets import HTML
from IPython.display import display
import base64
res = 'computed results'
#FILE
filename = 'res.txt'
b64 = base64.b64encode(res.encode())
payload = b64.decode()
#BUTTONS
html_buttons = '''<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<a download="{filename}" href="data:text/csv;base64,{payload}" download>
<button class="p-Widget jupyter-widgets jupyter-button widget-button mod-warning">Download File</button>
</a>
</body>
</html>
'''
html_button = html_buttons.format(payload=payload,filename=filename)
display(HTML(html_button))
Get Server URL and Pass to Python
下面這段 code 來自這裡。可能在 Jupyter Notebook 可以跑可是在 JupyterLab 不行因為 JavaScript 被 block 了
可能有辦法透過 pyviz_comms 得到 URL(sandbox-stable 上有安裝),不過能不能在 Voila 上跑是另一個問題
[4]:
%%javascript
IPython.notebook.kernel.execute("url = '" + window.location + "'")
Create New Cell Programmatically
[3]:
def create_new_cell(contents):
from IPython.core.getipython import get_ipython
shell = get_ipython()
payload = dict(
source='set_next_input',
text=contents,
replace=False,
)
shell.payload_manager.write_payload(payload, single = False)
contents = 'print("Hello World")'
create_new_cell(contents=contents)
[ ]:
print("Hello World")