让Bokeh Callback更新列表而不是ColumnDataSource吗?

时间:2015-07-07 01:05:03

标签: javascript python plot callback bokeh

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

我有一个矩阵m或原始数据,其中每一行对应一个变换空间中的一对x,y坐标(参见#MockData部分代码)。

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

我已经将问题缩小到了这一点,正确的数字将显示"指数"所指定的所需数据。名单。但是,我无法弄清楚如何将回调函数链接到索引列表。 (目前Callback无用地使用索引更新源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文档中的示例。我试图从左侧窗口中的选择中获取索引并使用它们从具有原始数据的矩阵中获取适当的行并绘制该行。 详细说明:

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

2 个答案:

答案 0 :(得分:1)

让我知道如果我误解了你的问题,但听起来你有一个矩阵(让我们称之为m1),你正在运行转换并产生数据s1并在p1中绘图。您希望能够选择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'); 
""")

这将获取所选数据的索引,并找到具有相同索引m1(原始数据)的x和y,并将其添加到s2。然后s2.trigger(&#39;更改&#39;)调用将更新p2中的数据点。

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

答案 1 :(得分:1)

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

出于数据探索的目的,无论如何都会这样做。

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)

现在,代码绘制了所选数据中前两个索引的原始数据。限制是必须预定义原始数据系列的数量,因此代码将只绘制两行。此外,它还需要至少两行才能执行。它不会只选择一个点工作。因此,如果我预先定义了更多要绘制的线条,我将始终选择该点数。