How to update DataTable interactively with a callback function in dash?

Question:

I feel like this is a basic problem and I`ve looked through all relevant topics on SO but still can’t manage to update a simple table in dash with interactive input.

Basically I have a table that contains data and want to be able to change that data depending on manual user inputs. I feel like this should be possible with a simple @callback. However no matter what I do the table always remains the same.

In the following example I am trying to filter the data by a category depending on a Input checklist. But I am not looking for a solution where I can filter but rather actually alter the table’s data, like multiplying the price by a Input factor etc.

# import dash and standard packages
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd

# creating the base table
df = pd.DataFrame(columns=['car', 'category', 'price'], data=[[1, 'SUV', 27000], [2, 'Sports', 90000],[3, 'SUV', 47000]])

# launch the app
app = dash.Dash()
app.layout = html.Div(children=[
    dcc.Checklist(id='category-list',
                  options=[{'label':s ,'value':s} for s in df['category'].unique()],
                  value=[s for s in df['category'].unique()],
                  labelStyle={"display": "block"}),
    html.Div([dash.dash_table.DataTable(
                id='scorecard-table',
                data=df.to_dict('records'),
                columns=[{"name": i, "id": i} for i in df.columns],
                fixed_rows={'headers': True, 'data': 0},
                fixed_columns={'headers': True, 'data': 1},
                export_columns='visible',
                export_format='xlsx')
    ])], style={'border':'2px grey solid'})

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

# update the table
@app.callback(
    Output('scorecard-table', 'data'),
    Input('category-list', 'value'),
)
def update_output(value):
    global df # not sure if that's helpful
    return df[df['category'].isin(value)].to_dict('records')

But if I change the checkboxes, no matter what way, nothing happens to the DataTable it always stays the same

enter image description here

Asked By: Quastiat

||

Answers:

I found the problem in your code.

enter image description here

I have changed the order of the code and I have also set the debug mode which helps to debug your code.

Below is the code with few modifications and fully functional

# import dash and standard packages
import dash
from dash import html, dcc,  Input, Output
import pandas as pd

# creating the base table
df = pd.DataFrame(columns=['car', 'category', 'price'], data=[[1, 'SUV', 27000], [2, 'Sports', 90000],[3, 'SUV', 47000]])

# launch the app
app = dash.Dash()
app.layout = html.Div(children=[
    dcc.Checklist(id='category-list',
                  options=[{'label':s ,'value':s} for s in df['category'].unique()],
                  value=[s for s in df['category'].unique()],
                  labelStyle={"display": "block"}),
    html.Div([dash.dash_table.DataTable(
                id='scorecard-table',
                data=df.to_dict('records'),
                columns=[{"name": i, "id": i} for i in df.columns],
                fixed_rows={'headers': True, 'data': 0},
                fixed_columns={'headers': True, 'data': 1},
                export_columns='visible',
                export_format='xlsx')
    ])], style={'border':'2px grey solid'})


# update the table
@app.callback(
    Output('scorecard-table', 'data'),
    Input('category-list', 'value'),
)
def update_output(value):
    if value == []:
        return df.to_dict('records')
    return df[df['category'].isin(value)].to_dict('records')

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

I hope it can help you to better understand how to use Dash appropriatelly and feel free to ask me any question you have about the modifications.

Also, if this answers helps, don’t forget to upvote it and set it as the answer.

Best Regards,
Leonardo

Answered By: Leonardo Ferreira