简体   繁体   English

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

[英]Using checkbox widget in Bokeh to hide or show lines for dynamic number of lines

I am trying to add checkboxes in my bokeh plot so that I can hide or show different lines in my plot. 我试图在bokeh图中添加复选框,以便可以在图中隐藏或显示不同的线条。 I found some code from github and modified it to fulfil my purpose. 我从github找到了一些代码,并对其进行了修改以实现我的目的。 Please have a look into the below code, 请看下面的代码,

    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)     

This code works perfectly. 此代码完美地工作。 However my requirment is something else. 但是我的要求是其他。 In my case the number of plts will be different each time I run the code as my data is different. 就我而言,由于我的数据不同,因此每次运行代码时的plts数量都会不同。 So I tried to modify this code but have not had any success yet. 因此,我尝试修改此代码,但尚未成功。

The changes I made are 我所做的更改是

    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

I also tried using 我也尝试使用

    source = ColumnDataSource(data = dict( ... ) ...
    callback = CustomJS(args=dict(source=source), code="""

But it failed as well and did not show any plot. 但是它也失败了,没有显示任何情节。 I'm using the latest version of Bokeh and python 2.7 Any suggestion is highly appriciated and thanks in advance !! 我正在使用Bokeh和python 2.7的最新版本。任何建议都得到高度重视,在此先感谢!! :) :)

You can do something like this: 您可以执行以下操作:

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

This builds the callback code based on the number of lines. 这将基于行数构建回调代码。 Since you asked for the code to adapt to your data, you can certainly determine the number of lines from the data. 由于您要求使用代码来适应您的数据,因此可以肯定地确定数据中的行数。

After that, if you also want to add lines dynamically through interactions you need to update: 之后,如果您还想通过交互来动态添加行,则需要更新:

checkbox.labels (just add one label name) checkbox.labels (只需添加一个标签名称)

checkbox.active (set it to a range() list with one more number) checkbox.active (将其设置为具有更多数字的range()列表)

checkbox.callback (with one more pair for "args" and one more entry for "code") checkbox.callback (其中一对用于“ args”,另一对用于“ code”)

Actually I found out the answer to this question from the following post 其实我从下面的帖子中找到了这个问题的答案

How to interactively display and hide lines in a Bokeh plot? 如何交互显示和隐藏散景图中的线?

In the Comment section user2561747 has suggested something similar. 在“注释”部分中,user2561747提出了类似的建议。 Initially I was having problems becasue I wanted to use hover tool as well for which I was trying to name each plot differently and then something like that 最初我遇到问题是因为我也想使用悬停工具,为此我试图用不同的方式命名每个图,然后再用类似的方式命名

    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];
    """)

I could never figure out what the problem was but I ended up naming all the plots "hideable" and it worked for the hover tool as well. 我永远无法弄清楚问题出在哪里,但是我最终将所有地块都命名为“隐藏”,它也适用于悬停工具。 So the final code looks something like this, 所以最终的代码看起来像这样,

    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];
    """)

If anyone can find out the problem with the 1st approach that would be awesome. 如果有人能找到第一种方法的问题,那就太好了。 I saw absolutely no error in the browser console however the elements of rends array had different structures in both cases. 我在浏览器控制台中看不到任何错误,但是在两种情况下,rends数组的元素都有不同的结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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