如何修改代码实现Flask多路由部署多个Bokeh Server绘图?
解决Flask多路由嵌入不同Bokeh绘图的问题
我帮你梳理下问题:你在原有Flask+Bokeh整合的代码基础上添加了/plot路由后程序崩溃,大概率是因为没有正确在Bokeh Server中注册第二个绘图应用,或者路由引用的路径配置有误。下面是针对你使用的Bokeh 0.12.14版本的完整解决方案:
核心思路
要在不同Flask路由展示不同Bokeh绘图,需要做到两点:
- 在Bokeh Server中注册独立的Bokeh应用(每个绘图对应一个应用)
- 每个Flask路由生成对应Bokeh应用的嵌入脚本,指向正确的Bokeh Server路径
完整代码示例
1. Flask主文件(比如app.py)
from flask import Flask, render_template from bokeh.embed import server_document from bokeh.server.server import Server from tornado.ioloop import IOLoop from threading import Thread app = Flask(__name__) # --- 第一个绘图:主页面的绘图 --- def modify_doc_main(doc): from bokeh.plotting import figure from bokeh.models import ColumnDataSource # 这里写你原来的modify_doc绘图逻辑 source = ColumnDataSource(data=dict(x=[1, 2, 3], y=[4, 5, 6])) p = figure(title="主页面绘图") p.circle(x='x', y='y', source=source, size=10, color="navy") doc.add_root(p) # --- 第二个绘图:/plot路由的网格绘图 --- def modify_doc_grid(doc): from bokeh.layouts import gridplot from bokeh.plotting import figure # 这里写你的网格绘图逻辑 p1 = figure(plot_width=250, plot_height=250, title="图1") p1.circle([1, 2, 3], [4, 5, 6], color="red") p2 = figure(plot_width=250, plot_height=250, title="图2") p2.line([1, 2, 3], [6, 5, 4], color="green") p3 = figure(plot_width=250, plot_height=250, title="图3") p3.square([1, 2, 3], [5, 3, 4], color="orange") # 创建网格布局 grid = gridplot([[p1, p2], [p3, None]]) doc.add_root(grid) # --- 启动Bokeh Server的线程 --- def bokeh_server_worker(): # 注册两个Bokeh应用,分别对应不同路径 server = Server( { '/main_app': modify_doc_main, '/grid_app': modify_doc_grid }, io_loop=IOLoop(), # 必须包含Flask的运行地址,否则WebSocket连接会被拒绝 allow_websocket_origin=["localhost:8000"] ) server.start() server.io_loop.start() # --- Flask路由 --- @app.route('/') def main_page(): # 生成指向Bokeh Server中/main_app的嵌入脚本 script = server_document('http://localhost:5006/main_app') return render_template("embed.html", script=script) @app.route('/plot') def grid_plot_page(): # 生成指向Bokeh Server中/grid_app的嵌入脚本 script = server_document('http://localhost:5006/grid_app') return render_template("embed.html", script=script) if __name__ == '__main__': # 启动Bokeh Server线程 Thread(target=bokeh_server_worker).start() # 启动Flask服务,端口8000(和Bokeh Server的5006区分开) app.run(port=8000, debug=True)
2. 模板文件(templates/embed.html)
在项目根目录创建templates文件夹,放入下面的模板:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Bokeh绘图展示</title> {{ script|safe }} </head> <body> <!-- Bokeh绘图会自动渲染在这里 --> </body> </html>
关键注意事项(避免崩溃的核心)
- Bokeh Server应用注册:每个绘图必须对应一个独立的
modify_doc函数,并且在Server中注册不同的路径(比如/main_app和/grid_app),不能重复路径。 - 跨域配置:
allow_websocket_origin必须包含Flask的运行地址(比如localhost:8000),否则Bokeh的实时交互连接会被拒绝,导致页面崩溃。 - 端口区分:Bokeh Server默认用5006端口,Flask用8000,避免端口冲突。
可选:静态绘图嵌入(无需Bokeh Server)
如果你的绘图不需要动态交互(比如滑块、按钮),可以用components函数生成静态片段,不需要启动Bokeh Server线程,更轻量:
from flask import Flask, render_template from bokeh.embed import components from bokeh.plotting import figure from bokeh.layouts import gridplot app = Flask(__name__) @app.route('/') def static_main(): p = figure(title="静态主绘图") p.circle([1,2,3], [4,5,6]) script, div = components(p) return render_template("static_embed.html", script=script, div=div) @app.route('/plot') def static_grid(): p1 = figure(plot_width=200, plot_height=200) p1.circle([1,2,3], [4,5,6]) p2 = figure(plot_width=200, plot_height=200) p2.line([1,2,3], [6,5,4]) grid = gridplot([[p1,p2]]) script, div = components(grid) return render_template("static_embed.html", script=script, div=div) if __name__ == '__main__': app.run(port=8000, debug=True)
对应的static_embed.html模板需要引入Bokeh的CSS和JS:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>静态Bokeh绘图</title> <link rel="stylesheet" href="https://cdn.bokeh.org/bokeh/release/bokeh-0.12.14.min.css" type="text/css" /> <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-0.12.14.min.js"></script> {{ script|safe }} </head> <body> {{ div|safe }} </body> </html>
内容的提问来源于stack exchange,提问作者machump
相关产品推荐
相关产品推荐

