【问题标题】:Python Bokeh CustomJS RadioGroupPython Bokeh CustomJS RadioGroup
【发布时间】:2017-09-06 13:55:29
【问题描述】:

我对 Python 和 Pandas 有相当的经验,但对 Bokeh 包非常陌生,过去几天一直在努力完成这项任务,但没有任何进展。我正在构建一个仪表板来显示数据,使用单选按钮在同一个图上选择/显示不同的线会非常有帮助。我一直在关注这里的示例 (https://github.com/bokeh/bokeh/issues/3715),我可以使用复选框正常工作。我已在第 21 行将“CheckboxGroup”更改为“RadioGroup”,以及“active”参数。结果是,当我更改单选按钮的选择并且再也没有回来时,两条绘制的线都消失了。我不明白为什么 CheckboxGroup 有效而 RadioGroup 无效,考虑到它们有多相似并且它们都使用“活动”事件进行回调。有人可以指出我的错误吗?

import numpy as np

from bokeh.io import show
from bokeh.layouts import widgetbox
from bokeh.models.widgets import CheckboxGroup, RadioGroup
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.layouts import column, row
from bokeh.plotting import figure

t = np.arange(0.0, 2.0, 0.01)
s = np.sin(3*np.pi*t)
c = np.cos(3*np.pi*t)

source = ColumnDataSource(data=dict(t=t, s=s, c=c))

plot = figure(plot_width=400, plot_height=400)
a = plot.line('t', 's', source=source, line_width=3, line_alpha=0.6, 
line_color='blue')
b = plot.line('t', 'c', source=source, line_width=3, line_alpha=0.6,
line_color='red')

checkbox = RadioGroup(labels=["Cosinus", "Sinus"], active=0)

checkbox.callback = CustomJS(args=dict(line0=a, line1=b), code="""   
    //console.log(cb_obj.active);
    line0.visible = false;
    line1.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;
        }
    }
""")

layout = row(plot, widgetbox(checkbox))

show(layout)

【问题讨论】:

    标签: javascript python charts bokeh dashboard


    【解决方案1】:

    在 radioboxgroup 中,您一次只能有一个活动值,因此当您尝试循环一个整数时,您的 for 循环是无用的。这是您的代码更正

    checkbox.callback = CustomJS(args=dict(line0=a, line1=b), code="""   
        line0.visible = false;
        line1.visible = false;
    
        if (cb_obj.active == 0) {
            line0.visible = true;
        } else if (cb_obj.active == 1) {
            line1.visible = true;
        }
    """)
    

    有一个更好的方法可以做到这一点,如果你有很多行,你可以在一个循环中使用“标签”列表的长度

    line_list = [line0,line1];
    
    lab_len=cb_obj.labels.length;
    
    for (i=0;i<lab_len;i++) {
    if (cb_obj.active == i) {
    line_list[i].visible = true;
    } else {
    line_list[i].visible = false;
    }
    }
    

    在复选框组中,“活动”属性是索引列表。您只需更改 if 条件即可使代码正常工作:

    checkbox = CheckboxGroup(labels=["Cosinus", "Sinus"], active=[0,1])
    
    checkbox.callback = CustomJS(args=dict(line0=a, line1=b), code="""   
        line_list = [line0,line1];
    
        lab_len=cb_obj.labels.length;
    
        for (i=0;i<lab_len;i++) {
        if (cb_obj.active.includes(i)) {
        line_list[i].visible = true;
        } else {
        line_list[i].visible = false;
        }
        }
    """)
    

    【讨论】:

    • 这正是我一直在寻找的,现在就像一个魅力:)
    【解决方案2】:

    我认为使用 multi_line 方法更容易绘制它。然后您可以选择在回调中选择哪些行,如下所示。

    import numpy as np
    
    from bokeh.io import show
    from bokeh.layouts import widgetbox
    from bokeh.models.widgets import CheckboxGroup, RadioGroup
    from bokeh.models import CustomJS, ColumnDataSource
    from bokeh.layouts import column, row
    from bokeh.plotting import figure
    
    t = np.arange(0.0, 2.0, 0.01)
    s = np.sin(3*np.pi*t)
    c = np.cos(3*np.pi*t)
    
    source = ColumnDataSource(data=dict(t=[t]*2, s=[s,c], colors = ['red', 'blue']))
    
    plot = figure(plot_width=400, plot_height=400)
    plot.multi_line('t', 's',line_color='colors' ,source=source)
    
    checkbox = RadioGroup(labels=["Cosinus", "Sinus"], active=0)
    
    checkbox.callback = CustomJS(args=dict(s=source), code="""   
        s.selected['1d'].indices = [cb_obj.active]
        s.trigger('change');
    """)
    
    layout = row(plot, widgetbox(checkbox))
    
    show(layout)
    

    【讨论】:

    • 我喜欢这种紧凑性,我将不得不在下一个仪表板中使用它。我一直在 Bokeh 中使用 pandas DataFrames(或其切片),但我在很多地方都看到了 ColumnDataSource。将来自 DF 的相关数据放在 ColumnDataSource 中然后绘制而不是直接使用 DF 是否值得?
    • 使用 ColumnDataSources 和其他数据源对象的关键原因是大多数级别的交互性和动态更新都需要它们。要使用数据框更新或更改绘图,您很可能每次都必须重新创建整个绘图。到目前为止,根据我的经验,我发现使用 ColumnDataSource 更容易,如果我想要来自 DF 的数据,只需使用 to_dict 方法。
    【解决方案3】:

    如果您想让用户轻松控制字形的可见性,那么从 Bokeh 0.12.5 开始,您可以让图例具有交互性,以便在用户单击图例条目时隐藏字形或使其静音:

    如果要完全隐藏字形,请将图例的 click_policy 设置为 "hide"

    p = figure()
    p.circle([1,2,3], [4,5,6], legend="foo")
    p.square([1,2,3], [7,9,8], legend="bar")
    p.legend.click_policy = "hide"
    

    您还可以将策略设置为静音:

    p.legend.click_policy = "mute"
    

    但您需要指定每个字形的“静音”外观,例如

    p.circle([1,2,3], [4,5,6], muted_alpha=0.2, legend="foo")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2019-09-07
      相关资源
      最近更新 更多