Dash(Python) - can't display dataframe in datatable after calculations

与世无争的帅哥 提交于 2019-12-13 18:03:14

问题


I'm reading a text file(.csv mostly) from dash_core_components.Upload. I had no problems printing the file that i've taken. But, problems arise when i do some calculations and try printing that.
and the error is:

dash.exceptions.InvalidCallbackReturnValue: 
The callback for property `children`
of component `dataframe_output` returned a value
which is not JSON serializable.

In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.

Here's what I've done and tried:

# importing required libraries
import dash
import dash_table
import pandas as pd
import dash_core_components as dash_core
import dash_html_components as dash_html
from dash.dependencies import Input, Output

# starting app layout
app.layout = dash_html.Div([
    # upload button to take csv files
    dash_core.Upload(id='upload_data',
               children=dash_html.Div(['Drag and Drop or ',
                                  dash_html.A('Select Files')
                                  ]),
               style={'width': '100%',
                      'height': '60px',
                      'lineHeight': '60px',
                      'borderWidth': '1px',
                      'borderStyle': 'dashed',
                      'borderRadius': '5px',
                      'textAlign': 'center',
                      'margin': '10px'
                      },
               multiple=False),
    # a 'Div' to return table output to
    dash_html.Div(id='dataframe_output'),
])

# callback to take and output the uploaded file
@app.callback(Output('dataframe_output', 'children'),
              [Input('upload_data', 'contents'),
               Input('upload_data', 'filename')])
def update_output(contents, filename):
    if contents is not None:
        # reading the file
        input_data = pd.read_csv(filename)
        # creating a dataframe that has info about "data types", "count of nulls", "count of unique values"
        info_dataframe = pd.concat([pd.DataFrame(input_data.dtypes,       columns=["data_types"]),
                                    pd.DataFrame(input_data.isna().sum(), columns=["count of blanks"]),
                                    pd.DataFrame(input_data.nunique(),    columns=["count of unique values"])
                                           ],
                                          axis=1, sort=True)
        # adding index as a row
        info_dataframe.reset_index(level=0, inplace=True)
        # returning it to 'Div'
        return dash_html.Div([
            dash_table.DataTable(
                id='table',
                columns=[{"name": i, "id": i} for i in info_dataframe .columns],
                # columns=[{"name": i, "id": i} for i in input_data.columns], # this works fine
                data=info_dataframe .to_dict("rows"),
                # data=input_data.to_dict("rows"), # this works fine
                style_cell={'width': '50px',
                            'height': '30px',
                            'textAlign': 'left'}
                        )
        ])

# running the app now
if __name__ == '__main__':
    app.run_server(debug=True, port=8050)

(I also want to save this to a text file after displaying on browser. how do i do that too).


回答1:


This always worked for me - try using a hidden Div for storing json serialized dataframe

import dash
import dash_table
import pandas as pd
import dash_core_components as dash_core
import dash_html_components as dash_html
from dash.dependencies import Input, Output
import base64
import io

# starting app layout
app.layout = dash_html.Div([
    # upload button to take csv files
    dash_core.Upload(id='upload_data',
               children=dash_html.Div(['Drag and Drop or ',
                                  dash_html.A('Select Files')
                                  ]),
               style={'width': '100%',
                      'height': '60px',
                      'lineHeight': '60px',
                      'borderWidth': '1px',
                      'borderStyle': 'dashed',
                      'borderRadius': '5px',
                      'textAlign': 'center',
                      'margin': '10px'
                      },
               multiple=False),
    # Div to store json serialized dataframe
    dash_html.Div(id='json_df_store', style={'display':'none'}),
    # a 'Div' to return table output to
    dash_html.Div(id='dataframe_output'),
])

@app.callback(Output('json_df_store', 'children'),
              [Input('upload_data', 'contents'),
               Input('upload_data', 'filename')])
def load_df(content, filename):
    if content:
        # Modify the read_csv callback part
        content_type, content_string = contents.split(',')
        decoded = base64.b64decode(content_string)

        try:
            if 'csv' in filename:

                # Assume that the user uploaded a CSV file
                input_data  = pd.read_csv(io.StringIO(decoded.decode('utf-8')))

                info_dataframe = pd.DataFrame(data={
                                              "data_types": input_data.dtypes,
                                              "blanks_count": input_data.isna().sum(),
                                              "unique_count": input_data.nunique()
                                                   })

                # adding index as a row
                info_dataframe.reset_index(level=0, inplace=True)
                info_dataframe.rename(columns={'index':'col_name'}, inplace=True)

                info_dataframe['data_types'] = info_dataframe['data_types'].astype(str)

                return info_dataframe.to_json(date_format='iso', orient='split')

        except Exception as e:
            #print(e)
            return pd.DataFrame(data={'Error': e}, index=[0]).to_json(date_format='iso', orient='split')



# callback to take and output the uploaded file
@app.callback(Output('dataframe_output', 'children'),
              [Input('json_df_store', 'children')])
def update_output(json_df):

   info_dataframe = pd.read_json(json_df, orient='split')

   data = info_dataframe .to_dict("rows")
   cols = [{"name": i, "id": i} for i in info_dataframe .columns]

   child = dash_html.Div([
                dash_table.DataTable(
                                id='table',
                                data=data, 
                                columns=cols,
                                style_cell={'width': '50px',
                                            'height': '30px',
                                            'textAlign': 'left'}
                                      )
                           ])
    return child

# running the app now
if __name__ == '__main__':
    app.run_server(debug=True, port=8050)



来源:https://stackoverflow.com/questions/58990502/dashpython-cant-display-dataframe-in-datatable-after-calculations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!