【问题标题】:bokeh plot is missing in layout布局中缺少散景图
【发布时间】:2019-08-01 07:51:18
【问题描述】:

我正在尝试使用 python 的散景包创建仪表板。

仪表板将有 6 个 2 x 3 格式的图。每个绘图将在绘图上方有一组小部件,在绘图下方有一个小部件(范围滑块)。

我正在尝试使用 layout() 来使其正常工作。但是,出于某种原因,小部件出现了,但情节却没有。

下面是一个最小的工作示例(使用随机数据)来说明问题。

非常感谢任何帮助。

import numpy as np
import pandas as pd
from bokeh.plotting import figure, show, output_file, curdoc
from bokeh.layouts import layout, row, column, Spacer, widgetbox
from bokeh.models import ColumnDataSource, DateRangeSlider, BoxAnnotation, HoverTool
from bokeh.models.widgets import RangeSlider, Button, CheckboxButtonGroup, Div


# synthetic data

data = pd.DataFrame({
    'date':pd.date_range(start='1/1/2000', periods=1000),
    'x':np.random.choice(range(100), 1000)
})

startDate = data.iloc[0]['date']
endDate = data.iloc[-1]['date']
source = ColumnDataSource(data)


# title
title = Div(text='Some series')

# main figure
p1 = figure(plot_width=635, plot_height=550, x_axis_type='datetime', x_range=(startDate,endDate))
p1.line(x=data['date'], y=data['x'], line_width=2, color='navy')
p1.toolbar.logo = None

# some 'tier-1' widgets
someButton = Button(label='>>', button_type='success')
someSelector = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])

# range slider widget
def updateRange(attr, old, new):
    p1.x_range.start = new[0]
    p1.x_range.end = new[1]

rSlider = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
rSlider.on_change('value', updateRange)


curdoc().add_root(
    layout(
        [[column(title, row(someSelector, someButton), p1, rSlider), column(title, row(someSelector, someButton), p1, rSlider), column(title, row(someSelector, someButton), p1, rSlider)],
        [column(title, row(someSelector, someButton), p1, rSlider), column(title, row(someSelector, someButton), p1, rSlider), column(title, row(someSelector, someButton), p1, rSlider)]]
    )
)

【问题讨论】:

    标签: python bokeh dashboard


    【解决方案1】:

    您的代码不会向终端抛出错误,但会在浏览器的控制台中抛出错误 (F12):错误:重复编辑变量:Plot(1009).height。在我Googled 出现错误后,我发现无法将相同的绘图/小部件多次添加到您的文档中。

    如果你像这样绘制它确实有效:

    import numpy as np
    import pandas as pd
    from bokeh.plotting import figure, show, output_file, curdoc
    from bokeh.layouts import layout, row, column, Spacer, widgetbox
    from bokeh.models import ColumnDataSource, DateRangeSlider, BoxAnnotation, HoverTool
    from bokeh.models.widgets import RangeSlider, Button, CheckboxButtonGroup, Div
    
    
    # synthetic data
    
    data = pd.DataFrame({
        'date':pd.date_range(start='1/1/2000', periods=1000),
        'x':np.random.choice(range(100), 1000)
    })
    
    startDate = data.iloc[0]['date']
    endDate = data.iloc[-1]['date']
    source = ColumnDataSource(data)
    
    
    # title
    title1 = Div(text='Some series')
    title2 = Div(text='Some series')
    title3 = Div(text='Some series')
    title4 = Div(text='Some series')
    title5 = Div(text='Some series')
    title6 = Div(text='Some series')
    
    # main figure
    p1 = figure( x_axis_type='datetime', x_range=(startDate,endDate))
    p1.line(x=data['date'], y=data['x'], line_width=2, color='navy')
    p1.toolbar.logo = None
    
    p2 = figure( x_axis_type='datetime', x_range=(startDate,endDate))
    p2.line(x=data['date'], y=data['x'], line_width=2, color='navy')
    p2.toolbar.logo = None
    
    p3 = figure( x_axis_type='datetime', x_range=(startDate,endDate))
    p3.line(x=data['date'], y=data['x'], line_width=2, color='navy')
    p3.toolbar.logo = None
    
    p4 = figure( x_axis_type='datetime', x_range=(startDate,endDate))
    p4.line(x=data['date'], y=data['x'], line_width=2, color='navy')
    p4.toolbar.logo = None
    
    p5 = figure( x_axis_type='datetime', x_range=(startDate,endDate))
    p5.line(x=data['date'], y=data['x'], line_width=2, color='navy')
    p5.toolbar.logo = None
    
    p6 = figure( x_axis_type='datetime', x_range=(startDate,endDate))
    p6.line(x=data['date'], y=data['x'], line_width=2, color='navy')
    p6.toolbar.logo = None
    
    
    # some 'tier-1' widgets
    someButton1 = Button(label='>>', button_type='success')
    someSelector1 = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])
    someButton2 = Button(label='>>', button_type='success')
    someSelector2 = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])
    someButton3 = Button(label='>>', button_type='success')
    someSelector3 = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])
    someButton4 = Button(label='>>', button_type='success')
    someSelector4 = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])
    someButton5 = Button(label='>>', button_type='success')
    someSelector5 = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])
    someButton6 = Button(label='>>', button_type='success')
    someSelector6 = CheckboxButtonGroup(labels=['Series A', 'Series B'], active=[0, 1])
    
    # range slider widget
    def updateRange(attr, old, new):
        p1.x_range.start = new[0]
        p1.x_range.end = new[1]
        p2.x_range.start = new[0]
        p2.x_range.end = new[1]
        p3.x_range.start = new[0]
        p3.x_range.end = new[1]
        p4.x_range.start = new[0]
        p4.x_range.end = new[1]
        p5.x_range.start = new[0]
        p5.x_range.end = new[1]
        p6.x_range.start = new[0]
        p6.x_range.end = new[1]
    
    rSlider1 = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
    rSlider1.on_change('value', updateRange)
    rSlider2 = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
    rSlider2.on_change('value', updateRange)
    rSlider3 = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
    rSlider3.on_change('value', updateRange)
    rSlider4 = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
    rSlider4.on_change('value', updateRange)
    rSlider5 = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
    rSlider5.on_change('value', updateRange)
    rSlider6 = DateRangeSlider(start=startDate, end=endDate, value=(startDate,endDate), show_value=False, width=600)
    rSlider6.on_change('value', updateRange)
    
    curdoc().add_root(
        layout(
            [[column(title1, row(someSelector1, someButton1), p1, rSlider1), column(title2, row(someSelector2, someButton2), p2, rSlider2), column(title3, row(someSelector3, someButton3), p3, rSlider3)],
            [column(title4, row(someSelector4, someButton4), p4, rSlider4), column(title5, row(someSelector5, someButton5), p5, rSlider5), column(title6, row(someSelector6, someButton6), p6, rSlider6)]]
        )
    )
    

    【讨论】:

    • 谢谢,这行得通。我想使用玩具示例来测试布局的陷阱。感谢您解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多