2017-10-11 96 views
0

我使用的是散景0.12.9。我有一个表格和一个我在回调的全局布局中替换的图形。在构建新图形/表格之前,我通常会构建ColumnDataSource。现在我想尝试一下,看看我是否可以有一个全局的ColumnDataSource,这样我就可以通过CDSView调整数据(不需要替换表/数字)。使用全局ColumnDataSource替换布局中的图形和表格

不幸的是,即使保留单独的CDS并查看表格和绘图失败。当点击单选按钮几次我收到以下JavaScript错误: Uncaught TypeError: Cannot read property 'data' of undefined

from datetime import date 
from random import randint 

from bokeh.models import Line 
import numpy as np 
import pandas as pd 

from bokeh.plotting import figure, output_file, show 
from bokeh.models import ColumnDataSource 
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn 
import bokeh.layouts as layouts 
import bokeh.models.widgets as widgets 
from bokeh.io import curdoc 
from bokeh.models import CustomJS, Slider 
from bokeh import palettes 
from bokeh.layouts import layout 
from bokeh.models import ColumnDataSource, CDSView, IndexFilter 
from bokeh.models import widgets 


def gen_plot(source=None, view=None): 
    p = figure(title='test', 
       x_axis_type="datetime", 
       plot_width=600, plot_height=400) 
    colors = palettes.Category10[10] 
    cols = [str(col) for col in source.column_names] 
    for ix, col in enumerate(cols): 
     if col == 'index': 
      continue 
     r = p.line(x='index', y=col, source=source, view=view, 
        legend='_' + col, 
        color=colors[ix]) 
    p.legend.location = "bottom_left" 
    return p 


def gen_table(source=None, view=None): 
    columns = [TableColumn(field=ele, title=ele) for ele 
       in source.column_names] 
    tab = widgets.DataTable(source=source, view=view, columns=columns, 
          selectable=False, 
          reorderable=False, 
          width=600, height=400) 
    return tab 



def update(attr, old, new): 
    p = gen_plot(source=cdss[0], view=vs[0]) 
    t = gen_table(source=cdss[1], view=vs[1]) 

    print l.children 
    l.children[1] = p 
    l.children[2].children[0] = t 


# set up data 
cols = ['col1', 'col2', 'col3', 'col4'] 
df1 = pd.DataFrame(pd.util.testing.getTimeSeriesData()) 
df1.columns = cols 
df2 = pd.DataFrame(pd.util.testing.getTimeSeriesData()) 
df2.columns = cols 
dfs = [df1, df2] 
cds1 = ColumnDataSource(df1) 
cds2 = ColumnDataSource(df2) 
cdss = [cds1, cds2] 
filters = [IndexFilter([0, 1, 2, 4])] 
filters = [] 
v1 = CDSView(source=cds1, filters=filters) 
v2 = CDSView(source=cds2, filters=filters) 
vs = [v1, v2] 


# initialize items to replace 
p = gen_plot(source=cdss[0], view=vs[0]) 
t = gen_table(source=cdss[1], view=vs[1]) 

# initialize controls 
radio_wghting = widgets.RadioButtonGroup(labels=["Equal", "Exponential"], 
             active=0) 
radio_wghting.on_change('active', update) 

# set up layout 
sizing_mode = 'fixed' 
l = layout([radio_wghting, p, t], sizing_mode=sizing_mode) 

curdoc().add_root(l) 
curdoc().title = 'blub' 


# call callback initially 
update('value', 0, 0) 

任何提示都非常感谢!

回答

0

Now I wanted to try and see if I can have a global ColumnDataSource so that I can adjust the data via a CDSView (no need to replace table/figure then).

您显示的代码是您尝试替换图形和表格的代码。

以这种方式替换布局对象的子对象时,实际上并未从curdoc中删除以前的图形,而文档中的其他元素在其引用中仍旧具有旧的图形和表格。

您可以尝试类似的方式直接更新源代码。

for rend in p.renderers: 
    try: 
     rend.data_source 
    except AttributeError: 
     pass 
    else: 
     rend.data_source.data.update(new_data_dictionary) 

t.source.data.update(new_data_dictionary) 

编辑回答评论

from bokeh.io import curdoc 
from bokeh.plotting import figure 
from bokeh.models import ColumnDataSource, Button 
from bokeh.layouts import gridplot, widgetbox 

from random import random, choice 

import numpy as np 

my_data = {1:{'x':[],'y':[],'colo':[],'size':[]}} 

kelly_colors = [ '#F3C300','#875692', '#F38400', '#A1CAF1','#BE0032', '#C2B280', '#848482','#008856', '#E68FAC', '#0067A5', 
        '#F99379', '#604E97', '#F6A600','#B3446C', '#DCD300', '#882D17','#8DB600', '#654522', '#E25822','#2B3D26',  ] 

x = np.arange(0,50,0.1) 

def rand_dict(): 

    rand_x = [choice(x) for i in range(7)] 

    return {'x':rand_x,'y':np.array([random()*100 for i in rand_x]),'colo':np.array([choice(kelly_colors) for i in rand_x]),'size':np.array([(5+int(random()*50)) for i in rand_x])} 

def add_stuff(): 

    global my_data 

    my_data[max(my_data.keys())+1] = rand_dict() 

    make_doc() 

def change_stuff(): 

    global my_data 

    myfig = curdoc().select_one({"name":"myfig"}) 

    for i,rend in enumerate(myfig.renderers): 
     try: 
      rend.data_source 
     except AttributeError: 
      pass 
     else: 
      my_data[i+1] = rand_dict() 
      rend.data_source.data.update(my_data[i+1]) 

def clear_stuff(): 

    global my_data 

    my_data = {1:{'x':[],'y':[],'colo':[],'size':[]}} 

    make_doc() 

def make_doc(): 

    curdoc().clear() 

    myfig = figure(plot_width=1000,plot_height=800,outline_line_alpha=0,name='myfig') 
    myfig.x_range.start = -5 
    myfig.x_range.end = 55 
    myfig.y_range.start = -10 
    myfig.y_range.end = 110 

    myfig.renderers = [] 

    add_button = Button(label='add stuff',width=100) 
    change_button = Button(label='change stuff',width=100) 
    clear_button = Button(label='clear stuff',width=100) 

    add_button.on_click(add_stuff) 
    change_button.on_click(change_stuff) 
    clear_button.on_click(clear_stuff) 

    grid = gridplot([[myfig,widgetbox(add_button,change_button,clear_button)]],toolbar_location=None) 

    curdoc().add_root(grid) 

    update_doc() 

def update_doc(): 

    myfig = curdoc().select_one({"name":"myfig"}) 

    for key in my_data: 
     myfig.scatter(x='x',y='y',color='colo',size='size',source=ColumnDataSource(data=my_data[key])) 

curdoc().title = 'mytitle' 

make_doc() 

是我喜欢做的,这是,你可以只保存my_data字典,numpy的,后来加载并从那里继续改变你的情节。

def load_data(): 

    global my_data 

    my_data = np.load(path_to_saved_data).item() 

    make_doc() 

你可以使用熊猫数据框做类似的事情,我只是比较喜欢简单的字典。

+0

嘿seb。有没有干净的方式完全删除图形和表格?我试着更新数据。 – bjonen

+0

我还没有找到一种方法来干净地做到这一点。当我需要替换或添加实际模型时,我所做的工作就是编写我的应用程序,以便清除文档并在函数中重新创建文档,然后使用全局数据源填充所有图。 – Seb

+0

你介意给这个答案添加一些伪代码吗? – bjonen