我有一个
shiny
应用程序,它使用
folium
在地图上显示多个图层。
我想让用户能够将其中一个图层(线串地理数据框)下载为地理包文件。
这是我到目前为止的代码:
# relevant imported packages
from shiny import App, render, ui, reactive
import pandas as pd
import geopandas as gpd
# code in the ui for the download button
ui.download_button(id="downloadRoute", label="Get the route file"),
# code in the server function
@output
@render.download
def downloadRoute():
result_value = result()
route = result_value['route_detailed']
with io.BytesIO() as buffer:
route.to_file(buffer, driver='GPKG')
buffer.seek(0)
return ui.download(filename="my_route.gpkg", file=buffer.read(), content_type="application/geopackage+sqlite3")
我已经验证
route
实际上是一个有效的地理数据框。如果我在闪亮之外下载它,它是一个有效的地理包。
在闪亮中,单击下载按钮不会在 UI 上执行任何操作。它只在控制台中打印此错误:
500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "pyogrio\_io.pyx", line 1268, in pyogrio._io.ogr_create
File "pyogrio\_err.pyx", line 177, in pyogrio._err.exc_wrap_pointer
pyogrio._err.CPLE_OpenFailedError: sqlite3_open(<_io.BytesIO object at 0x000002494BFCE3E0>) failed: unable to open database file
我做错了什么?我还有其他方法可以实现这一目标吗?
在闪亮应用程序中遇到错误是因为试图将 geopackage 写入存储在内存中的 BytesIO 对象,而不是文件系统上的实际文件。然后,当闪亮尝试读取此 BytesIO 对象以提供下载时,它会遇到问题,因为它预计文件路径是有效的。
以下是如何使用服务器端临时文件修复代码的方法:
from shiny import App, render, ui, reactive
import pandas as pd
import geopandas as gpd
import tempfile
import os
# ui 中的下载按钮代码
ui.download_button(id="downloadRoute", label="获取路线文件"),
# 服务器函数中的代码
@output
@render.download
def downloadRoute():
result_value = result()
route = result_value['route_detailed']
# 创建一个临时文件
with tempfile.NamedTemporaryFile(delete=False, suffix=".gpkg") as tmp:
filepath = tmp.name
# 将 geodataframe 保存到临时文件
route.to_file(filepath, driver='GPKG')
# 返回一个下载处理程序,该处理程序将在发送后删除临时文件
return ui.download(
filename="my_route.gpkg",
content=lambda: open(filepath, "rb").read(),
content_type="application/geopackage+sqlite3",
on_done=lambda: os.remove(filepath),
)
这个修改后的代码做了以下工作:
-
创建一个临时文件:
它使用
tempfile.NamedTemporaryFile()
创建一个唯一的临时文件,该文件在发送后将被删除。 -
将 geodataframe 保存到文件:
它使用 geopandas
to_file()
方法将route
geodataframe 保存到创建的临时文件中。 -
返回下载处理程序:
它返回一个
ui.download
处理程序,该处理程序执行以下操作:-
将文件名设置为
my_route.gpkg
。 -
使用
content
参数读取并提供临时文件的内容。 -
设置正确的
content_type
。 -
使用
on_done
参数确保在将文件发送到浏览器后删除临时文件。
-
将文件名设置为
通过这种方法,正在创建一个可以通过
ui.download
处理的有效文件,从而防止出现错误并允许用户下载 geopackage 文件。