Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 641
sparrow Avatar asked Mar 20 '19 20:03

sparrow


2 Answers

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

like image 181
n00b Avatar answered Oct 20 '22 20:10

n00b


You almost got it done just with minor modification in update_datatable it should work fine (not tested):

def update_datatable(n_clicks,csv_file):            
    if n_clicks:                            
        dfgb = df.groupby(['state']).sum()
        return html.Div([dash_table.DataTable(
                data=dfgb.to_dict('rows'),
                columns=[{'name': i, 'id': i} for i in dfgb.columns],
                style_header={'backgroundColor': "#FFD700",
                              'fontWeight': 'bold',
                              'textAlign': 'center',},
                style_table={'overflowX': 'scroll'},  
                style_cell={'minWidth': '180px', 'width': '180px',
                        'maxWidth': '180px','whiteSpace': 'normal'},                        
                         filtering=True,
                 row_selectable="multi",
                 n_fixed_rows=1),
               html.Hr()
        ])
like image 22
shivsn Avatar answered Oct 20 '22 20:10

shivsn