Javascript 使用Bokeh中的复选框小部件隐藏或显示动态行数的行

Javascript 使用Bokeh中的复选框小部件隐藏或显示动态行数的行,javascript,python,python-2.7,bokeh,Javascript,Python,Python 2.7,Bokeh,我试图在我的博克图中添加复选框,以便在我的图中隐藏或显示不同的线。我从github中找到了一些代码,并对其进行了修改以达到我的目的。请查看下面的代码 for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4): df = pd.DataFrame(data) source = ColumnDataSo

我试图在我的博克图中添加复选框,以便在我的图中隐藏或显示不同的线。我从github中找到了一些代码,并对其进行了修改以达到我的目的。请查看下面的代码

    for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):          
        df = pd.DataFrame(data) 
        source = ColumnDataSource(data = dict(date = pd.to_datetime(df['date']), close = df['close']))                      
        plt = fig.line('date', 'close', line_width=2, color=color, alpha=0.8,
               muted_color=color, muted_alpha=0.2, legend = name, source=source)

        graph_labels.append(name)
        plots.append(plt)

    checkbox = CheckboxGroup(labels = graph_labels, active = [0,1,2,3]) 

    checkbox.callback = CustomJS(args = dict(line0 = plots[0], line1=plots[1], line2=plots[2], line3=plots[3]),  code=""" 
        //console.log(cb_obj.active);
        line0.visible = false;
        line1.visible = false;
        line2.visible = false;
        line3.visible = false;

        for (i in cb_obj.active) {
            //console.log(cb_obj.active[i]);
            if (cb_obj.active[i] == 0) {
                line0.visible = true;
            } else if (cb_obj.active[i] == 1) {
                line1.visible = true;
            } else if (cb_obj.active[i] == 2) {
                line2.visible = true;
            } else if (cb_obj.active[i] == 3) {
                line3.visible = true;
            }
        }
    """)

    layout = row(fig, widgetbox(checkbox), sizing_mode='fixed')

    show(layout)     
这段代码工作得很好。然而,我的要求是别的。在我的情况下,每次运行代码时,PLT的数量都会不同,因为我的数据不同。所以我试图修改这段代码,但还没有成功

我所做的改变是

    checkbox = CheckboxGroup(labels = graph_labels, active = list(range(0, len(plots))))
    arg_list = []

    for idx in range(0, len(plots)):
        arg_list.append('line' + str(idx))
        arg_list.append(plots[idx])

    i = iter(arg_list)  
    checkbox.callback = CustomJS(args = dict(izip(i, i)),  code=""" 
        // Here I don't know how to use dynamic names for line0 and line1 and use them to control their visibility
        // As type of line0 is object and if I 'm trying to make a dynamic string I can't convert it to object and it fails
我也试过使用

    source = ColumnDataSource(data = dict( ... ) ...
    callback = CustomJS(args=dict(source=source), code="""
但它也失败了,没有显示任何阴谋。 我使用的是Bokeh和Python2.7的最新版本
我们非常感谢您的任何建议!!:)

您可以这样做:

from bokeh.io import show
from bokeh.plotting import figure
from bokeh.models import CustomJS, CheckboxGroup
from bokeh.layouts import Row
from bokeh.palettes import Category20_20

from random import random,choice

N_lines = int(100*random())/10 # undefined but known from the start number of lines.

x= range(3)
fig = figure()
args = []
code = "active = cb_obj.active;"
for i in range(N_lines):
    glyph = fig.line(x,[random() for j in x],color=choice(Category20_20))
    args += [('glyph'+str(i),glyph)]
    code += "glyph{}.visible = active.includes({});".format(i,i)

checkbox = CheckboxGroup(labels=[str(i) for i in range(N_lines)],active=range(N_lines))

checkbox.callback = CustomJS(args={key:value for key,value in args},code=code)

show(Row(fig,checkbox))
这将根据行数生成回调代码。 因为您要求代码适应您的数据,所以您当然可以根据数据确定行数

之后,如果还希望通过交互动态添加行,则需要更新:

复选框.标签
(只需添加一个标签名称)

checkbox.active
(将其设置为包含一个以上数字的范围()列表)


checkbox.callback
(多了一对“args”和一个“code”条目)

事实上,我从下面的帖子中找到了这个问题的答案

在评论部分,user2561747提出了类似的建议。起初,我遇到了一些问题,因为我想使用悬停工具,我试图用不同的名称命名每个情节,然后诸如此类

    for column, color in zip(df.columns.values, Spectral4):
    ...... 
    ...... 
         plt = fig.line('date', 'value', name = column, line_width = 2, color = color, alpha = 0.8,
                   muted_color = color, muted_alpha = 0.2, legend = column, source = source)

         graph_labels.append(column)
         plots.append(plt)
    ......
    ......

    checkbox = CheckboxGroup(labels = graph_labels, active = list(range(0, len(plots))))    

    checkbox.callback = CustomJS.from_coffeescript(args = dict(plot = fig, checkbox = checkbox), code=""" 
    rends = []; 
    rends.push plot.select(label) for label in checkbox.labels;
    rends[i].visible = i in checkbox.active for i in [0...rends.length];
    """)
我从来都不知道问题出在哪里,但我最终把所有的情节都命名为“可隐藏的”,这也适用于悬停工具。最后的代码是这样的

    checkbox.callback = CustomJS.from_coffeescript(args = dict(plot = fig, checkbox = checkbox), code=""" 
    rends = plot.select("hideable");
    rends[i].visible = i in checkbox.active for i in [0...rends.length];
    """)

如果有人能发现第一种方法的问题,那就太棒了。我在浏览器控制台中完全没有看到任何错误,但是在这两种情况下,rends数组的元素具有不同的结构

非常感谢您的回复。不幸的是,这种方法并不适合我。当我尝试在您建议的修改后运行我的代码时,它根本没有显示任何绘图。@neo我提供的代码在所有浏览器中都能正常工作。当你把它调整到你的时候,你会错过什么吗?很好的答案。我想在for循环之外这样做:只是让其他人知道,
code
类似于
active=cb_obj.active;glyph0.visible=活动。包括(0);glyph1.visible=活动。包括(1)
@FrancescoBoi谢谢,但是请注意,在bokeh中实现交互式图例以显示/隐藏线条之前,现在我建议使用它,而不是创建自定义复选框