Skip to content
Advertisement

Updating boxplot when choosing rows

I need to allow users to choose particular rows in a data frame and generate a boxplot.

My implementation does not allow me to update a boxplot when I choose rows. Can somebody please point out what I do wrong? I am interested in only one column which is [‘Phase’].

Here is my implementation.

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)

Advertisement

Answer

I am inexperienced with Dash, but from the example in the official reference, I would guess that the reason is that the value of the active cell is not being retrieved. I found an example of updating a graph by clicking on a data table, so I used that as a basic form to create the code with appropriate sample data. The key point is that I set the initial active cell, and in the callback, I extract the data frame from the row and column data of the latest active cell, from the row index, and use that as the graph data.

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')

enter image description here

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement