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