我写了一本jupyter笔记本,我想使用voila来创建一个小型Web应用程序/工具。
该工具要做的是获取一个 geojson文件,其中包含来自用户的许多多边形,并返回包含许多 geojson文件的zip文件(每个文件多边形)。例如,如果用户将Geojson文件带有20个多边形(它们都在同一文件中),则输出应为一个zip文件,其中包含20个单独的Geojson文件 - 每个Polygon文件。
我可以在本地进行,并根据需要保存邮政编码。
但是,我想使用voila渲染它,以便以后可以从任何地方使用,这意味着zip文件将在内存/in-thin-thin-thin-thim-a-a-buffer中创建(不确定哪个术语是准确的一个)然后,用户将能够通过自动下载或单击按钮或使用弹出窗口下载下载zip文件,这确实无关紧要。
这是我的代码的片段(让我知道它是否不够):
def on_button_clicked(event):
with output:
clear_output()
df = gpd.GeoDataFrame().from_features(json.loads(upload.data[0])) # if the file is geojson
display(HTML(f'<h4><left>There are {len(df)} polygons in the file</left></h4>'))
# make results.zip in temp directory
# https://gist.github.com/simonthompson99/362404d6142db3ed14908244f5750d08
tmpdir = tempfile.mkdtemp()
zip_fn = os.path.join(tmpdir, 'results.zip')
zip_obj = zipfile.ZipFile(zip_fn, 'w')
for i in range(df.shape[0]):
if len(field_names_col.value)==0:
field_name = f'field_{str(i+1)}'
else:
field_name = df[field_names_col.value][i]
output_name = f'{field_name}.{output_format.value.lower()}'
df.iloc[[i]].to_file(f'{tmpdir}\\{output_name}', driver=output_format.value)
for f in glob.glob(f"{tmpdir}/*"):
zip_obj.write(f, os.path.basename(f)) # add file to archive, second argument is the structure to be represented in zip archive, i.e. this just makes flat strucutre
zip_obj.close()
button_send.on_click(on_button_clicked)
vbox_result = widgets.VBox([button_send, output])
重要的部分接近末端:
for f in glob.glob(f"{tmpdir}/*"):
zip_obj.write(f, os.path.basename(f)) # add file to archive, second argument is the structure to be represented in zip archive, i.e. this just makes flat strucutre
zip_obj.close()
我迭代临时单独的文件并创建存储在 zip_obj中的临时zip文件(results.zip)
。如何使用jupyter笔记本“将”这个ZIP对象“推”到用户下载?
我尝试使用( zip_obj.close()
):
local_file = FileLink(os.path.basename(f), result_html_prefix="Click here to download: ")
display(local_file)
但是,我在使用voila渲染时会遇到错误:
路径(results.zip)不存在。它可能仍在
被生成,或者您可能有不正确的路径。
例如,为了在当地保存它:
with zipfile.ZipFile('c:/tool/results.zip', 'w') as zipf:
for f in tmpdir.glob("*"):
zipf.write(f, arcname=f.name)
I writing a jupyter notebook, which I would like to render using Voila to create a small web app/tool.
What the tool does is to get one Geojson file containing many polygons from the user and return a ZIP file containing many GeoJSON files (a file per polygon). For example, if the user uploads a GeoJSON file with 20 polygons (they are all in the same file), then the output should be a ZIP file containing 20 separate GeoJSON files - file per polygon.
I am able to do it locally and the ZIP file is saved as needed.
However, I would like to render it using Voila so that it can later work from anywhere, meaning the ZIP file will be created in-memory/on-the-fly/as-a-buffer (not sure which term is the accurate one) and then the user will be able to download the ZIP file, via automatic download, or by clicking on a button or with a pop-up window to download, it really does not matter here.
Here is a snippet of my code (let me know if it's not enough):
def on_button_clicked(event):
with output:
clear_output()
df = gpd.GeoDataFrame().from_features(json.loads(upload.data[0])) # if the file is geojson
display(HTML(f'<h4><left>There are {len(df)} polygons in the file</left></h4>'))
# make results.zip in temp directory
# https://gist.github.com/simonthompson99/362404d6142db3ed14908244f5750d08
tmpdir = tempfile.mkdtemp()
zip_fn = os.path.join(tmpdir, 'results.zip')
zip_obj = zipfile.ZipFile(zip_fn, 'w')
for i in range(df.shape[0]):
if len(field_names_col.value)==0:
field_name = f'field_{str(i+1)}'
else:
field_name = df[field_names_col.value][i]
output_name = f'{field_name}.{output_format.value.lower()}'
df.iloc[[i]].to_file(f'{tmpdir}\\{output_name}', driver=output_format.value)
for f in glob.glob(f"{tmpdir}/*"):
zip_obj.write(f, os.path.basename(f)) # add file to archive, second argument is the structure to be represented in zip archive, i.e. this just makes flat strucutre
zip_obj.close()
button_send.on_click(on_button_clicked)
vbox_result = widgets.VBox([button_send, output])
The important part is near the end:
for f in glob.glob(f"{tmpdir}/*"):
zip_obj.write(f, os.path.basename(f)) # add file to archive, second argument is the structure to be represented in zip archive, i.e. this just makes flat strucutre
zip_obj.close()
I iterate over the temporary separate files and create a temporary ZIP file (results.zip) stored in the zip_obj
. How can I "push" this ZIP object to the user for download using Jupyter Notebook?
I tried using (just before or just after zip_obj.close()
):
local_file = FileLink(os.path.basename(f), result_html_prefix="Click here to download: ")
display(local_file)
But I get an error when rendering it with Voila:
Path (results.zip) doesn't exist. It may still be in the process of
being generated, or you may have the incorrect path.
For example, to save it locally I did:
with zipfile.ZipFile('c:/tool/results.zip', 'w') as zipf:
for f in tmpdir.glob("*"):
zipf.write(f, arcname=f.name)
发布评论
评论(1)
There's an example of making a download link that will show up in the Voila rendering 在这里。 (从在这里,尽管那里的焦点也上传了示例。 A/60013735/8508004“>此处的答案,转换为您的案例:
为底部部分的其他类型的文件(目前在其中的所有内容)中说明了这两个选项,答案在这里。
There's an example of making a download link that will show up in the Voila rendering here. (Learned of it from here, although the focus there was on file upload. The example covers downloading the results, too.) A simpler take on this is found at the bottom of this answer here, converted to your case:
These two options are illustrated for a different type of file in the bottom section (everything below the line break presently there) of the answer here.