plotly dash update datatable data on barchart click

Viewed 1277

I have a Plotly dash barchart and datatable, I want the datatable to be updated when there is a click on one of the barcharts.

I am currently reading the click data the selected bar in display_click_data() and using that value to filter a dataframe which I want to update the datatable with. The issue is I am not sure how to return the dataframe and update the datatable. Do I need a separate update_table() function for this or can I just return it from within the update_click_data() function and recreate the datatable from that ? or is there a better way to do this ?

app = DjangoDash('SimpleExample')
df1 = get_spec_dataframe('security')
df_data = get_mostfrequent_data_all()
most_frequent_words = df_data[0][:30]
most_frequent_words_values = df_data[1][:30]
df = get_dataframe()

app.layout = html.Div([
    dcc.Graph(
        id='basic-interactions',
        figure={
            'data': [
                {
                    'x': most_frequent_words,
                    'y': most_frequent_words_values,
                    'name': 'Trace 1',
                    'mode': 'markers',
                    'type': 'bar'
                }  
            ],
            'layout': {
                'clickmode': 'event+select'
            }
        }
    ),

    html.Div(className='row', children=[

        html.Div([
            html.Pre(id='click-data'),
            dash_table.DataTable(id='table',columns=[{"name": i, "id": i} for i in df.columns],data=df.to_dict('records')),
            ], className='three columns'),
    ])
])

@app.callback(
    Output('click-data', 'children'),
    [Input('basic-interactions', 'clickData')])
def display_click_data(clickData):

    if clickData != None:
        label = str(clickData['points'][0]['x'])
    else:
        label = "security"
    df = get_spec_dataframe(label)
    return (df)

1 Answers

You could try the following:

First, you'll need to define your html.Div as empty in order to pass children as table:

html.Div(id='table')

Then configure your callback to Output the table itself:

@app.callback(Output('table', 'children'), [Input('basic-interactions', 'clickData')])
def create_table(clickData):
    if clickData != 'null':
        table = dash_table.DataTable(columns=[{"name": i, "id": i} for i in df.columns],data=df['<filter df by clickData info>'].to_dict('records'))
    else:
        table = dash_table.DataTable(columns=[{"name": i, "id": i} for i in df.columns],data=df['<don't filter df>'].to_dict('records'))

    return table

I'd recommend usind selectData rather than clickData , this way the visual input (selection of bar(s)) is more intuitive to the user and it makes it easier to "de-select"

Related