选择行时更新箱线图

Updating boxplot when choosing rows

我需要允许用户选择数据框中的特定行并生成箱线图。

我的实现不允许我在选择行时更新箱线图。有人可以指出我做错了什么吗?我只对 ['Phase'].

一栏感兴趣

这是我的实现。

from dash import Dash, dash_table, dcc, html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objects as px


df = summary_extended.copy()

app = JupyterDash(__name__)

app.layout = html.Div([
    dash_table.DataTable(
        id='datatable-interactivity',
        columns=[
            {"name": i, "id": i, "deletable": True, "selectable": True} for i in df.columns
        ],
        data=df.to_dict('records'),
        editable=True,
        filter_action="native",
        sort_action="native",
        sort_mode="multi",
        column_selectable="single",
        row_selectable="multi",
        row_deletable=True,
        selected_columns=[],
        selected_rows=[],
        page_action="native",
        page_current= 0,
        page_size= 10,
    ),
    html.Div(id='datatable-interactivity-container')
])

@app.callback(
    Output('datatable-interactivity-container', "children"),
    Input('datatable-interactivity', "derived_virtual_data"),
    Input('datatable-interactivity', "derived_virtual_selected_rows"))
def update_graphs(rows, derived_virtual_selected_rows):
    if derived_virtual_selected_rows is None:
        derived_virtual_selected_rows = []

    dff = summary_extended if rows is None else pd.DataFrame(rows)
    print('rows', rows)

    colors = ['#7FDBFF' if i in derived_virtual_selected_rows else '#0074D9'
              for i in range(len(dff))]
    y= dff['Phase']      
    trace0 = go.Box(y=y)
    data=[trace0]

    return [
            dcc.Graph(figure={'data': data}, id='box-plot')
    ]



if __name__ == '__main__':
    app.run_server(debug=True)

我对 Dash 没有经验,但从官方参考中的示例来看,我猜测原因是未检索活动单元格的值。我找到了一个通过单击数据 table 来更新图表的示例,因此我将其用作基本形式来创建具有适当示例数据的代码。关键是我设置了初始活动单元格,在回调中,我从最新活动单元格的行和列数据、行索引中提取数据框,并将其用作图形数据。

from dash import Dash, dash_table, dcc, html, no_update
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import pandas as pd
import plotly.graph_objects as px
import plotly.express as px

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

#app = Dash(__name__, external_stylesheets=external_stylesheets)
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)

mixed_df = px.data.experiment(indexed=False)
mixed_df['experiment_1'] = round(mixed_df['experiment_1'], 2)
mixed_df['experiment_2'] = round(mixed_df['experiment_2'], 2)
mixed_df['experiment_3'] = round(mixed_df['experiment_3'], 2)
mixed_df['experiment_4'] = round(mixed_df['experiment_1'] * 0.85, 2)
mixed_df['experiment_5'] = round(mixed_df['experiment_2'] * 0.85, 2)
mixed_df['experiment_6'] = round(mixed_df['experiment_3'] * 0.85, 2) 
mixed_df['id'] = mixed_df.index
mixed_df = mixed_df[['id','gender','group','experiment_1','experiment_2','experiment_3','experiment_4','experiment_5','experiment_6']]
mixed_df.columns = ['id','gender','group','experi_1','experi_2','experi_3','experi_4','experi_5','experi_6']
columns = mixed_df.columns
initial_active_cell = {"row": 0, "column": 0, "column_id": "id", "row_id": 0}

app.layout = html.Div(
    [
        html.Div(
            [
                html.H3("Experiment Box Plot", style={"textAlign":"center"}),
                dash_table.DataTable(
                    id="table",
                    columns=[{"name": c, "id": c} for c in columns],
                    data=mixed_df.to_dict("records"),
                    page_size=10,
                    sort_action="native",
                    active_cell=initial_active_cell,
                ),
            ],
            style={"margin": 50},
            className="seven columns"
        ),
        html.Div(id="output-graph", className="three columns"),
    ],
    className="row"
)


@app.callback(
    Output("output-graph", "children"), Input("table", "active_cell"),
)
def cell_clicked(active_cell):
    if active_cell is None:
        return no_update

    row = active_cell["row_id"]
    print(f"row id: {row}")
    print("---------------------")
    
    dff = mixed_df.iloc[row,:].to_frame().T
    #print(dff)
    fig = px.box(
        dff, x='gender', y=dff.columns[2:], title=f'Selected row num: {row}'
    )
    fig.update_layout(title={"font_size": 20}, title_x=0.5, margin=dict(t=190, r=15, l=5, b=5))

    return dcc.Graph(figure=fig)


if __name__ == "__main__":
    app.run_server(debug=True, mode='inline')