loo*_*opy 5 python python-3.x jupyter-notebook ipywidgets
我构建了一个 ipywidget 按钮。我希望当按钮被点击时,程序进行计算,并得到一个结果字符串,然后用户可以将该字符串作为文件下载。
代码是这样的:
import ipywidgets as widgets
download_button = widgets.ToggleButton()
download_button.on_click(do_some_work)
def do_some_work(content)-> str:
res = compute()
# Here comes the problem: how to let user download the res as a file?
def compute()-> str:
# ... do_some_compute
return res
Run Code Online (Sandbox Code Playgroud)
我已多次阅读ipywidgets 文档,但找不到解决方案。
我现在使用另一种方式(严重影响用户体验):创建一个 HTML 小部件,当单击 download_button 时,将 HTML 小部件的值更改为一个链接data:text/plain;charset=utf-8,{res}
以让用户单击并下载,但有什么方法可以实现这一点只需单击一下?
任何帮助将不胜感激。
小智 8
我见过的最优雅的方法是此处的解决方案 1 (略有修改并在下面介绍):
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))
Run Code Online (Sandbox Code Playgroud)
游戏迟到了,但如果其他人面临这个问题并且需要动态文件内容,这里有一个方法。该代码的灵感来自 @Poompil 的答案。此外,可能有更优雅的方法来绕过浏览器缓存,但无法使其在 Jupyter 中工作。
import base64
import hashlib
from typing import Callable
import ipywidgets
from IPython.display import HTML, display
class DownloadButton(ipywidgets.Button):
"""Download button with dynamic content
The content is generated using a callback when the button is clicked.
"""
def __init__(self, filename: str, contents: Callable[[], str], **kwargs):
super(DownloadButton, self).__init__(**kwargs)
self.filename = filename
self.contents = contents
self.on_click(self.__on_click)
def __on_click(self, b):
contents: bytes = self.contents().encode('utf-8')
b64 = base64.b64encode(contents)
payload = b64.decode()
digest = hashlib.md5(contents).hexdigest() # bypass browser cache
id = f'dl_{digest}'
display(HTML(f"""
<html>
<body>
<a id="{id}" download="{self.filename}" href="data:text/csv;base64,{payload}" download>
</a>
<script>
(function download() {{
document.getElementById('{id}').click();
}})()
</script>
</body>
</html>
"""))
Run Code Online (Sandbox Code Playgroud)
现在我们可以简单地添加
DownloadButton(filename='foo.txt', contents=lambda: f'hello {time.time()}', description='download')
Run Code Online (Sandbox Code Playgroud)
它添加了一个下载按钮,当该按钮计时时,会生成下载文件的内容。
归档时间: |
|
查看次数: |
2334 次 |
最近记录: |