Bokeh Callback 是否更新了列表而不是 ColumnDataSource?

Have Bokeh Callback update a list instead of a ColumnDataSource?

我的问题与修改 Bokeh Gallery 中的 this 示例有关。

我有一个矩阵 m 或原始数据,其中每一行对应于转换后的一对 x,y 坐标 space(请参阅代码的#MockData 部分)。

x,y 坐标绘制在左图上。我正在尝试更改示例,以便当我 select 左图中的某些点时,右图将显示相应行的线图。

我已将问题缩小到右图将显示 "indices" 列表指定的所需数据的程度。但是,我无法弄清楚如何 link 索引列表的回调函数。 (目前,回调无​​用地使用索引更新源 s2。)

代码在复制时应该有效:

from bokeh.plotting import figure, output_file, show, ColumnDataSource, hplot
from bokeh.models import HoverTool, Callback, ColumnDataSource
import pandas as pd
output_file("Map.html")

# Mock data
m = np.zeros((6,11))
for i in range(6):
    for j in range(11):
        m[i,j] = i+j
x = [0,1,2,3,4,5]; y = [0,2,4,6,8,10]
m0 = m.transpose()
m1 = pd.DataFrame(m0, index=['0','1','2','3','4','5','6','7','8','9','10'], columns=[np.arange(0,len(m),1).astype(str)])

#First plot
s1 = ColumnDataSource(data=dict(x=x,y=y))
p1 = figure(tools=["lasso_select"], plot_width=600, plot_height=400)
p1.scatter('x', 'y', fill_color='black', line_color=None, size=10, source=s1)

#Second plot
s2 = ColumnDataSource(data=dict(z=[]))
p2 = figure(plot_width=400, plot_height=400)    
m1 = ColumnDataSource(m1)
indices = [1,3,4]
for i in indices:
    p2.line(np.arange(0,11,1), '%s'%i ,  source=m1)

s1.callback = Callback(args=dict(s2=s2), code="""
  var inds = cb_obj.get('selected')['1d'].indices;
  var d2 = s2.get('data');
  d2['z'] = []
  for (i = 0; i < inds.length; i++) {
      d2['z'].push(inds[i])}
  s2.trigger('change'); 
""")

layout = hplot(p1, p2)
show(layout)

原问题:

使用 Bokeh 文档中的示例。我正在尝试从左侧 window 的 selection 获取索引,并使用它们从具有原始数据的矩阵中获取适当的行并绘制该行。 详细:

我从一个值矩阵开始,其中每一列是一年,每一行是一个位置。我 运行 在矩阵上使用 sklearn Spectral Embedding 来表征数据并得到一个矩阵,其中每一列都以某种方式描述数据。我将前 3 列绘制为 x、y 坐标和一种颜色。 接下来,我尝试修改示例,以便当我 select 一些点时,第二个图表将它们的原始数据(行)显示为单独的线。主要取自示例的相关代码如下。

如果我误解了你的问题请告诉我,但听起来你有一个矩阵(我们称它为 m1),你是 运行 对 s1 中的数据进行转换并产生数据在 p1 中绘制。您希望能够 select p1 中的一些数据并将 m1 中的相应数据绘制在 p2 中。

如果没错,您将需要三个 ColumnDataSource 对象。您将必须为 m1 创建一个 ColumnDataSource 并使用您已有的 s1 和 s2。回调需要类似于:

s1.callback = Callback(args=dict(m1=m1, s2=s2), code="""
  var inds = cb_obj.get('selected')['1d'].indices;
  var d1 = m1.get('data');
  var d2 = s2.get('data');
  d2['x'] = []
  d2['y'] = []
  for (i = 0; i < inds.length; i++) {
    d2['x'].push(d1['x'][inds[i]])
    d2['y'].push([inds[i]])
  }
  s2.trigger('change'); 
""")

这将采用 selected 数据的索引并找到具有相同索引 m1(原始数据)的 x 和 y,并将其添加到 s2。然后 s2.trigger('change') 调用将更新 p2.

中的数据点

如果我误解了你的问题,请告诉我。

在这里和 Bokeh 邮件列表中都没有任何回复,这让我相信不可能以这种方式使用回调,所以我不得不解决它并接受当前的限制,即无法使回调 "size" 动态。

出于数据探索的目的,无论如何都可以。

from bokeh.plotting import figure, output_file, show, ColumnDataSource, hplot
from bokeh.models import HoverTool, Callback, ColumnDataSource
import pandas as pd
output_file("bla.html")

# Mock data
m = np.ones((6,11))
for i in range(2,6):
    for j in range(11):
        m[i,j] = i+j
x = [0,1,2,3,4,5]; y = [0,2,4,6,8,10]
m0 = m.transpose()
m1 = pd.DataFrame(m0, index=['0','1','2','3','4','5','6','7','8','9','10'], columns=[np.arange(0,len(m),1).astype(str)])

#First plot
s1 = ColumnDataSource(data=dict(x=x,y=y))
p1 = figure(tools=["lasso_select"], plot_width=600, plot_height=400)
p1.scatter('x', 'y', fill_color='black', line_color=None, size=10, source=s1)

#Second plot
s2 = ColumnDataSource(data=dict(x=[],y=[],y2=[]))
p2 = figure(plot_width=400, plot_height=400, tools =[])

m1 = ColumnDataSource(m1) #Actual Datasource for the second plot
p2.line(np.arange(0,100,1), 'y' , source=s2) # From original data - series 1
p2.line(np.arange(0,100,1), 'y2' , source=s2) # From original data - series 2

s1.callback = Callback(args=dict(s2=s2, m1=m1), code="""
  var inds = cb_obj.get('selected')['1d'].indices;
  var d1 = m1.get('data'); 
  var d2 = s2.get('data');
  d2['y'] = []
  d2['y2'] = []
  for (i = 0; i < 11; i++) {
    d2['y'].push(d1[inds['0']][i]),
    d2['y2'].push(d1[inds['1']][i])
  }
  s2.trigger('change'); 
""")

layout = hplot(p1, p2)
show(layout)

代码现在绘制 selected 数据中前两个索引的原始数据。限制是原始数据系列的数量必须预先定义,因此代码只会绘制两条线。此外,它还需要至少两行来执行。它不会只对一分 selected 有效。因此,如果我预定义要绘制的更多线条,我将始终需要 select 那个点数。