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
相关产品推荐
相关产品推荐

