{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# ipywidgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Notes\n", "\n", "* [Jupyter-flex doc](https://jupyter-flex.extrapolations.dev/) example 裡有所有 ipywidgets demo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ipysheet\n", "\n", "* 實測沒辦法當 user input 用\n", " * 無法直接從剪貼簿貼上一個 cell range(不過[有人](https://github.com/QuantStack/ipysheet/issues/5) request 了)\n", " * 從 ipysheet 複製到剪貼簿倒是可以\n", " * 一格一格敲完後也不知道怎麼把值傳回 df(ipysheet.calculation 只能用來加 cell 之間的 dependency)\n", " * [這裡](https://stackoverflow.com/questions/59899960/ipywidget-text-input-and-ipysheet-interacting-voila)說 Voila 無法 render ipysheet" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "dcbe75f30431498285620f928e7e50c6", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Sheet(cells=(Cell(column_end=0, column_start=0, row_end=0, row_start=0, type='numeric', value=0.0), Cell(colum…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import ipysheet \n", "import numpy as np\n", "from ipysheet import to_dataframe\n", "from pandas import DataFrame\n", "\n", "sheet = ipysheet.sheet(rows=3, columns=2)\n", "\n", "df = DataFrame(np.zeros((3, 2)))\n", "\n", "def record(change):\n", " for i in range(3):\n", " for j in range(2): \n", " df.iloc[i, j] = cell(i, j).value\n", "\n", "for i in range(3):\n", " for j in range(2):\n", " ipysheet.cell(i, j).observe(record, 'value')\n", "\n", "sheet" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Math Formula Generator\n", "\n", "* [這裡](https://github.com/jupyter-widgets/ipywidgets/issues/2280)有在討論怎麼把 widgets 轉成 static image" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mSignature:\u001b[0m \u001b[0mtxt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mon_msg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcallback\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mremove\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m\n", "(Un)Register a custom msg receive callback.\n", "\n", "Parameters\n", "----------\n", "callback: callable\n", " callback will be passed three arguments when a message arrives::\n", "\n", " callback(widget, content, buffers)\n", "\n", "remove: bool\n", " True if the callback should be unregistered.\n", "\u001b[0;31mFile:\u001b[0m /srv/conda/envs/notebook/lib/python3.7/site-packages/ipywidgets/widgets/widget.py\n", "\u001b[0;31mType:\u001b[0m method\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import ipywidgets as widgets\n", "\n", "txt = widgets.Textarea(\n", " value='Hello World',\n", " placeholder='Type something',\n", " description='String:',\n", " disabled=False\n", ")\n", "import numpy as np\n", "\n", "txt.on_msg?" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "09902fe3a4b94497a8a1d900cd47c63a", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Textarea(value='')" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d91cbf3f71a243be87d2c6de59a38350", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(description='Convert', style=ButtonStyle())" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f33fd5248a1949fca7b172a5221427a1", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Output()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# mathurl\n", "\n", "import ipywidgets as widgets\n", "from IPython.display import display, clear_output\n", "\n", "formulaInput = widgets.Textarea()\n", "button = widgets.Button(description='Convert')\n", "output = widgets.Output()\n", "\n", "def test(f):\n", " with output:\n", " clear_output()\n", " display(widgets.HTMLMath(formulaInput.value))\n", "\n", "button.on_click(test)\n", "\n", "display(formulaInput, button, output)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* matplotlib 就可以 render 數學式了" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# https://stackoverflow.com/questions/14110709/creating-images-of-mathematical-expressions-from-tex-using-matplotlib\n", "\n", "import pylab\n", "\n", "formula = r'$x=3^2, y = \\frac{1}{\\frac{2}{3}}}$'\n", "\n", "fig = pylab.figure()\n", "text = fig.text(0, 0, formula)\n", "\n", "# Saving the figure will render the text.\n", "dpi = 300\n", "fig.savefig('formula.png', dpi=dpi)\n", "\n", "# Now we can work with text's bounding box.\n", "bbox = text.get_window_extent()\n", "width, height = bbox.size / float(dpi) + 0.005\n", "\n", "# Adjust the figure size so it can hold the entire text.\n", "fig.set_size_inches((width, height))\n", "\n", "# Adjust text's vertical position.\n", "dy = (bbox.ymin/float(dpi))/height\n", "text.set_position((0, -dy))\n", "\n", "# Save the adjusted text.\n", "fig.savefig('formula.png', dpi=dpi)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* [這裡](https://latex2image.joeraut.com/)有一個 open source JS 版本" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Notebook to PDF Converter Without Callback\n", "\n", "* [FileLink 可以改](https://github.com/voila-dashboards/voila/issues/578)。同一個 issue,有人示範了 download button,不需要知道 file encoding。下面這個版本可以成功佈署到 Voila 上\n", "* [GridspecLayout](https://blog.jupyter.org/introducing-templates-for-jupyter-widget-layouts-f72bcb35a662) 不好用,試了半天還是用 HBox 和 VBox" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1221067f86d5452097a0a6332eaa8eec", "version_major": 2, "version_minor": 0 }, "text/plain": [ "FileUpload(value={}, description='Upload')" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e65239b10e42477bac37f7b6e25ba15e", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(description='Convert', style=ButtonStyle())" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "fef2420be3524273bf27e570ff66d580", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Output()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ipywidgets import FileUpload, Button, Output\n", "from IPython.display import display, HTML\n", "import subprocess, os, base64\n", "\n", "output = Output()\n", "fileInput = FileUpload()\n", "convertButton = Button(description='Convert')\n", "\n", "def convert(b):\n", " with output:\n", " print('Your PDF will be ready in a few seconds. ')\n", " nbName = list(fileInput.value.keys())[0]\n", " pdfName = nbName.replace('ipynb', 'pdf')\n", " with open(nbName, 'w+b') as f:\n", " f.write(fileInput.data[0])\n", " proc = subprocess.run(['jupyter', 'nbconvert', nbName, '--to', 'pdf'])\n", " if proc.returncode == 1:\n", " print('LaTeX compiling error!')\n", " else:\n", " with open(pdfName, \"rb\") as f:\n", " data = f.read()\n", " b64 = base64.b64encode(data)\n", " payload = b64.decode()\n", " display(HTML(f''' \n", " \n", " '''))\n", "\n", "convertButton.on_click(convert)\n", "\n", "display(fileInput, convertButton, output) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Notebook to PDF Converter\n", "\n", "用 Javascript ```window.location.href``` 可以知道當前 server url。下面這個 app 在 JupyterLab 是完全可以跑的,不過 [Volia 一遇到 Javascript 會有很多問題](https://github.com/voila-dashboards/voila/issues/108),所以用 Voila 佈署失敗。如果把 ```alert(\"aaa\");``` 插在 callback 的最前面,實驗顯示 Voila 根本完全沒有執行 callback。這個 [issue](https://github.com/voila-dashboards/voila-material/issues/18) 提到 Voila 遇到 callback 會失敗的問題。目前還沒有修好" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ba8b29f746e14b82a4c12bab6beaf788", "version_major": 2, "version_minor": 0 }, "text/plain": [ "FileUpload(value={}, description='Upload')" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d34acaf56b8c4983b2344860e653a64b", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(description='Convert', style=ButtonStyle())" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "aa266ac1034d4fe9b97defcfb199a594", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Output()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ipywidgets import FileUpload, Button, Output\n", "from IPython.display import display, FileLink, HTML, Javascript\n", "import subprocess, os\n", "\n", "env = 'lab' # change to 'voila' before deploying\n", "\n", "output = Output()\n", "fileInput = FileUpload()\n", "convertButton = Button(description='Convert')\n", "\n", "def convert(b):\n", " with output:\n", " print('Your PDF will be ready in a few seconds. ')\n", " nbName = list(fileInput.value.keys())[0]\n", " pdfName = nbName.replace('ipynb', 'pdf')\n", " with open(nbName, 'w+b') as f:\n", " f.write(fileInput.data[0]) \n", " proc = subprocess.run(['jupyter', 'nbconvert', nbName, '--to', 'pdf'])\n", " if proc.returncode == 1:\n", " print('LaTeX compiling error!')\n", " else:\n", " pdfPath = '/'.join(['tree'] + str(FileLink(pdfName)).split('/')[3:])\n", " display(HTML('''\n", " \n", " \n", " \n", "
\n", " \n", "
\n", " \n", " \n", " '''% (env, pdfPath)))\n", "\n", "convertButton.on_click(convert)\n", "\n", "display(fileInput, convertButton, output) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Download Button Example in ipywidgets](https://stackoverflow.com/questions/61708701/how-to-download-a-file-using-ipywidget-button)\n", "\n", "This works in Voila, but to download PDF this way one needs to know the encoding of the PDF. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HTML(value='\\n\\n\\n\\n\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "'''\n", "\n", "html_button = html_buttons.format(payload=payload,filename=filename)\n", "display(HTML(html_button))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Get Server URL and Pass to Python\n", "\n", "* 下面這段 code 來自[這裡](https://stackoverflow.com/questions/31818127/can-a-jupyter-ipython-notebook-take-arguments-in-the-url/37134476#37134476)。可能在 Jupyter Notebook 可以跑可是在 JupyterLab 不行因為 JavaScript 被 block 了\n", "* 可能有辦法透過 [pyviz_comms](https://github.com/holoviz/pyviz_comms) 得到 URL(sandbox-stable 上有安裝),不過能不能在 Voila 上跑是另一個問題" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "\n", "IPython.notebook.kernel.execute(\"url = '\" + window.location + \"'\")\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%javascript\n", "\n", "IPython.notebook.kernel.execute(\"url = '\" + window.location + \"'\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Create New Cell Programmatically](https://discourse.jupyter.org/t/how-to-programmatically-add-serveral-new-cells-in-a-notebook-in-jupyterlab/4323)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def create_new_cell(contents):\n", " from IPython.core.getipython import get_ipython\n", " shell = get_ipython()\n", " payload = dict(\n", " source='set_next_input',\n", " text=contents,\n", " replace=False,\n", " )\n", " shell.payload_manager.write_payload(payload, single = False)\n", "\n", "contents = 'print(\"Hello World\")'\n", "create_new_cell(contents=contents)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Hello World\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.8" } }, "nbformat": 4, "nbformat_minor": 4 }