2016-07-24 8 views
9

का उपयोग करके प्लॉट को गतिशील रूप से जोड़ें/हटाएं मेरा प्रश्न another thread को बोके 0.7.1 का उपयोग करके काफी समान है, लेकिन बोके सर्वर के लिए एपीआई 0.12.0 में पर्याप्त बदल गया है, कि मैं संघर्ष कर रहा हूं नए संस्करण के जवाब को अनुकूलित करने के लिए।गतिशील रूप से 'बोके सेवा' (बोकेह 0.12.0)

संक्षेप में, मेरे पास एक पृष्ठ है जो टाइमस्ट्रीम प्लॉट्स के ग्रिड के साथ एक फ़ाइल है जो लगातार अद्यतन होने वाली फ़ाइल से डेटा खींचती है। पृष्ठ में एक मल्टी सिलेक्ट मेनू है जो मेरी फ़ाइल में सभी चर सूचीबद्ध करता है। मैं मेनू में विभिन्न चर का चयन करने में सक्षम होना चाहता हूं, एक बटन दबाएं, और फिर मौजूदा चर के भूखंड गायब हो जाएं और नए टाइमस्ट्रीम द्वारा प्रतिस्थापित किया जाए, जहां भूखंडों की संख्या अलग हो सकती है। मैं अपनी स्क्रिप्ट bokeh serve --show script.py रैपर के साथ चला रहा हूं।

इस पर मेरे शुरुआती प्रयास में, मैंने एक ईवेंट हैंडलर को एक बटन पर असाइन किया, जो 'curdoc' को साफ़ करता है और फिर मल्टीसेलेक्ट से नए चुने गए चर के लिए प्लॉट जोड़ता है। यह चलता है, लेकिन भूखंडों की संख्या अद्यतन नहीं होती है। जाहिर है, मैं उस कॉल को याद कर रहा हूं जो किसी भी तरह से पेज लेआउट रीफ्रेश करने के लिए सर्वर को बताता है।

import numpy as np 

from bokeh.driving import count 
from bokeh.plotting import figure, curdoc 
from bokeh.layouts import gridplot 
from bokeh.models import Slider, Column, Row, ColumnDataSource, MultiSelect, Button 
from netCDF4 import Dataset 
import datetime 

# data 
#data = Dataset('/daq/spt3g_software/dfmux/bin/output.nc', 'r', format='NETCDF4') 
data = Dataset('20160714_warm_overbiased_noise.nc', 'r', format='NETCDF4') 
vars = data.variables.keys()[1:11] 

# plots 
d = {('y_%s'%name):[] for name in vars} 
d['t'] = [] 
source = ColumnDataSource(data=d) 

figs = [figure(x_axis_type="datetime", title=name) for name in vars] 
plots = [f.line(x='t', y=('y_%s'%f.title.text), source=source, color="navy", line_width=1) for f in figs] 
grid = gridplot(figs, ncols=3, plot_width=500, plot_height=250) 

# UI definition 
npoints = 2000 
slider_npoints = Slider(title="# of points", value=npoints, start=1000, end=10000, step=1000.) 
detector_select = MultiSelect(title="Timestreams:", value=[], options=vars) 
update_detector_button = Button(label="update detectors", button_type="success") 

# UI event handlers 
def update_detector_handler(): 
    global figs, plots, grid, source 
    d = {('y_%s'%name):[] for name in detector_select.value} 
    d['t'] = [] 
    source = ColumnDataSource(data=d) 

    figs = [figure(x_axis_type="datetime", title=name) for name in detector_select.value] 
    plots = [f.line(x='t', y=('y_%s'%f.title.text), source=source, color="navy", line_width=1) for f in figs] 
    grid = gridplot(figs, ncols=3, plot_width=500, plot_height=250) 
    curdoc().clear() 
    curdoc().add_root(Column(Row(slider_npoints, Column(detector_select, update_detector_button)), grid)) 

update_detector_button.on_click(update_detector_handler) 

# callback updater 
@count() 
def update(t): 
    data = Dataset('20160714_warm_overbiased_noise.nc', 'r', format='NETCDF4') 
    #data = Dataset('/daq/spt3g_software/dfmux/bin/output.nc', 'r', format='NETCDF4') 

    npoints = int(slider_npoints.value) 
    new_data = {('y_%s'%f.title.text):data[f.title.text][-npoints:] for f in figs} 
    new_data['t'] = data['Time'][-npoints:]*1e3 

    source.stream(new_data, npoints) 

# define HTML layout and behavior 
curdoc().add_root(Column(Row(slider_npoints, Column(detector_select, update_detector_button)), grid)) 
curdoc().add_periodic_callback(update, 500) 

उत्तर

6

ऐसा ही एक समस्या Bokeh Github पेज here पर जवाब दिया गया था।

अनिवार्य रूप से, curdoc() के साथ गड़बड़ करने की बजाय आप लेआउट ऑब्जेक्ट के बच्चों को संशोधित करते हैं उदा। someLayoutHandle.children

एक साधारण उदाहरण जोड़ सकते हैं और एक ग्राफ दूर करने के लिए एक टॉगल बटन उपयोग कर रहा है:

from bokeh.client import push_session 
from bokeh.layouts import column, row 
from bokeh.models import Toggle 
from bokeh.plotting import figure, curdoc 
import numpy as np 
# Create an arbitrary figure 
p1 = figure(name = 'plot1') 

# Create sin and cos data 
x = np.linspace(0, 4*np.pi, 100) 
y1 = np.sin(x) 
y2 = np.cos(x) 

# Create two plots 
r1 = p1.circle(x,y1) 

# Create the toggle button 
toggle = Toggle(label = 'Add Graph',active=False) 

mainLayout = column(row(toggle,name='Widgets'),p1,name='mainLayout') 
curdoc().add_root(mainLayout) 
session = push_session(curdoc()) 
# Callback which either adds or removes a plot depending on whether the toggle is active 
def toggleCallback(attr): 
    # Get the layout object added to the documents root 
    rootLayout = curdoc().get_model_by_name('mainLayout') 
    listOfSubLayouts = rootLayout.children 

    # Either add or remove the second graph 
    if toggle.active == False: 
     plotToRemove = curdoc().get_model_by_name('plot2') 
     listOfSubLayouts.remove(plotToRemove) 

    if toggle.active == True: 
     if not curdoc().get_model_by_name('plot2'): 
      p2 = figure(name='plot2') 
      plotToAdd = p2 
      p2.line(x,y2) 
      # print('Remade plot 2') 
     else: 
      plotToAdd = curdoc().get_model_by_name('plot2') 
     listOfSubLayouts.append(plotToAdd) 

# Set the callback for the toggle button 
toggle.on_click(toggleCallback) 

session.show() 
session.loop_until_closed() 

हिस्सा जो मुझे दिया सबसे मुसीबत यह सुनिश्चित करें कि साजिश मैं जोड़ना चाहते थे curdoc() का हिस्सा था, बना रहा था जो यही कारण है कि कॉलबैक फ़ंक्शन में परिभाषा है। यदि यह कॉलबैक के भीतर नहीं है, तो प्रत्येक बार प्लॉट 2 हटा दिया जाता है, यह बोके बैकएंड द्वारा नहीं पाया जा सकता है। यह जांचने के लिए, कॉलबैक फ़ंक्शन में प्रिंट स्टेटमेंट को असम्बद्ध करें।

मुझे आशा है कि इससे मदद मिलती है!

+1

कोई भी विचार सर्वर एप्लिकेशन के लिए ऐसा कैसे करना है? सबकुछ स्पष्ट है, लेकिन session.loop_until_closed() बोके सेवा के लिए काम नहीं कर रहा है। –

+0

ऐसा लगता है कि 'loop_until_closed()' उपयोग अब निराश है: https://github.com/bokeh/bokeh/pull/7339 –

संबंधित मुद्दे