Bokeh 3.3.0服务器:如何通过Tornado API托管图片文件夹实现悬停提示图
Bokeh服务中HoverTool提示框图片无法加载的解决方案
问题背景
在远程服务器上使用Bokeh 3.3.0和Tornado运行可视化服务,图表渲染正常,但鼠标悬停标记时提示框内的图片无法访问。核心原因是图片文件夹未被Tornado托管,导致无法通过HTTP路径访问图片。
现有代码
from bokeh.layouts import column from bokeh.models import ColumnDataSource,HoverTool from bokeh.plotting import figure from bokeh.server.server import Server def bkapp(doc): #get necessary data... dfsource=ColumnDataSource(df) hover = HoverTool(tooltips =""" <div> <div> <img src="@_id.png" style="float: left; margin: 0px 5px 5px 0px;" border="2" ></img> </div> <div> <span style="font-size: 15px;">@_id</span> <span style="font-size: 10px; color: #696;">(@ucx, @ucy)</span> </div> """) # create a plot p = figure(sizing_mode="stretch_width", max_width=2000, height=800, tools=["pan", 'wheel_zoom',"tap","reset"]) p.add_tools(hover) circle = p.circle(source=dfsource,x="ucx",y="ucy") doc.add_root(p) server = Server({'/': bkapp}, num_procs=4) server.start() if __name__ == '__main__': print('Opening Bokeh application on http://localhost:5006/') server.io_loop.add_callback(server.show, "/") server.io_loop.start()
文件夹结构
-cwd --myapp.py --imagefolder/
已尝试的图片路径
src="imagefolder/@_id.png"src="file://@_id.png"src="http://localhost:5006/@_id.png"
解决方案:让Tornado托管图片文件夹
要让Bokeh的Tornado服务器托管静态资源文件夹,需通过Server类的extra_patterns参数添加静态路由,具体步骤如下:
- 导入Tornado静态文件处理器:引入
tornado.web.StaticFileHandler处理静态文件请求。 - 配置静态路由:创建
Server实例时,通过extra_patterns添加指向imagefolder的路由,映射本地文件夹路径与HTTP访问前缀。 - 修正HoverTool图片路径:将
src改为托管后的HTTP路径"/imagefolder/@_id.png"。
修改后的完整代码
from bokeh.layouts import column from bokeh.models import ColumnDataSource, HoverTool from bokeh.plotting import figure from bokeh.server.server import Server from tornado.web import StaticFileHandler import os def bkapp(doc): # get necessary data... dfsource = ColumnDataSource(df) hover = HoverTool(tooltips =""" <div> <div> <img src="/imagefolder/@_id.png" style="float: left; margin: 0px 5px 5px 0px;" border="2" width="100" ></img> </div> <div> <span style="font-size: 15px;">@_id</span> <span style="font-size: 10px; color: #696;">(@ucx, @ucy)</span> </div> """) # create a plot p = figure(sizing_mode="stretch_width", max_width=2000, height=800, tools=["pan", 'wheel_zoom',"tap","reset"]) p.add_tools(hover) circle = p.circle(source=dfsource, x="ucx", y="ucy") doc.add_root(p) # 获取当前脚本所在目录的绝对路径 current_dir = os.path.dirname(os.path.abspath(__file__)) # 配置静态路由:将/imagefolder/路径映射到本地imagefolder文件夹 extra_patterns = [ (r"/imagefolder/(.*)", StaticFileHandler, {"path": os.path.join(current_dir, "imagefolder")}) ] # 创建Server实例时传入extra_patterns server = Server({'/': bkapp}, num_procs=4, extra_patterns=extra_patterns) server.start() if __name__ == '__main__': print('Opening Bokeh application on http://localhost:5006/') print('Images accessible at http://localhost:5006/imagefolder/[image_name].png') server.io_loop.add_callback(server.show, "/") server.io_loop.start()
关键说明
- 静态路由配置:
(r"/imagefolder/(.*)", StaticFileHandler, {"path": ...})表示所有以/imagefolder/开头的请求,都会转发到本地imagefolder文件夹匹配对应图片。 - 绝对路径使用:通过
os.path模块获取绝对路径,避免因运行目录变化导致的路径错误,适配远程服务器环境。 - 路径一致性:HoverTool中的图片路径必须与静态路由完全匹配,确保前端能正确请求到图片资源。
内容的提问来源于stack exchange,提问作者lesolorzanov
相关产品推荐
相关产品推荐

