可点击的字形在散景上生成图

Clickable glyphs to generate plots on bokeh

使用散景,我想生成一个带有字形的图形,可以 selected 或 un-selected。给定字形的 selection 应该导致使用与该给定字形点关联的特定数据更新绘图。我希望能够同时单击和 select 多个字形,图表显示所有不同的数据。

下面的代码显示了我的位置

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

# Create data for clickable plot
x = [0, 1]
y = [0, 1]
table_index = [0, 1]

# Create the clickable plot
plot = figure(height=400, width=600,title='Select a point', tools='tap')
plot_source = ColumnDataSource(data=dict(x=x, y=y))
renderer = plot.circle('x', 'y', source=plot_source, size=30)

# Create two sets of data for the updatable plot
master_data = {}

master_data[0] = {'x_values': [1, 2, 3, 4, 5],'y_values': [6, 7, 2, 3, 6]}
master_data[1] = {'x_values': [1, 2, 3, 4, 5], 'y_values': [6, 5, 4, 3, 2]}

# Create updatable plot
data = master_data[0]
plot_source2 = ColumnDataSource(data=data)
c = figure(title="test", x_axis_label='numbers', y_axis_label='more numbers')
c.line(x='x_values', y='y_values', source=plot_source2, line_width=2)

# Here the reactions of the server are defined
def my_tap_handler(attr, old, new):
    index = new[0]
    c.line.source = ColumnDataSource(master_data[index])  #problematic line

plot_source.selected.on_change("indices", my_tap_handler)

# Collect it all together in the current doc
curdoc().add_root(column(plot, c))
curdoc().title = 'Select experiment'

这段代码 运行 生成了一个可点击的图表以及数据图表,但它有两个问题:首先,我不能 select 两者(或两者都不是!) “可点击图”上的字形,以便在“可更新图”中显示两个数据集(或 none!)。其次,上面有问题的行没有做它应该做的事情。

也许我不想使用 on_tap 处理程序,而是 on_click,但我不知道如何使用。另一方面,我很想 运行 直接在 jupyter notebook 上,但现在我被迫保存常规 python 代码“test.py”和 运行 它通过 bokeh serve --show test.py。有没有办法将这一切嵌入到 Jupyter 中?

有多种方法:

  • 切换到 multi_line 并更改其数据(如下所示)
  • 切换到 multi_line 并创建带有 index-based 过滤器的 ``CDSView`
  • 继续使用 line,但在开始时绘制所有这些,稍后只需更改它们的 visible 属性

它并没有真正在任何地方记录(至少,我找不到任何东西),但是通过点击选择字形也尊重 Shift 和 Ctrl 键,尽管它不是很直观。这是来自 Bokeh 的相关代码,应该是 self-explanatory.

  protected _select_mode(ev: UIEvent): SelectionMode {
    const {shiftKey, ctrlKey} = ev

    if (!shiftKey && !ctrlKey)
      return "replace"
    else if (shiftKey && !ctrlKey)
      return "append"
    else if (!shiftKey && ctrlKey)
      return "intersect"
    else if (shiftKey && ctrlKey)
      return "subtract"
    else
      unreachable()
  }

另请注意,没有选择和选择所有字形在视觉上没有区别,但回调将收到不同的值。

下面是您想要实现的示例实现。

from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure

plot = figure(height=400, width=600, title='Select a point', tools='tap')
plot_source = ColumnDataSource(data=dict(x=[0, 1], y=[0, 1]))
renderer = plot.circle('x', 'y', source=plot_source, size=30)

master_data = [{'x_values': [1, 2, 3, 4, 5], 'y_values': [6, 7, 2, 3, 6]},
               {'x_values': [1, 2, 3, 4, 5], 'y_values': [6, 5, 4, 3, 2]}]

plot_source2 = ColumnDataSource(data=dict(x_values_s=[], y_values_s=[]))
c = figure(title="test", x_axis_label='numbers', y_axis_label='more numbers')
c.multi_line(xs='x_values_s', ys='y_values_s', source=plot_source2, line_width=2)


def my_tap_handler(attr, old, new):
    print(new)
    plot_source2.data = dict(x_values_s=[master_data[i]['x_values'] for i in new],
                             y_values_s=[master_data[i]['y_values'] for i in new])


plot_source.selected.on_change("indices", my_tap_handler)

curdoc().add_root(column(plot, c))
curdoc().title = 'Select experiment'