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

Python Bokeh双交互式联动图表开发:点击图表1联动展示图表2数据

实现Bokeh交互式条形图点击展示对应原始数据

嘿,我明白你想要的效果了——点击均值条形图(plot1)里的任意条形,就能在第二个图(plot2)中展示对应原始数据列的内容对吧?下面我给你两种靠谱的实现方案,分别适配静态HTML导出和后端交互的场景,代码都是可直接运行的哦~

先搭好示例数据

咱先构造两个关联的DataFrame,模拟你的场景:

import pandas as pd
import numpy as np

# 生成原始数据df2
np.random.seed(42)
df2 = pd.DataFrame({
    "A": np.random.randn(50),
    "B": np.random.randn(50) + 1,
    "C": np.random.randn(50) - 1
})

# 生成均值数据df1,列名和df2完全对应
df1 = pd.DataFrame({
    "column": df2.columns,
    "mean": df2.mean()
})

方案1:纯前端CustomJS回调(无需Bokeh服务器)

这种方案适合生成静态HTML文件,所有交互在浏览器端完成,不需要后端服务。核心是把df2的原始数据提前转为JSON格式,通过CustomJS监听条形图的点击事件,实时更新plot2的数据源。

完整代码:

from bokeh.plotting import figure, show, output_file
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.layouts import row

# 准备数据源
source1 = ColumnDataSource(df1)
# 将df2转换为字典,键是列名,值是对应的数据列表
raw_data = {col: df2[col].tolist() for col in df2.columns}
# 初始默认展示第一列的数据
source2 = ColumnDataSource(data={"x": range(len(df2)), "y": raw_data[df2.columns[0]]})

# 创建plot1:均值条形图
plot1 = figure(x_range=df1["column"], title="各列均值", width=400, height=300)
bars = plot1.vbar(x="column", top="mean", width=0.7, source=source1, color="skyblue")

# 创建plot2:原始数据展示图(这里用折线图,你也可以换成散点图/直方图)
plot2 = figure(title="原始数据", width=600, height=300)
plot2.line(x="x", y="y", source=source2, line_width=2)

# 编写CustomJS回调逻辑
callback = CustomJS(args=dict(source2=source2, raw_data=raw_data), code="""
    // 获取点击的条形对应的列名
    const selected_col = cb_obj.data['column'][cb_obj.selected.indices[0]];
    // 更新plot2的数据源
    source2.data = {
        x: Array.from({length: raw_data[selected_col].length}, (_, i) => i),
        y: raw_data[selected_col]
    };
    // 通知Bokeh更新视图
    source2.change.emit();
""")

# 给条形图绑定点击事件回调
bars.data_source.selected.js_on_change('indices', callback)

# 布局并导出静态HTML
layout = row(plot1, plot2)
output_file("bokeh_interactive_plot.html")
show(layout)

关键说明:

  • 我们把df2的所有原始数据提前转为JSON格式的字典raw_data,传递给前端的CustomJS使用。
  • 监听条形图数据源的selected.indices变化,当用户点击条形时,自动获取对应的列名,然后更新plot2的数据源。
  • 如果想给plot2加动态标题,只需要在CustomJS里加一句plot2.title.text = "原始数据 - " + selected_col;(记得把plot2也加入args参数)。

方案2:Bokeh服务器Python回调(适合复杂后端逻辑)

如果你的场景需要后端处理数据(比如从数据库动态加载、做复杂计算),可以用Bokeh服务器的Python回调。这种方案需要运行Bokeh服务器,而非导出静态HTML。

完整代码(保存为app.py):

from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource
from bokeh.layouts import row
import pandas as pd
import numpy as np

# 准备数据(和方案1一致)
np.random.seed(42)
df2 = pd.DataFrame({
    "A": np.random.randn(50),
    "B": np.random.randn(50) + 1,
    "C": np.random.randn(50) - 1
})
df1 = pd.DataFrame({
    "column": df2.columns,
    "mean": df2.mean()
})

# 数据源
source1 = ColumnDataSource(df1)
source2 = ColumnDataSource(data={"x": range(len(df2)), "y": df2["A"].tolist()})

# 创建绘图
plot1 = figure(x_range=df1["column"], title="各列均值", width=400, height=300)
bars = plot1.vbar(x="column", top="mean", width=0.7, source=source1, color="skyblue")

plot2 = figure(title="原始数据", width=600, height=300)
plot2.line(x="x", y="y", source=source2, line_width=2)

# Python回调函数
def update_plot(attr, old, new):
    if new:
        # 获取选中的列名
        selected_col = source1.data["column"][new[0]]
        # 更新plot2的数据,还可以在这里加后端逻辑(比如查库、计算)
        source2.data = {
            "x": range(len(df2)),
            "y": df2[selected_col].tolist()
        }
        # 给plot2更新动态标题
        plot2.title.text = f"原始数据 - {selected_col}"

# 绑定回调到选中事件
source1.selected.on_change("indices", update_plot)

# 添加到Bokeh文档
curdoc().add_root(row(plot1, plot2))
curdoc().title = "Bokeh Interactive Demo"

运行方式:

在终端执行以下命令,浏览器会自动打开交互页面:

bokeh serve --show app.py

关键说明:

  • 用source1.selected.on_change("indices", update_plot)把Python函数绑定到条形图的选中事件上。
  • 回调函数里可以直接操作DataFrame,甚至加入数据库查询、复杂计算等后端逻辑,灵活性更高。

额外小技巧

  • 如果plot2想展示原始数据的直方图,只需要把plot2.line换成plot2.quad(直方图的API),并调整数据源的结构即可。
  • 可以给条形图加选中高亮效果,只需要给vbar添加selection_color="orange"参数,点击后的条形会变成橙色,用户体验更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:03:10