在 Bokeh 中通过在不同图形上悬停来改变一组图形的颜色或显示描绘关系的线条

31 阅读2分钟

在 Bokeh 中,有一个图形包含两个数据源,分别对应于一组圆形和一组方形。现在,我想实现以下交互效果:

  • 当鼠标悬停在某个方形上时,改变该方形下方三个圆形的颜色。
  • 当鼠标悬停在另一个方形上时,改变该方形上方两个圆形的颜色。
  • 在方形和圆形之间显示线条,描绘它们之间的关系,仅在鼠标悬停在方形上时才显示这些线条。

2、解决方案

为了实现这些效果,我们需要使用 Bokeh 中的 HoverToolCDSView 工具。HoverTool 用于在图形上悬停时显示工具提示,而 CDSView 用于过滤数据源,以便仅显示与悬停的图形相关的数据。

首先,我们需要创建一个数据帧来标识方形和圆形之间的关系。这个数据帧应该有以下列:

  • square_id: 方形的唯一标识符。
  • circle_ids: 与该方形相关的一组圆形的唯一标识符。

接下来,我们需要创建一个 CDSView 对象,并使用 GroupFilter 属性来过滤数据源。GroupFilter 属性接受一个列名和一个组名,它将仅显示属于该组的数据。

view = CDSView(source=source1, filters=[GroupFilter(column_name="circle_ids", group="square_id")])

然后,我们需要创建一个 HoverTool 对象,并将 view 属性设置为我们刚刚创建的 CDSView 对象。这将确保当鼠标悬停在方形上时,只显示与该方形相关的数据。

hover_tool = HoverTool(renderers=[c, s], tooltips=[('x', '@x')])
hover_tool.view = view

最后,我们需要将 HoverTool 对象添加到图形中。

p.add_tools(hover_tool)

现在,当鼠标悬停在方形上时,该方形下方三个圆形的颜色将改变。当鼠标悬停在另一个方形上时,该方形上方两个圆形的颜色将改变。而且,方形和圆形之间将显示线条,描绘它们之间的关系,仅在鼠标悬停在方形上时才显示这些线条。

# 代码例子

from bokeh.layouts import gridplot
from bokeh.models import ColumnDataSource, CDSView, IndexFilter
from bokeh.plotting import figure, show
from bokeh.io import curdoc, output_notebook, output_file, export_png
from bokeh.models import (
  ColumnDataSource, Circle, Square, HoverTool,Grid, TapTool,PanTool, WheelZoomTool, BoxSelectTool,ZoomInTool, ZoomOutTool, CDSView, GroupFilter)

curdoc().clear()
output_notebook()

source1 = ColumnDataSource(data=dict(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5], group="square_id"))
source2 = ColumnDataSource(data=dict(x=[3, 4], y=[2, 3]))

p = figure(plot_height=300, plot_width=300, tools="pan,wheel_zoom,box_zoom,reset,zoom_in,zoom_out,save")
circle = Circle(x="x", y="y", size=10)

square = Square(x="x", y="y", size=10)
hover_square = Square(x="x", y="y", size=10, fill_color="red")

c = p.add_glyph(source1, circle)
s = p.add_glyph(source2, square, hover_glyph=hover_square)

view = CDSView(source=source1, filters=[GroupFilter(column_name="circle_ids", group="square_id")])

hover_tool = HoverTool(renderers=[c, s], tooltips=[('x', '@x')])
hover_tool.view = view

p.add_tools(hover_tool)

show(p)