动态更新破折号表列名称

Update dashtable columns name dynamically

我正在尝试制作一个破折号表,它的列将根据下拉值动态更改。

下面是我的示例代码:

import pandas as pd
import numpy as np
import plotly.express as px
import dash
from dash import html
from dash import dcc
from dash.dependencies import Input, Output,State
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
from dash import dash_table

df1 = pd.DataFrame({
    'Contract No': ['VN122001','VN122002','VN122003','VN122004','VN122005'],
    'Amount': [22071,20775,20841,21891,22395]})
df1 = df1.set_index('Contract No')

df2 = pd.DataFrame({
    'Contract No': ['VN122001','VN122002','VN122003','VN122004','VN122005'],
    'Cusname': ['A','B','C','D','E'],
    'Branch': ['HN','HCM','HP','BN','DN']})
df2 = df2.set_index('Contract No')

app = dash.Dash(__name__,external_stylesheets=[dbc.themes.LUX])

app.layout = html.Div([
    dbc.Row([   
            dbc.Col([
                    dcc.Dropdown(id='columns_name',placeholder="Columns name", # Dropdown for heatmap color
                    options=list_column, 
                    value='Cusname',
                    multi=False,
                    disabled=False,
                    clearable=True,
                    searchable=True)    
                    ],width={'size':4,'offset':0,'order':1},style={'padding-top' : 15}),
    ]),
    dbc.Row([
        html.Div(
        id = 'tableDiv',
        className = 'tableDiv'
    )
    ])
])

@app.callback(Output('tableDiv', 'children'),
             [Input('columns_name', 'value')])
              
def update_columns_name(columns):
    col_name = df2[[columns]] 
    df3 = pd.merge(df1, col_name, left_index=True, right_index=True)
    df3 = df3.reset_index()
    mycolumns = [{'name': i, 'id': i} for i in df3.columns]
    return html.Div([
                dash_table.DataTable(
            id='table',
            columns=mycolumns,
            data=df3.to_dict("rows")
         )
        ])
if __name__ == "__main__":
    app.run_server(debug=False,port=1222)

实际上它运行良好,但是当我尝试创建 Tabs 然后 return 它到 Tab 时,没有任何显示。下面是我创建标签的代码。

app.layout = html.Div([dbc.Tabs(
            [dbc.Tab(label="Dashboard", tab_id="dashboard"),
            dbc.Tab(label="Table", tab_id="table"),
            ],
            id="tabs",
            active_tab="dashboard"),
    html.Div(id="tab-content", className="p-4"),
    ])

@app.callback(
    Output("tab-content", "children"),
    [Input("tabs", "active_tab")])

def render_tab_content(active_tab):
    if active_tab == "dashboard":
        return html.Div([dbc.Row([html.H5('Graphs')])])
    elif active_tab == "table":
        return html.Div([
        dbc.Row([
        html.Div(id = 'tableDiv',
        className = 'tableDiv')
    ])
])
    
@app.callback(Output('tableDiv', 'children'),
             [Input('columns_name', 'value')])
              
def update_columns_name(columns):
    col_name = df2[[columns]] 
    df3 = pd.merge(df1, col_name, left_index=True, right_index=True)
    df3 = df3.reset_index()
    mycolumns = [{'name': i, 'id': i} for i in df3.columns]
    return html.Div([
            dash_table.DataTable(
            id='table',
            columns=mycolumns,
            data=df3.to_dict("rows"))
        ])
if __name__ == "__main__":
    app.run_server(debug=False,port=1222)   

我应该怎么做才能解决这个问题。谢谢。

这是 javascript 在浏览器控制台中返回的错误:

Object { message: "ID not found in layout", html: "Attempting to connect a callback Output item to component:\n \"tableDiv\"\nbut no components with that id exist in the layout.\n\nIf you are assigning callbacks to components that are\ngenerated by other callbacks (and therefore not in the\ninitial layout), you can suppress this exception by setting\n```suppress_callback_exceptions=True```.\nThis ID was used in the callback(s) for Output(s):\n tableDiv.children" } dash_renderer.v2_1_0m1644023699.min.js:2:84904

Object { message: "ID not found in layout", html: "Attempting to connect a callback Input item to component:\n \"columns_name\"\nbut no components with that id exist in the layout.\n\nIf you are assigning callbacks to components that are\ngenerated by other callbacks (and therefore not in the\ninitial layout), you can suppress this exception by setting\n```suppress_callback_exceptions=True```.\nThis ID was used in the callback(s) for Output(s):\n tableDiv.children" }

正如它所暗示的那样,您指的是另一个回调生成的 id 组件(即回调 render_tab_content 生成 tableDiv div 并被 update_column_name).这是一个问题,因为当您 select 仪表板 table 时,您的 tableDiv 将不存在,但回调仍可能被调用(至少最初是这样,这就是您遇到问题的原因开头)。

最好将 update_column_name 的内容与 render_table_content 结合起来,并通过一个回调生成您需要的列内容。在这种情况下,拆分为 2 个回调实际上并没有任何好处,如果您真的愿意,可以将另一个回调的内容抽象为一个普通函数,然后在 render_tab_content 中调用它。这是一个建议的改编:

def update_columns_name(columns):
    col_name = df2[[columns]]
    df3 = pd.merge(df1, col_name, left_index=True, right_index=True)
    df3 = df3.reset_index()
    mycolumns = [{'name': i, 'id': i} for i in df3.columns]
    return (
        html.Div([
            dbc.Row([
                html.Div([
                    html.Div([
                        dash_table.DataTable(
                            id='table',
                            columns=mycolumns,
                            data=df3.to_dict("rows")
                        )
                    ])
                ],
                    id='tableDiv',
                    className='tableDiv')
            ])
        ])
    )


@app.callback(
    Output("tab-content", "children"),
    [Input("tabs", "active_tab")],
    [State('columns_name', 'value')]
)
def render_tab_content(active_tab, columns):
    print(active_tab, columns)
    if active_tab == "dashboard":
        return html.Div([dbc.Row([html.H5('Graphs')])])
    elif active_tab == "table":
        return update_columns_name(columns)