2016-07-24 11 views
9

Câu hỏi của tôi khá giống với another thread sử dụng bokeh 0.7.1, nhưng API cho máy chủ bokeh đã thay đổi đủ trong 0.12.0. để điều chỉnh câu trả lời đó cho phiên bản mới.Tự động thêm/xóa cốt truyện bằng cách sử dụng 'bokeh phân phối' (bokeh 0.12.0)

Để tóm tắt, tôi có một trang có lưới ô nhịp thời gian kéo dữ liệu từ tệp được cập nhật liên tục. Trang này có menu MultiSelect liệt kê tất cả các biến trong tệp của tôi. Tôi muốn có thể chọn các biến khác nhau trong menu, nhấn một nút và sau đó có các ô của biến hiện tại biến mất và được thay thế bằng dòng thời gian mới, nơi số lượng ô có thể khác nhau. Tôi đang chạy tập lệnh của mình với trình bao bọc bokeh serve --show script.py.

Trong lần thử đầu tiên, tôi đã gán một trình xử lý sự kiện cho một nút, trong đó xóa 'curdoc' và sau đó thêm ô cho các biến mới được chọn từ MultiSelect. Điều này chạy, nhưng số lượng ô không cập nhật. Rõ ràng tôi đang thiếu cuộc gọi nói với máy chủ bằng cách nào đó làm mới bố cục trang.

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) 

Trả lời

6

Một vấn đề tương tự đã được trả lời trên trang Bokeh Github here.

Về cơ bản, thay vì gây rối với curdoc() bạn thay vì sửa đổi con của đối tượng bố cục, ví dụ: someLayoutHandle.children.

Một ví dụ đơn giản là sử dụng một nút bật tắt để thêm và loại bỏ một đồ thị:

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() 

Phần đó đã cho tôi những rắc rối nhất là đảm bảo rằng các âm mưu tôi muốn thêm là một phần của curdoc(), mà là lý do tại sao định nghĩa nằm trong hàm gọi lại. Nếu nó không nằm trong hàm gọi lại, mỗi lần lô2 bị loại bỏ thì không thể tìm thấy nó bởi phần phụ trợ bokeh. Để kiểm tra xem đây có phải là trường hợp không, hãy bỏ ghi chú in trong chức năng gọi lại.

Tôi hy vọng điều này sẽ hữu ích!

+1

Bất kỳ ý tưởng nào làm cho điều này xảy ra cho ứng dụng máy chủ? Mọi thứ đều rõ ràng, nhưng session.loop_until_closed() dường như không hoạt động để phục vụ bokeh. –

+0

Có vẻ như việc sử dụng 'loop_until_closed()' hiện không được khuyến khích: https://github.com/bokeh/bokeh/pull/7339 –

Các vấn đề liên quan