菜单选择在散景多仪表板生成器中不起作用

问题描述 投票:0回答:1

我有一个脚本,使用 easgui 提示用户输入他们感兴趣的系统的名称和感兴趣的参数以及其他几个配置。然后继续为所有参数和系统创建 Bokeh(使用版本“2.4.3”)仪表板,其中每个系统都有一个仪表板,其中包含该仪表板所需的所有可用参数数据。在我的脚本末尾,我定义了一个菜单,以便用户可以选择在生成整个内容后他们看到的系统仪表板。但是菜单在某种意义上不起作用,因为它只显示默认值并且从中选择任何选项都不会改变实际显示的内容。

下面是最小的可复制示例:

import os
import pandas as pd
import numpy as np
import os
from bokeh import plotting
from bokeh import layouts
from bokeh.models.tools import HoverTool
from bokeh.models.widgets.markups import Div
from bokeh.models import CustomJS, TapTool, Button, ColumnDataSource, Select, DatetimeTickFormatter
from bokeh.io import curdoc

systems=['TestSys1', 'TestSys2']
dashboards={}
dash_sources={}
index_list = list(range(len(systems)))
sys_figs={}
for idx in index_list:
    system=systems[idx]
    save_loc=r'.\Test'
    customer='TestCustomer'
    all_or_view='all'
    conceal_params=False

    sys_figs[system] = {}

    system_params=['p_1', 'p_2', 'p_3', 'p_4']

    first_logtime = '1990-01-01 00:00:00.000'
    last_logtime = '2023-01-01 00:00:00.000'
    
    # Initialise objects for tracking things that need to be tracked
    indices = list(range(len(system_params)))
    shared_x_range = None
    figures = {}
    sources = {param:ColumnDataSource() for param in system_params}
    
    for idx in indices:
        param_name = system_params[idx]
        param_id = system_params[idx]
                
        param_name_normalised = param_name.replace(' ', '')

        raw_label=param_name

        dates = pd.date_range(start=first_logtime, end=last_logtime, freq='D')
        data = np.random.randn(len(dates), 1)
        df = pd.DataFrame(data=data, index=dates, columns=[param_name])
        df.index.name='LogTime'
        src=ColumnDataSource(df)
        

        prepared_param_data={'source':src}

        # Save the param_last_log_time for this param so that the update function can then query
        # the database and stream and plot only data that has LogTime greater than the previous 
        # param_last_log_time, if any.

        sources[param_name].data = dict(prepared_param_data['source'].data)

        ## Set shared_x_range ##
        if len(figures) > 0:
            first_plotted_param = list(figures.keys())[0]
            shared_x_range=figures[first_plotted_param].x_range
        else:
            shared_x_range=None

        ## Instantiate figures ##
        
        if shared_x_range != None:
            sys_figs[system][param_name] = plotting.figure(x_axis_label='DateTime',
                                y_axis_label=raw_label,
                                x_range=shared_x_range,
                                x_axis_type='datetime',
                                title=raw_label,
                                toolbar_location='right')
        else:
            sys_figs[system][param_name] = plotting.figure(x_axis_label='DateTime',
                                y_axis_label=raw_label,
                                x_axis_type='datetime',
                                title=raw_label,
                                toolbar_location='right')
        
        ## Plot line glyph for data ##
        sys_figs[system][param_name].line(x='LogTime', 
                                            y=raw_label, 
                                            source=src, 
                                            color='#47ed00',
                                            line_alpha=0.7,
                                            muted_alpha=0.2,
                                            legend_label=raw_label)
        
        
        param_fig = sys_figs[system][param_name]
        
        if param_fig != None:
            figures[param_name_normalised] = param_fig

    # Construct dashboard
    figure_columns=[layouts.column(figures['p_1'], figures['p_2']),
                    layouts.column(figures['p_3'], figures['p_4'])]

    dashboard = layouts.row(figure_columns)
    
    dashboard_title = Div(text=f"{system} Dashboard", style={'font-size':'30px', 'color':'black'}, width=3000)

    dashboard = layouts.column(dashboard_title, dashboard)
    
    dashboards[system]=dashboard
    dash_sources[system]=sources
    print(f'Dashboard for {system} created.')


# Create a dropdown menu with options for each dashboard key
dashboard_keys = list(dashboards.keys())
dashboard_select = Select(title="Select Dashboard", value=dashboard_keys[0], options=dashboard_keys)

# Create a ColumnDataSource to hold the selected dashboard
selected_dashboard = ColumnDataSource(data={'dashboard': [dashboards[dashboard_keys[0]]]})

def update_dashboard(attrname, old, new):
    selected_dashboard.data = {'dashboard': [dashboards[new]]}
    selected_dashboard.change.emit()

dashboard_select.on_change('value', update_dashboard)

# Create a layout with the dropdown menu and the selected dashboard
layout = layouts.column(dashboard_select, selected_dashboard.data['dashboard'][0])

# Add a callback to update the layout when the selected_dashboard changes
def update_layout(attrname, old, new):
    layout.children[1] = selected_dashboard.data['dashboard'][0]

selected_dashboard.on_change('data', update_layout)

# Add the layout to the current document
curdoc().add_root(layout)

然后我通过从 Anaconda 命令行运行

bokeh serve --show "C:\Users\a00555655\OneDrive - ONEVIRTUALOFFICE\Documents\Test\StackExchangeExample.py" --port 1535
来提供服务。

为什么下拉菜单不起作用?

我尝试了很多东西,但没有成功。问题似乎出在回调上,但我不确定我哪里出错了。

python bokeh
1个回答
0
投票

这就是问题所在:

    selected_dashboard.change.emit()

JS和Python控制台都报错(你没看到这些吗?):

AttributeError:ColumnDataSource 的意外属性“更改”,可能的属性是数据、js_event_callbacks、js_property_callbacks、name、selected、selection_policy、subscribed_events、syncable 或 tags

如果我删除该行,示例代码对我有用。

仅供参考,如果您为

source.data
分配一个全新的值,例如
source.data = new_data
,它会被自动检测到——无需其他操作即可触发更新。仅当“就地”更新列时才需要调用
emit
(不鼓励这样做)。

© www.soinside.com 2019 - 2024. All rights reserved.