2017-10-11 50 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