在用户输入的散景中隐藏情节 - 自定义 JS?

Hide plot in bokeh on user input - custom JS?

我有一个 python/bokeh 应用程序,我在其中显示许多人的时间序列数据,每个人都有单独的图。这些地块被布置在一列中。

假设我有每个人的体温信息,分辨率为 1 年的每个小时(只是一个虚构的例子)。我在 y 轴上绘制了它们每个的温度与 x 轴上的时间。我将所有这些图存储在字典中。所以我有一个字典 ind 这样 ind 中的键是个人名称,对应的值是 bokeh.plotting 图形对象。然后,我使用 column() 来渲染数字。

我有很多人在看,比如说 26。所以当我启动应用程序时,我有一列 26 个地块,一次可以比较很多。 (请理解,这是一个虚构的例子,只是为了交流。我的项目要求我不要在同一张图中叠加所有个人的数据。我知道bokeh允许我们在'mute'和'hide'层如果我要将它们绘制在同一个图中但我不能那样做,那就是传说中的情节。)

因此,我提供了一个包含所有个人姓名的 CheckboxGroup,这样用户就可以 select 他们现在想看到哪些人。我的用户可能想同时检查任意数量的人。它可能是 3 或 4 或 10。因此,我无法确定要在一列中排列的图的数量。

在 CheckboxGroup 小部件中的用户 selection 上,我需要以交互方式隐藏或显示绘图。我认为应该有一些 CustomJS 的方式来做,但我不知道如何做。我知道我们可以使用 Javascript 更改对象的可见性,如下所述:Show/hide 'div' using JavaScript

如有任何帮助,我们将不胜感激。此外,如果您可以展示如何根据用户输入(可以是下面示例中的 TextInput)对图重新排序,那将非常有帮助。

这是一个最小的工作示例:

import string
import random
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox, column
from bokeh.models.widgets import CheckboxGroup, TextInput
from bokeh.models import Range1d
from bokeh.io import curdoc, show

data= dict(zip(list(string.ascii_lowercase), [{"x": [i for i in range(8760)], "y": [random.uniform(35, 40) for x in range(8760)]} for i in range(26)]))

checkbox = CheckboxGroup(labels=list(string.ascii_lowercase), active=[0, 1, 4, 7, 10])
order = TextInput(title="Arrange plots in order as in this string")
ind = {}
for f in list(string.ascii_lowercase):
    ind[f] = figure(plot_width= 800, plot_height= 100, tools ='save, reset, resize')
    ind[f].vbar(x= "x", source= data[f], width= 0.5, bottom= 0, top= "y")
    ind[f].y_range= Range1d(start= 32, end= 43)
    ind[f].title.text = f

p = column(*ind.values())

inputs = widgetbox(*[order, checkbox], sizing_mode='fixed')

l = layout([
            [inputs, p],
            ], sizing_mode='fixed')

show(p)

curdoc().add_root(l)
curdoc().title = "test"

注意:Python 3 和最新版本的散景。

更新:御好烧下面的回答可以完成上述工作,但在稍微复杂的情况下,它是不够的。我认为对 Okonomiyaki 的回答做一些补充就可以了。基本上,我对每个人都有两个不同的观察结果,另一个是,比方说,体重。用户可以从下拉菜单中 select 他们想要研究的观察结果。绘制的数据反应性地绑定到 Select 小部件。在默认加载后使用复选框一段时间后,如果我将 selection 更改为权重,某些人的 x 轴不会更新。这是一个更新的最小工作示例(包括 Okonomiyaki 的回答):

import string
import random
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox, column
from bokeh.models.widgets import CheckboxGroup, TextInput, Select
from bokeh.models import Range1d, ColumnDataSource
from bokeh.io import curdoc, show

data1= dict(zip(list(string.ascii_lowercase), [{"x": [i for i in range(8760)], "y": [random.uniform(35, 40) for x in range(8760)]} for i in range(26)]))

data2= dict(zip(list(string.ascii_lowercase), [{"x": [i for i in range(870)], "y": [random.uniform(140, 200) for x in range(870)]} for i in range(26)]))

select_data = Select(title= "Select dataset", value= "data1", options= ["data1", "data2"])

def data_update(attr, new, old):
    for f in list(string.ascii_lowercase):
        print(select_data.value + '\n\n')
        data[f].data= dict(x= globals()[select_data.value][f]["x"], y= globals()[select_data.value][f]["y"])

data= {f: ColumnDataSource(data= dict(x= data1[f]["x"], y= data1[f]["y"])) for f in list(string.ascii_lowercase)}

checkbox = CheckboxGroup(labels=list(string.ascii_lowercase), active=[0, 1, 4, 7, 10])
order = TextInput(title="Arrange plots in order as in this string")
ind = {}
for f in list(string.ascii_lowercase):
    ind[f] = figure(plot_width= 800, plot_height= 100, tools ='save, reset, resize')
    ind[f].vbar(x= "x", source= data[f], width= 0.5, bottom= 0, top= "y")
    ind[f].y_range= Range1d(start= 32, end= 43)
    ind[f].title.text = f

p = column(*ind.values())

def checkboxchange(attr,new,old):
    plots = []
    for aind in checkbox.active:
        plots.append(ind[checkbox.labels[aind]])
    l.children[0].children[1].children = plots

def orderchange(attr,new,old):
    # check the checkbox
    chval = []
    for aind in checkbox.active:
        chval.append(checkbox.labels[aind])
    # change the order if all the values in the string are also plotted currently
    plots=[]
    orderlist = [order.value[i] for i in range(len(order.value))]
    if(len(set(orderlist+chval)) == len(chval)):
        for aind in orderlist:
            plots.append(ind[aind])
        l.children[0].children[1].children = plots

order.on_change('value', orderchange)
checkbox.on_change('active', checkboxchange)
select_data.on_change('value', data_update)

inputs = widgetbox(*[select_data, order, checkbox], sizing_mode='fixed')

l = layout([
            [inputs, p],
            ], sizing_mode='fixed')

#show(p)
plots = []
for aind in checkbox.active:
    plots.append(ind[checkbox.labels[aind]])

l.children[0].children[1].children = plots

curdoc().add_root(l)
curdoc().title = "test"

实现了字符串排序的示例(仅当用户输入的字符串具有当前选中的值时)

import string
import random
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox, column
from bokeh.models.widgets import CheckboxGroup, TextInput
from bokeh.models import Range1d
from bokeh.io import curdoc, show

data= dict(zip(list(string.ascii_lowercase), [{"x": [i for i in range(8760)], "y": [random.uniform(35, 40) for x in range(8760)]} for i in range(26)]))

checkbox = CheckboxGroup(labels=list(string.ascii_lowercase), active=[0, 1, 4, 7, 10])
order = TextInput(title="Arrange plots in order as in this string")
ind = {}
for f in list(string.ascii_lowercase):
    ind[f] = figure(plot_width= 800, plot_height= 100, tools ='save, reset, resize')
    ind[f].vbar(x= "x", source= data[f], width= 0.5, bottom= 0, top= "y")
    ind[f].y_range= Range1d(start= 32, end= 43)
    ind[f].title.text = f

p = column(*ind.values())

def checkboxchange(attr,new,old):
    plots = []
    for aind in checkbox.active:
        plots.append(ind[checkbox.labels[aind]])
    l.children[0].children[1].children = plots

def orderchange(attr,new,old):
    # check the checkbox
    chval = []
    for aind in checkbox.active:
        chval.append(checkbox.labels[aind])
    # change the order if all the values in the string are also plotted currently    
    plots=[]
    orderlist = [order.value[i] for i in range(len(order.value))]
    if(len(set(orderlist+chval)) == len(chval)):
        for aind in orderlist:
            plots.append(ind[aind])
        l.children[0].children[1].children = plots

order.on_change('value', orderchange)              
checkbox.on_change('active', checkboxchange)   

inputs = widgetbox(*[order, checkbox], sizing_mode='fixed')

l = layout([
            [inputs, p],
            ], sizing_mode='fixed')

#show(p)
plots = []
for aind in checkbox.active:
    plots.append(ind[checkbox.labels[aind]])

l.children[0].children[1].children = plots

curdoc().add_root(l)
curdoc().title = "test"