You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bokeh图表标题与工具栏未渲染问题求助

排查Bokeh动态添加图表时的渲染异常问题

这个Cannot read property 'draw_legend' of undefined错误大概率不是Bokeh的bug,而是你在多线程环境下操作Bokeh文档的方式不符合它的线程安全要求,加上旧版本Bokeh的一些限制导致的。我来给你拆解问题和解决方案:

核心问题:线程不安全的文档修改

Bokeh Server的Document对象(也就是你代码里的doc)不是线程安全的,所有对文档内模型(比如添加图表、修改数据源)的操作都必须在Bokeh自身的事件循环线程中执行。而你继承multithreading.Thread后,直接在自定义子线程里执行plt_col.append(fig[fig_name])这类修改操作,会导致Python端的模型状态和前端JS端不同步——前端拿到的模型可能是不完整的,比如工具栏、图例的关联对象还没初始化,自然会抛出找不到draw_legend的错误。

解决方案:用Bokeh的回调机制修改文档

你需要把所有修改文档的代码包装到Bokeh提供的add_next_tick_callback方法中,确保操作在正确的线程上下文里执行。修改你的添加图表代码如下:

from bokeh.plotting import curdoc

def add_new_figure():
    if fig_name not in fig: 
        print(f'add fig {fig_name}')
        TOOLS="pan,wheel_zoom,box_zoom,reset,save,tap,hover"
        # 创建figure
        fig[fig_name] = figure(
            plot_width=900, 
            plot_height=280, 
            tools=TOOLS, 
            toolbar_location='right', 
            logo=None, 
            title=fig_name, 
            name=str(fig_name)
        )
        # 初始化数据源(建议同时初始化后续要用到的y字段,避免后续添加线条时出错)
        cds[fig_name] = ColumnDataSource(data=dict(x=np.array([]), y=np.array([])), name=f'{fig_name}_cds')
        # 获取UI容器并添加图表
        plt_col = curdoc().get_model_by_name('plt_ui_col').children
        plt_col.append(fig[fig_name])

# 不要在子线程直接修改文档,而是提交回调到Bokeh事件循环
curdoc().add_next_tick_callback(add_new_figure)

额外的排查点

  1. 确保figure有渲染器:如果你的figure创建后没有添加任何线条、散点等渲染器(比如fig[fig_name].line(...)),空图表可能会触发旧版本Bokeh的图例渲染bug。记得在添加图表后及时绑定数据源和渲染器。
  2. 考虑升级Bokeh版本:你用的0.12.16是2018年的旧版本,后续的1.x和2.x系列修复了大量多线程和渲染相关的问题。如果条件允许,升级到稳定版能避免很多这类奇怪的兼容性问题。

内容的提问来源于stack exchange,提问作者Andreas Gschossmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:53:46