Search code examples
pythonpandasplotly-dash

Return a Pandas DataFrame as a data_table from a callback with Plotly Dash for Python


I would like to read a .csv file and return a groupby function as a callback to be displayed as a simple data table with "dash_table" library. @Lawliet's helpful answer shows how to do that with "dash_table_experiments" library. Here is where I’m stuck:

import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from dash.dependencies import Input, Output, State

df = pd.read_csv(
        'https://gist.githubusercontent.com/chriddyp/'
        'c78bf172206ce24f77d6363a2d754b59/raw/'
        'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
        'usa-agricultural-exports-2011.csv')

app = dash.Dash()
application = app.server

app.layout = html.Div([
    dash_table.DataTable(
        id = 'datatable',        
    ),

    html.Div([
        html.Button(id='submit-button',                
                children='Submit'
    )
    ]),    

])

@app.callback(Output('datatable','data'),
            [Input('submit-button','n_clicks')],
                [State('submit-button','n_clicks')])

def update_datatable(n_clicks,csv_file):            
    if n_clicks:                            
        dfgb = df.groupby(['state']).sum()
        return dfgb.to_dict('rows')

if __name__ == '__main__':
    application.run(debug=False, port=8080)

Solution

  • When you are trying to register the callback Output component as a DataTable, all the required / mandatory attributes for the DataTable component should be updated in the callback and returned. In your code, you are updating just DataTable.data and not DataTable.column, one easy way is to return the whole Datatable component which is prepopulated with all the required attribute values.

    Here is an example,

    import dash_html_components as html
    import dash_core_components as dcc
    import dash
    import dash_table
    import pandas as pd
    import dash_table_experiments as dt
    
    app = dash.Dash(__name__)
    
    #data to be loaded
    data = [['Alex',10],['Bob',12],['Clarke',13],['Alex',100]]
    df = pd.DataFrame(data,columns=['Name','Mark'])
    
    app.layout = html.Div([
        dt.DataTable(
                rows=df.to_dict('records'),
                columns=df.columns,
                row_selectable=True,
                filterable=True,
                sortable=True,
                selected_row_indices=list(df.index),  # all rows selected by default
                id='2'
         ),
        html.Button('Submit', id='button'),
        html.Div(id="div-1"),
    ])
    
    
    @app.callback(
        dash.dependencies.Output('div-1', 'children'),
        [dash.dependencies.Input('button', 'n_clicks')])
    def update_output(n_clicks):
    
        df_chart = df.groupby('Name').sum()
    
        return [
            dt.DataTable(
                rows=df_chart.to_dict('rows'),
                columns=df_chart.columns,
                row_selectable=True,
                filterable=True,
                sortable=True,
                selected_row_indices=list(df_chart.index),  # all rows selected by default
                id='3'
            )
        ]
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    
    

    Looks like dash-table-experiments is deprecated.

    Edit 1: Here is one way of how it can be achieved using dash_tables

    import pandas as pd
    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    import dash_table as dt
    from dash.dependencies import Input, Output, State
    
    df = pd.read_csv(
            'https://gist.githubusercontent.com/chriddyp/'
            'c78bf172206ce24f77d6363a2d754b59/raw/'
            'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
            'usa-agricultural-exports-2011.csv')
    
    app = dash.Dash()
    application = app.server
    
    app.layout = html.Div([
        dt.DataTable(
            id = 'dt1', 
            columns =  [{"name": i, "id": i,} for i in (df.columns)],
    
        ),
        html.Div([
            html.Button(id='submit-button',                
                    children='Submit'
            )
        ]),    
    
    ])
    
    @app.callback(Output('dt1','data'),
                [Input('submit-button','n_clicks')],
                    [State('submit-button','n_clicks')])
    
    def update_datatable(n_clicks,csv_file):            
        if n_clicks:                            
            dfgb = df.groupby(['state']).sum()
            data_1 = df.to_dict('rows')
            return data_1
    
    if __name__ == '__main__':
        application.run(debug=False, port=8080)
    

    Another way: return the whole DataTable

    import pandas as pd
    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    import dash_table as dt
    from dash.dependencies import Input, Output, State
    
    df = pd.read_csv(
            'https://gist.githubusercontent.com/chriddyp/'
            'c78bf172206ce24f77d6363a2d754b59/raw/'
            'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
            'usa-agricultural-exports-2011.csv')
    
    app = dash.Dash()
    application = app.server
    
    app.layout = html.Div([
        html.Div(id="table1"),
    
        html.Div([
            html.Button(id='submit-button',                
                    children='Submit'
        )
        ]),    
    
    ])
    
    @app.callback(Output('table1','children'),
                [Input('submit-button','n_clicks')],
                    [State('submit-button','n_clicks')])
    
    def update_datatable(n_clicks,csv_file):            
        if n_clicks:                            
            dfgb = df.groupby(['state']).sum()
            data = df.to_dict('rows')
            columns =  [{"name": i, "id": i,} for i in (df.columns)]
            return dt.DataTable(data=data, columns=columns)
    
    
    if __name__ == '__main__':
        application.run(debug=False, port=8080)
    
    
    

    I referred to this example: https://github.com/plotly/dash-table/blob/master/tests/cypress/dash/v_copy_paste.py#L33