链接行为#

将绘图链接起来以在绘图之间添加连接的交互性通常很有用。本节展示了一种使用 bokeh.plotting 接口轻松实现此目的的方法。

链接平移#

通常希望在多个绘图之间链接平移或缩放操作。要启用此功能,只需在 figure() 调用之间共享范围对象即可。

from bokeh.layouts import gridplot
from bokeh.plotting import figure, show

x = list(range(21))
y0 = x
y1 = [20-xx for xx in x]
y2 = [abs(xx-10) for xx in x]

# create a new plot
s1 = figure(width=250, height=250, title=None)
s1.scatter(x, y0, size=10, color="navy", alpha=0.5)

# create a new plot and share both ranges
s2 = figure(width=250, height=250, x_range=s1.x_range, y_range=s1.y_range, title=None)
s2.scatter(x, y1, size=10, marker="triangle", color="firebrick", alpha=0.5)

# create a new plot and share only one range
s3 = figure(width=250, height=250, x_range=s1.x_range, title=None)
s3.scatter(x, y2, size=10, marker="square", color="olive", alpha=0.5)

p = gridplot([[s1, s2, s3]], toolbar_location=None)

show(p)

现在您已经了解了如何使用 bokeh.plotting 接口在多个绘图之间链接平移。

SPLOM 部分中可以找到链接散点图矩阵的更复杂的示例 统计图 章节。

链接刷选#

Bokeh 中的链接刷选通过在图元渲染器之间共享数据源来表达。这是 Bokeh 需要理解的全部内容,即对一个图元执行的选择必须传递到共享相同源的所有其他图元。要查看链接选择如何扩展到仅绘制数据源中数据子集的图元渲染器,请参阅 使用过滤数据进行链接选择.

以下代码展示了在两个不同的 figure() 调用中对圆形图元进行链接刷选的示例

from bokeh.layouts import gridplot
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure, show
from bokeh.sampledata.penguins import data
from bokeh.transform import factor_cmap

SPECIES = sorted(data.species.unique())

TOOLS = "box_select,lasso_select,help"

source = ColumnDataSource(data)

left = figure(width=300, height=400, title=None, tools=TOOLS,
              background_fill_color="#fafafa")
left.scatter("bill_length_mm", "body_mass_g", source=source,
             color=factor_cmap('species', 'Category10_3', SPECIES))

right = figure(width=300, height=400, title=None, tools=TOOLS,
               background_fill_color="#fafafa", y_axis_location="right")
right.scatter("bill_depth_mm", "body_mass_g", source=source,
              color=factor_cmap('species', 'Category10_3', SPECIES))

show(gridplot([[left, right]]))

以下更复杂的示例演示了在 DataTable 小部件和散点图之间的链接选择

from bokeh.layouts import column
from bokeh.models import (ColumnDataSource, DataTable, HoverTool, IntEditor,
                          NumberEditor, NumberFormatter, SelectEditor,
                          StringEditor, StringFormatter, TableColumn)
from bokeh.plotting import figure, show
from bokeh.sampledata.autompg2 import autompg2 as mpg

source = ColumnDataSource(mpg)

manufacturers = sorted(mpg["manufacturer"].unique())
models = sorted(mpg["model"].unique())
transmissions = sorted(mpg["trans"].unique())
drives = sorted(mpg["drv"].unique())
classes = sorted(mpg["class"].unique())

columns = [
    TableColumn(field="manufacturer", title="Manufacturer",
                editor=SelectEditor(options=manufacturers),
                formatter=StringFormatter(font_style="bold")),
    TableColumn(field="model", title="Model",
                editor=StringEditor(completions=models)),
    TableColumn(field="displ", title="Displacement",
                editor=NumberEditor(step=0.1), formatter=NumberFormatter(format="0.0")),
    TableColumn(field="year", title="Year", editor=IntEditor()),
    TableColumn(field="cyl", title="Cylinders", editor=IntEditor()),
    TableColumn(field="trans", title="Transmission",
                editor=SelectEditor(options=transmissions)),
    TableColumn(field="drv", title="Drive", editor=SelectEditor(options=drives)),
    TableColumn(field="class", title="Class", editor=SelectEditor(options=classes)),
    TableColumn(field="cty", title="City MPG", editor=IntEditor()),
    TableColumn(field="hwy", title="Highway MPG", editor=IntEditor()),
]
data_table = DataTable(source=source, columns=columns, editable=True, width=800,
                       index_position=-1, index_header="row index", index_width=60)

p = figure(width=800, height=300, tools="pan,wheel_zoom,xbox_select,reset", active_drag="xbox_select")

cty = p.scatter(x="index", y="cty", fill_color="#396285", size=8, alpha=0.5, source=source)
hwy = p.scatter(x="index", y="hwy", fill_color="#CE603D", size=8, alpha=0.5, source=source)

tooltips = [
    ("Manufacturer", "@manufacturer"),
    ("Model", "@model"),
    ("Displacement", "@displ"),
    ("Year", "@year"),
    ("Cylinders", "@cyl"),
    ("Transmission", "@trans"),
    ("Drive", "@drv"),
    ("Class", "@class"),
]
cty_hover_tool = HoverTool(renderers=[cty], tooltips=[*tooltips, ("City MPG", "@cty")])
hwy_hover_tool = HoverTool(renderers=[hwy], tooltips=[*tooltips, ("Highway MPG", "@hwy")])

p.add_tools(cty_hover_tool, hwy_hover_tool)

show(column(p, data_table))

链接十字线#

在绘图之间链接十字线工具是另一种可以帮助更轻松地跨不同绘图进行比较的技术。在 Bokeh 中,十字线工具可以使用共享的 Span 实例为其叠加层进行配置,这将导致这些十字线彼此链接。这在下面演示

from random import random

from bokeh.layouts import row
from bokeh.models import CrosshairTool, Span
from bokeh.plotting import figure, show

x = [random() * 10 for _ in range(200)]
y = [random() * 10 for _ in range(200)]

width = Span(dimension="width", line_dash="dashed", line_width=2)
height = Span(dimension="height", line_dash="dotted", line_width=2)

p1 = figure(height=400, width=400, x_range=(0, 10), y_range=(0, 10),
            tools="hover", toolbar_location=None)
p1.add_tools(CrosshairTool(overlay=[width, height]))
p1.circle(x, y, radius=0.2, alpha=0.3, hover_alpha=1.0)

p2 = figure(height=400, width=250, x_range=(0, 10), y_range=(0, 10),
            tools="hover", toolbar_location=None)
p2.add_tools(CrosshairTool(overlay=[width, height]))
p2.circle(x, y, radius=0.2, alpha=0.3, hover_alpha=1.0)

show(row(p1, p2))

链接属性#

还可以使用 js_link() 方法将 Bokeh 模型属性的值链接在一起,以便它们保持同步。以下示例将圆形图元半径链接到滑块小部件的值

from bokeh.layouts import column
from bokeh.models import Slider
from bokeh.plotting import figure, show

plot = figure(width=400, height=400)
r = plot.circle([1,2,3,4,5], [3,2,5,6,4], radius=0.2, alpha=0.5)

slider = Slider(start=0.1, end=2, step=0.01, value=0.2)
slider.js_link('value', r.glyph, 'radius')

show(column(plot, slider))

链接在 JavaScript 中完成,因此此方法适用于独立 Bokeh 文档或 Bokeh 服务器应用程序。

小部件和 DOM 元素 有关不同小部件的更多信息,以及 JavaScript 回调 有关创建任意 JavaScript 回调的更多信息。