Black Lives Matter. Please consider donating to Black Girls Code today.

Upload content to hidden div

I am trying to take file contents using the upload content component. Instead of putting directly into the table as I’ve seen in some dash recipes, I want to store the data frame into a hidden div so it can be passed around to multiple callbacks (table rows, dropdown options, and graph figure). I’ve tried using the to_json method as described in the user guide but the issue is that this data frame is not globally defined at runtime, it is dependent upon the upload file contents. Below is my code to see what i’ve tried. Any help would be great!

##############################################################
#Imports

import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_table_experiments as dtable
from dash.dependencies import Input, Output, State

import plotly 
import plotly.graph_objs as go

import pandas as pd
import numpy as np

import json
import datetime
import operator
import os

import base64
import io
##############################################################
#Define app
app = dash.Dash()

app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True

##############################################################
#App layout
app.layout = html.Div([
################################
html.Div(id='temp_value', style={'display': 'none'}),
html.H5("Upload file"),
dcc.Upload(
    id = 'upload_data',
    children = html.Div([
        'Drag and Drop or ',
        html.A('Select Files')
    ]),
    style = {
            'width': '100%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px'
    },
    multiple = False),
#################################
html.Br(),
html.Div(dtable.DataTable(rows = [{}], id = 'table', row_selectable=True, filterable = True, sortable = True,
                          editable = False, selected_row_indices = [])),
#################################
html.Div([
    html.H5("X Dropdown"),
    dcc.Dropdown(
        id = 'x_dropdown',
        options = [],
        value = ''
    )
]),
html.Div([
    html.H5("Y Dropdown"),
    dcc.Dropdown(
        id = 'y_dropdown',
        options = [],
        value = ''
    )
]),
html.Div(
    dcc.Graph(
        id = 'graph'
    )
)
])
    ##############################################################
    #Functions
def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))

    except Exception as e:
        print(e)
        return None

    return df
##############################################################
#Callbacks

@app.callback(Output('temp_value', 'children'),
              [Input('upload_data', 'contents'),
               Input('upload_data', 'filename')])
def update_output(contents, filename):
    if contents is not None:
        df = parse_contents(contents, filename)
        return df.to_json(date_format = 'iso', orient = 'split')
    else:
        return [{}]

@app.callback(Output('table', 'rows'),
              [Input('temp_value', 'children')])
def update_table(temp_df):
    temp_df = pd.read_json(temp_df, orient = 'split')

    if temp_df is not None:
        return temp_df.to_dict('records')
    else:
        return [{}]



@app.callback(Output('x_dropdown', 'options'),
              [Input('temp_value', 'children')])
def update_x_dropdown(temp_df):
    temp_df = pd.read_json(temp_df, orient = 'split')
    return [{'label': i, 'value': i} for i in temp_df.columns]

@app.callback(Output('y_dropdown', 'options'),
              [Input('temp_value', 'children')])
def update_y_dropdown(temp_df):
    temp_df = pd.read_json(temp_df, orient = 'split')
    return [{'label': j, 'value': j} for j in temp_df.columns]

@app.callback(
    Output('graph', 'figure'),
    [Input('x_dropdown', 'value'),
     Input('y_dropdown', 'value'),
     Input('temp_value', 'children')])
def update_graph(xaxis_column_name, yaxis_column_name, temp_df):
    temp_df = pd.read_json(temp_df, orient = 'split')
    figure = {
        'data': [
            go.Scatter(
                x = temp_df[xaxis_column_name],
                y = temp_df[yaxis_column_name],
                mode = 'markers'
            )
        ],
        'layout': go.Layout(
            xaxis = {'title': xaxis_column_name},
            yaxis = {'title': yaxis_column_name},
            hovermode = 'closest'
        )
    }
    return figure

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

Hello kcp55555,

Did you ever find a solution? I am currently searching for the same functionality.

Also looking for something similar if you have code that you got working.

Have you looked into the dcc.Store component for this? It should be able to handle shared data between callbacks.

I have not but I think this will answer the mail. Will follow up either way for others’ awareness. Thank you!