简体   繁体   中英

Is there a way to use a MultiSelect in Bokeh to choose which channel of streaming data is plotted?

I'm putting together a bokeh server to collect multiple streams of data, and provide a live plot of whichever channel the user selects in a MultiSelect menu. I have the streaming bit working, but I'm not sure how to select which stream is displayed in the figure that I've added to the layout.

I've tried using curdoc().remove_root() to remove the current layout and then add a new one, but that just kills the app and the new layout doesn't show up. I've also tried to simply update the figure, but that also just kills the app.

from bokeh.layouts import column
from bokeh.plotting import figure,curdoc
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import MultiSelect

def change_plot(attr,old,new):
    global model,selector,p,source
    curdoc().remove_root(mode)
    p = figure()
    p.circle(x=new+'_x',y=new+'_y',source=source)
    model = column(selector,p)
    curdoc().add_root(model)

def update_plot():
    newdata = {}
    for i in range(10):
        # the following two lines would nominally provide real data
        newdata[str(i)+'_x'] = 1
        newdata[str(i)+'_y'] = 1
    source.stream(newdata,100)

selector = MultiSelect(title='Options',value=[str(i) for i in range(10)])
selector.on_change('value',change_plot)

data = {}
for i in range(10):
    data[str(i)+'_x'] = 0
    data[str(i)+'_y'] = 0
source = ColumnDataSource(data=data)

p = figure()
p.circle(x='0_x',y='0_y',source=source)
curdoc().add_root(model)
curdoc().add_periodic_callback(update_plot,100)

I run this code using bokeh serve --show app.py, and I would've expected it to create a new plot every time the MultiSelect is updated, but instead, it just crashes somewhere in the change_plot callback.

In this code selecting a line in MultiSelect adds a new line if it was not in the canvas and starts streaming or just toggles streaming if the line already was in the canvas. Code works for Bokeh v1.0.4. Run with bokeh serve --show app.py

from bokeh.models import ColumnDataSource, MultiSelect, Column
from bokeh.plotting import figure, curdoc
from datetime import datetime
from random import randint
from bokeh.palettes import Category10

lines = ['line_{}'.format(i) for i in range(10)]
data = [{'time':[], item:[]} for item in lines]
sources = [ColumnDataSource(item) for item in data]

plot = figure(plot_width = 1200, x_axis_type = 'datetime')

def add_line(attr, old, new):
    for line in new:
        if not plot.select_one({"name": line}):
            index = lines.index(line)
            plot.line(x = 'time', y = line, color = Category10[10][index], name = line, source = sources[index])

multiselect = MultiSelect(title = 'Options', options = [(i, i) for i in lines], value = [''])
multiselect.on_change('value', add_line)

def update():
    for line in lines:
        if line in multiselect.value:
            if plot.select({"name": line}):
                sources[lines.index(line)].stream(eval('dict(time = [datetime.now()], ' + line + ' = [randint(5, 10)])'))

curdoc().add_root(Column(plot, multiselect))
curdoc().add_periodic_callback(update, 1000)

Result:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM