如何在已显示的Bokeh图表中添加新的Candle实例?
在Bokeh中显示图表后添加第四个Candle实例的解决方案
你说得没错——直接调用show(plot)生成的静态HTML确实没法动态添加新数据,因为这个静态文件已经把所有初始数据和渲染逻辑都固化了,没有后端或前端的动态更新机制。不过有两种靠谱的方法能实现你要的功能,下面详细说:
方法一:使用Bokeh Server(推荐用于实时/动态场景)
Bokeh Server是Bokeh专门用来做交互式动态可视化的工具,它能让Python代码直接和前端页面交互,随时更新图表数据。步骤如下:
- 先把你的Candle实例转换成Bokeh能识别的
ColumnDataSource格式(这是Bokeh管理数据的核心对象); - 创建蜡烛图的渲染元素(高低线+实体柱);
- 写一个更新函数,用来把新的Candle数据追加到数据源;
- 用Bokeh Server启动应用,就能在页面上触发更新了。
举个完整的代码例子:
from bokeh.models import ColumnDataSource, Button from bokeh.plotting import figure, curdoc from bokeh.layouts import column # 假设你的Candle类定义如下 class Candle: def __init__(self, time, highest, lowest, open, close): self.time = time self.highest = highest self.lowest = lowest self.open = open self.close = close # 初始化三个蜡烛实例 candle1 = Candle("2024-01-01", 100, 90, 95, 98) candle2 = Candle("2024-01-02", 105, 97, 98, 102) candle3 = Candle("2024-01-03", 110, 100, 102, 108) # 转换为ColumnDataSource所需的字典格式 source = ColumnDataSource(data={ 'time': [c.time for c in [candle1, candle2, candle3]], 'high': [c.highest for c in [candle1, candle2, candle3]], 'low': [c.lowest for c in [candle1, candle2, candle3]], 'open': [c.open for c in [candle1, candle2, candle3]], 'close': [c.close for c in [candle1, candle2, candle3]] }) # 创建蜡烛图 p = figure(x_axis_type='categorical', title="实时股票蜡烛图", x_axis_label="日期", y_axis_label="价格") # 绘制高低影线 p.segment(x0='time', y0='high', x1='time', y1='low', source=source, color='black') # 绘制蜡烛实体(上涨绿,下跌红) p.vbar(x='time', width=0.6, top='open', bottom='close', source=source, fill_color='#2ecc71', line_color='black') p.vbar(x='time', width=0.6, top='close', bottom='open', source=source, fill_color='#e74c3c', line_color='black') # 定义添加新蜡烛的函数 def add_fourth_candle(): # 创建第四个Candle实例 candle4 = Candle("2024-01-04", 115, 105, 108, 112) # 用stream方法追加新数据(比update更高效,适合实时场景) source.stream({ 'time': [candle4.time], 'high': [candle4.highest], 'low': [candle4.lowest], 'open': [candle4.open], 'close': [candle4.close] }) # 添加一个按钮触发更新 add_button = Button(label="添加第四个蜡烛", button_type="success") add_button.on_click(add_fourth_candle) # 把图表和按钮加入文档 curdoc().add_root(column(p, add_button))
运行方式:保存成stock_candles.py,然后在终端执行bokeh serve --show stock_candles.py,浏览器会打开一个页面,点击按钮就能看到第四个蜡烛被添加进去了。
方法二:使用CustomJS在静态页面更新(无需后端)
如果不想搭Bokeh Server,也可以在生成静态HTML的时候,给页面加一个前端回调逻辑,用JavaScript来更新数据。这种方法适合不需要后端计算的简单场景:
from bokeh.models import ColumnDataSource, CustomJS, Button from bokeh.plotting import figure, show from bokeh.layouts import column # 同样的初始Candle实例和数据源 class Candle: def __init__(self, time, highest, lowest, open, close): self.time = time self.highest = highest self.lowest = lowest self.open = open self.close = close candle1 = Candle("2024-01-01", 100, 90, 95, 98) candle2 = Candle("2024-01-02", 105, 97, 98, 102) candle3 = Candle("2024-01-03", 110, 100, 102, 108) source = ColumnDataSource(data={ 'time': [c.time for c in [candle1, candle2, candle3]], 'high': [c.highest for c in [candle1, candle2, candle3]], 'low': [c.lowest for c in [candle1, candle2, candle3]], 'open': [c.open for c in [candle1, candle2, candle3]], 'close': [c.close for c in [candle1, candle2, candle3]] }) p = figure(x_axis_type='categorical', title="静态页面蜡烛图", x_axis_label="日期", y_axis_label="价格") p.segment(x0='time', y0='high', x1='time', y1='low', source=source, color='black') p.vbar(x='time', width=0.6, top='open', bottom='close', source=source, fill_color='#2ecc71', line_color='black') p.vbar(x='time', width=0.6, top='close', bottom='open', source=source, fill_color='#e74c3c', line_color='black') # 编写前端JavaScript回调 update_callback = CustomJS(args=dict(source=source), code=""" // 定义第四个蜡烛的数据(这里可以根据需要修改) const newCandle = { time: ["2024-01-04"], high: [115], low: [105], open: [108], close: [112] }; // 追加数据到数据源 source.stream(newCandle); """) # 创建按钮绑定回调 add_button = Button(label="添加第四个蜡烛", button_type="success") add_button.js_on_click(update_callback) # 布局并生成静态HTML layout = column(p, add_button) show(layout)
运行这个代码后,会生成一个静态HTML文件,打开后点击按钮就能在前端直接添加新蜡烛,不需要任何后端服务。
为什么直接用show(plot)不行?
当你调用show(plot)时,Bokeh会把所有数据和渲染逻辑打包成静态HTML/JavaScript文件,Python进程执行完就结束了,页面里的内容是固定的——没有任何机制能让你从外部(不管是Python还是前端)修改已渲染的图表数据。所以必须用上面两种方法中的一种,给页面加上动态更新的逻辑。
内容的提问来源于stack exchange,提问作者Javier Guzmán
相关产品推荐
相关产品推荐

