✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

How to save and access multiple data frames from dcc.Store in plotly dash

All,

I am getting into plotly dash and have got some great guidance from the documentation and the stack overflow community. Really thankful for that. Ran into one question, which I am not sure is clear in the documentation, so it would be great if anybody from the community can offer some guidance on. Here is what I have so far:

# Import required libraries
import dash
import math
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, MATCH


# App Begins
app = dash.Dash(
    __name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Tool"
server = app.server

# Create global chart template
mapbox_access_token = "pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNrOWJqb2F4djBnMjEzbG50amg0dnJieG4ifQ.Zme1-Uzoi75IaFbieBDl3A"

layout = dict(
    autosize=True,
    automargin=True,
    margin=dict(l=30, r=30, b=20, t=40),
    hovermode="closest",
    plot_bgcolor="#F9F9F9",
    paper_bgcolor="#F9F9F9",
    legend=dict(font=dict(size=10), orientation="h"),
    title="Satellite Overview",
    mapbox=dict(
        accesstoken=mapbox_access_token,
        style="light",
        center=dict(lon=-78.05, lat=42.54),
        zoom=7,
    ),
)

# Create app layout
app.layout = html.Div(
    [
        dcc.Store(id="aggregate_data"),
        # empty Div to trigger javascript file for graph resizing
        html.Div(id="output-clientside"),
        html.Div(
            [
                html.Div(
                    [
                        html.Img(
                            src=app.get_asset_url("dash-logo.png"),
                            id="plotly-image",
                            style={
                                "height": "60px",
                                "width": "auto",
                                "margin-bottom": "25px",
                            },
                        )
                    ],
                    className="one-third column",
                ),
                html.Div(
                    [
                        html.Div(
                            [
                                html.H3(
                                    "Dash Tool",
                                    style={"margin-bottom": "0px"},
                                ),
                            ]
                        )
                    ],
                    className="one-half column",
                    id="title",
                ),
            ],
            id="header",
            className="row flex-display",
            style={"margin-bottom": "25px"},
        ),
        html.Div(
            [
                html.Div(
                    [
                        html.P("Quantity 1:", className="control_label"),
                        dcc.Input(
                           id="quantity_1",
                           type="number",
                           placeholder=33.
                        ),
                        html.P("Quantity 2:", className="control_label"),
                        dcc.Input(
                            id="quantity_2",
                            type="number",
                            placeholder=-115.
                        ),
                        html.P("Number of Drop Downs:", className="control_label"),
                        dcc.Slider(
                            id="drop_downs",
                            min=2,
                            max=10,
                            value=2,
                            step=1.0,
                            className="dcc_control",
                        ),
                        html.P("Load Inputs:", className="control_label"),
                        dcc.Checklist(
                            id='sources_flag',
                            options=[
                                {'label': 'Yes', 'value': 'Y'},
                            ],
                            value=['Y'],
                            labelStyle={'display': 'inline-block'}
                        ),
                        html.Div(id='source_dropdown_container', children=[]),
                        html.Div(id='source_dropdown_container_output'),
                        html.Div(id='source_file_container', children=[]),
                        html.Div(id='source_file_container_output'),
                    ],
                    className="pretty_container four columns",
                    id="cross-filter-options",
                ),
            ],
            className="row flex-display",
        ),
    ],
    id="mainContainer",
    style={"display": "flex", "flex-direction": "column"},
)


# Create callbacks
@app.callback(
    Output(component_id='source_dropdown_container_output', component_property='children'),
    [
        Input(component_id='drop_downs', component_property='value'),
        Input(component_id='sources_flag', component_property='value'),
    ]
)
def update_source_dropdowns(value, value_1):
    """Controls the number of drop-downs available to choose sources"""
    print("cb", value, value_1)
    if value_1 == ['Y']:
        children = []
        for i in range(0, value):
            new_dropdown = html.Div(
                dcc.Upload(
                    id={'index': f'''meteo_source_dropdown_{str(value_1)}''', 'type': 'dynamic-dropdown'},
                    children=html.Div([
                        (html.Button('Upload File')),
                    ])
                )
            )
            children.append(new_dropdown)
        print(children)
        print(type(children))
        return children


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

When the user clicks each file upload button and uploads a new file (most likely a csv), how can I store and then retrieve them on an as needed basis without losing their identity from a dcc.Store? What I mean is, if a dataset was uploaded with the first button click, while retrieving that data from the dcc.Store, I would want to know which click that data set is associated with. Thanks a lot in advance for any help.

Hi @UdayGuntupalli

You could use multiple dcc.Store() with each one having an id associated with the dataset.
Or if you only want one dcc.Store() the data can be a dictionary. ie

data={"button1": df1.to_dict("records"), "button2": df2.to_dict("records)}

@AnnMarieW ,

Thank you for your response. So, if I had a dynamic # of drop downs, I could do something like this:

    html.Div(id='dropdown_container', children=[]),
    html.Div(id='dropdown_container_output'),

    @app.callback(
    Output({'type': 'dynamic-output', 'index': MATCH}, 'children'),
    Input({'type': 'dynamic-dropdown', 'index': MATCH}, 'value'),
    State({'type': 'dynamic-dropdown', 'index': MATCH}, 'id'),
)

Is similar functionality supported for a dcc.Store ? If you wouldn’t mind, can you share an example.

Thanks

Sure - Here is an example of a dcc.Store associated with each button.


import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, MATCH, ALL

app = dash.Dash(__name__, suppress_callback_exceptions=True)

app.layout = html.Div(
    [
        html.Button("Add upload button", id="dynamic-add-button", n_clicks=0),
        html.Div(id="dynamic-button-container", children=[]),
    ]
)


@app.callback(
    Output("dynamic-button-container", "children"),
    Input("dynamic-add-button", "n_clicks"),
    State("dynamic-button-container", "children"),
)
def display_buttons(n_clicks, children):
    new_element = html.Div(
        [
            html.Button(
                f"button {n_clicks}",
                id={"type": "dynamic-button", "index": n_clicks},
                n_clicks=0,
            ),
            dcc.Store(id={"type": "dynamic-store", "index": n_clicks}),
            html.Div(id={"type": "dynamic-output", "index": n_clicks}),
        ]
    )
    children.append(new_element)
    return children


@app.callback(
    Output({"type": "dynamic-store", "index": MATCH}, "data"),
    Input({"type": "dynamic-button", "index": MATCH}, "n_clicks"),
    State({"type": "dynamic-button", "index": MATCH}, "id"),
)
def display_output(n, id):
    if n > 0:
        # do upload and get data for the  button matching the id
        # in this example the only data is this text string
        return f" data for button {id['index']}"
    return dash.no_update


@app.callback(
    Output({"type": "dynamic-output", "index": MATCH}, "children"),
    Input({"type": "dynamic-store", "index": MATCH}, "data"),
)
def display_output(data):
    # This displays the data from the
    # dcc.Store associated with the button
    return data


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

@AnnMarieW.
Thank you. Here is my app. I still don’t really understand the piece where data is being passed to the data store and how to retrieve it for later use. Appreciate your patience and help in clarifying these questions. So, I have a total of 3 call backs:

  1. update_source_dropdowns - dynamic controller for dropdowns
  2. update_source_file_containers - dynamic controller for file upload (dcc.upload and dcc.store)
  3. save_data_to_store - saves data dynamically to different store objects

Here is the high-level overview:

  • User gets to pick how many dropdowns exist handled by 1 and a checklist
  • Within the available dropdowns, the users choice determines if there will be a file upload or no
  • Lastly, whether a file is uploaded or not, I want to store the data based on the user selection to a dcc.Store

I am currently not seeing any data being printed out in the third call back i.e. save_data_to_store when I upload files. Could you help me understand what I am doing wrong ?

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


# Declare Constants
DROPDOWN_LIST = ['GOOG', 'FB', 'AAPL', 'AMZN', 'BABA']
PREFERRED_LIST = ['AAPL', 'AMZN']


# Helper Functions
def parse_data(contents, filename) -> pd.DataFrame:
    content_type, content_string = contents.split(",")

    decoded = base64.b64decode(content_string)
    try:
        if "csv" in filename:
            # Assume that the user uploaded a CSV or TXT 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))
        elif "txt" or "tsv" in filename:
            # Assume that the user upl, delimiter = r'\s+'oaded an excel file
            df = pd.read_csv(io.StringIO(decoded.decode("utf-8")), delimiter=r"\s+")
    except Exception as e:
        print(e)
        return html.Div(["There was an error processing this file."])

    return df


# App Layout
app = dash.Dash(
    __name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Dash Tool"
server = app.server

# Create global chart template

layout = dict(
    autosize=True,
    automargin=True,
    margin=dict(l=30, r=30, b=20, t=40),
    hovermode="closest",
    plot_bgcolor="#F9F9F9",
    paper_bgcolor="#F9F9F9",
    legend=dict(font=dict(size=10), orientation="h"),
    title="Satellite Overview",
    mapbox=dict(
        accesstoken='pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNrOWJqb2F4djBnMjEzbG50amg0dnJieG4ifQ.Zme1-Uzoi75IaFbieBDl3A',
        style="light",
        center=dict(lon=-78.05, lat=42.54),
        zoom=7,
    ),
)

app.layout = html.Div(
    [
        dcc.Store(id="tmy_aggregate_data", children=[]),
        # empty Div to trigger javascript file for graph resizing
        html.Div(id="output-clientside"),
        html.Div(
            [
                html.Div(
                    [
                        html.Img(
                            src=app.get_asset_url("dash-logo.png"),
                            id="plotly-image",
                            style={
                                "height": "60px",
                                "width": "auto",
                                "margin-bottom": "25px",
                            },
                        )
                    ],
                    className="one-third column",
                ),
                html.Div(
                    [
                        html.Div(
                            [
                                html.H3(
                                    "Dash Tool",
                                    style={"margin-bottom": "0px"},
                                ),
                            ]
                        )
                    ],
                    className="one-half column",
                    id="title",
                ),
            ],
            id="header",
            className="row flex-display",
            style={"margin-bottom": "25px"},
        ),
        html.Div(
            [
                html.Div(
                    [
                        html.P("Quantity 1:", className="control_label"),
                        dcc.Input(
                            id="quantity_1",
                            type="number",
                            placeholder=33.0
                        ),
                        html.P("Quantity 2:", className="control_label"),
                        dcc.Input(
                            id="quantity_2",
                            type="number",
                            placeholder=-115.0
                        ),
                        html.P("Number of Dynamic Objects:", className="control_label"),
                        dcc.Slider(
                            id="dynamic_objects",
                            min=2.,
                            max=10.,
                            value=2.,
                            step=1.0,
                            marks={
                                2: '2',
                                3: '3',
                                4: '4',
                                5: '5',
                                6: '6',
                                7: '7',
                                8: '8',
                                9: '9',
                                10: '10'
                            },
                            className="dcc_control",
                        ),
                        html.P("Load Dynamic Objects:", className="control_label"),
                        dcc.Checklist(
                            id='load_flag',
                            options=[
                                {'label': 'Yes', 'value': 'Y'},
                            ],
                            value=['Y'],
                            labelStyle={'display': 'inline-block'}
                        ),
                        html.Div(id='dropdown_container', children=[]),
                        html.Div(id='dropdown_container_output'),
                        html.Div(id='file_container', children=[]),
                        html.Div(id='file_container_output'),
                    ],
                    className="pretty_container four columns",
                    id="cross-filter-options",
                ),
                html.Div(
                    [
                        html.Div(
                            [dcc.Graph(id="count_graph")],
                            id="countGraphContainer",
                            className="pretty_container",
                        ),
                    ],
                    id="right-column",
                    className="eight columns",
                ),
            ],
            className="row flex-display",
        ),
        html.Div(
            [
                html.Div(
                    [dcc.Graph(id="main_graph")],
                    className="pretty_container seven columns",
                ),
                html.Div(
                    [dcc.Graph(id="individual_graph")],
                    className="pretty_container five columns",
                ),
            ],
            className="row flex-display",
        ),
        html.Div(
            [
                html.Div(
                    [dcc.Graph(id="pie_graph")],
                    className="pretty_container seven columns",
                ),
                html.Div(
                    [dcc.Graph(id="aggregate_graph")],
                    className="pretty_container five columns",
                ),
            ],
            className="row flex-display",
        ),
    ],
    id="mainContainer",
    style={"display": "flex", "flex-direction": "column"},
)


# Define callbacks
@app.callback(
    Output(component_id='dropdown_container_output', component_property='children'),
    [
        Input(component_id='dynamic_objects', component_property='value'),
        Input(component_id='load_flag', component_property='value'),
    ]
)
def update_source_dropdowns(n_dynamic_objects: int, flag: list) -> list:
    """Controls the number of drop-downs available"""
    if flag == ['Y']:
        children = []
        for i in range(0, n_dynamic_objects):
            new_dropdown = html.Div([
                dcc.Dropdown(
                    id={'index': f'''source_dropdown_{str(i)}''', 'type': 'dynamic-dropdown'},
                    options=[{"label": v, "value": v} for v in DROPDOWN_LIST],
                ),
                html.Div(
                    id={
                        'type': 'dynamic-output',
                        'index': f'''source_dropdown_{str(i)}'''
                    }
                )
            ])
            children.append(new_dropdown)
        return children


@app.callback(
    Output({'type': 'dynamic-output', 'index': MATCH}, 'children'),
    Input({'type': 'dynamic-dropdown', 'index': MATCH}, 'value'),
    State({'type': 'dynamic-dropdown', 'index': MATCH}, 'id'),
)
def update_source_file_containers(value: int, dropdown_id: dict) -> list:
    """Controls the source file containers for user to upload data"""
    if value not in PREFERRED_LIST:
        new_element = html.Div([
            dcc.Upload([
                html.Button(
                    'Upload File',
                    id={'type': 'dynamic-button', 'index': f'''data_upload_button_{dropdown_id['index']}'''}
                       ),
                dcc.Store(id={'type': 'dynamic-store', 'index': f'''data_upload_button_{dropdown_id['index']}'''})
            ])
        ])
        return new_element


@app.callback(
    Output({"type": "dynamic-store", "index": MATCH}, "data"),
    [
        Input({"type": "dynamic-button", "index": MATCH}, "contents"),
        Input({"type": "dynamic-button", "index": MATCH}, "filename")
    ],
    State({"type": "dynamic-button", "index": MATCH}, "id"),
)
def save_data_to_store(contents, file_name, upload_id):

    if contents:
        contents = contents[0]
        filename = file_name[0]
        df = parse_data(contents, filename)
        data = df.to_dict('records')
        print(data)
        return data


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

Hi @UdayGuntupalli

I’m happy to help with this, but you can make things easier by simplifying your app. Try creating a minimal example that isolates the feature you are working on. This makes debugging so much easier. Check out this post for some guidelines on how to do this: How to Get your Questions Answered on the Plotly Forum

Looking at your code, "contents" and "filename" are not properties of the html.Button. There may be other things that cause the issue as well, but it’s a lot of code to review.

@app.callback(
    Output({"type": "dynamic-store", "index": MATCH}, "data"),
    [
        Input({"type": "dynamic-button", "index": MATCH}, "contents"),
        Input({"type": "dynamic-button", "index": MATCH}, "filename")

@AnnMarieW,

Thank you for your response. I appreciate and understand what you are referring to. Here is a trimmed down version of the app. Here are the primary goals I am struggling with:

  • When user uploads a file(to further simplify, lets say always a csv file) to dcc.upload coupled with a button, how can we load it into a dcc.Store without losing which drop-down selection that data is linked to. For e.g. if I have trading data for GOOG, APPL etc., when I select the ‘GOOGL’ in the drop-down and I upload the data for ‘GOOGL’, I want to know that when I access the data in my dcc.Store

  • How can I retrieve the data from the dcc.Store to prepare different plots using all of these data sets together.

Let me know if I can clarify any further

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


# Declare Constants
DROPDOWN_LIST = ['GOOG', 'FB', 'AAPL', 'AMZN', 'BABA']


# App Layout
app = dash.Dash(
    __name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Dash Tool"
server = app.server

app.layout = html.Div(
    [
        # empty Div to trigger javascript file for graph resizing
        html.Div(id="output-clientside"),
        html.Div(
            [
                html.Div(
                    [
                        html.Img(
                            src=app.get_asset_url("dash-logo.png"),
                            id="plotly-image",
                            style={
                                "height": "60px",
                                "width": "auto",
                                "margin-bottom": "25px",
                            },
                        )
                    ],
                    className="one-third column",
                ),
                html.Div(
                    [
                        html.Div(
                            [
                                html.H3(
                                    "Dash Tool",
                                    style={"margin-bottom": "0px"},
                                ),
                            ]
                        )
                    ],
                    className="one-half column",
                    id="title",
                ),
            ],
            id="header",
            className="row flex-display",
            style={"margin-bottom": "25px"},
        ),
        html.Div(
            [
                html.Div(
                    [
                        html.P("Number of Dynamic Objects:", className="control_label"),
                        dcc.Slider(
                            id="dynamic_objects",
                            min=2.,
                            max=10.,
                            value=2.,
                            step=1.0,
                            marks={
                                2: '2',
                                3: '3',
                                4: '4',
                                5: '5',
                                6: '6',
                                7: '7',
                                8: '8',
                                9: '9',
                                10: '10'
                            },
                            className="dcc_control",
                        ),
                        html.P("Load Dynamic Objects:", className="control_label"),
                        dcc.Checklist(
                            id='load_flag',
                            options=[
                                {'label': 'Yes', 'value': 'Y'},
                            ],
                            value=['Y'],
                            labelStyle={'display': 'inline-block'}
                        ),
                        html.Div(id='dropdown_container', children=[]),
                        html.Div(id='dropdown_container_output'),
                        html.Div(id='file_container', children=[]),
                        html.Div(id='file_container_output'),
                    ],
                    className="pretty_container four columns",
                    id="cross-filter-options",
                ),
                html.Div(
                    [
                        html.Div(
                            [dcc.Graph(id="count_graph")],
                            id="countGraphContainer",
                            className="pretty_container",
                        ),
                    ],
                    id="right-column",
                    className="eight columns",
                ),
            ],
            className="row flex-display",
        ),
    ],
    id="mainContainer",
    style={"display": "flex", "flex-direction": "column"},
)


# Define callbacks
@app.callback(
    Output(component_id='dropdown_container_output', component_property='children'),
    [
        Input(component_id='dynamic_objects', component_property='value'),
        Input(component_id='load_flag', component_property='value'),
    ]
)
def update_source_dropdowns(n_dynamic_objects: int, flag: list) -> list:
    """Controls the number of drop-downs available"""
    if flag == ['Y']:
        children = []
        for i in range(0, n_dynamic_objects):
            new_dropdown = html.Div([
                dcc.Dropdown(
                    id={'index': f'''source_dropdown_{str(i)}''', 'type': 'dynamic-dropdown'},
                    options=[{"label": v, "value": v} for v in DROPDOWN_LIST],
                ),
                html.Div(
                    id={
                        'type': 'dynamic-output',
                        'index': f'''source_dropdown_{str(i)}'''
                    }
                )
            ])
            children.append(new_dropdown)
        return children


@app.callback(
    Output({'type': 'dynamic-output', 'index': MATCH}, 'children'),
    Input({'type': 'dynamic-dropdown', 'index': MATCH}, 'value'),
    State({'type': 'dynamic-dropdown', 'index': MATCH}, 'id'),
)
def update_source_file_containers(value: int, dropdown_id: dict) -> list:
    """Controls the source file containers for user to upload data"""

    new_element = html.Div([
        dcc.Upload([
            html.Button(
                'Upload File',
                id={'type': 'dynamic-button', 'index': f'''data_upload_button_{dropdown_id['index']}'''}
            ),
            dcc.Store(id={'type': 'dynamic-store', 'index': f'''data_upload_button_{dropdown_id['index']}'''})
        ])
    ])
    return new_element


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


Hi @UdayGuntupalli

Here is another example to get you started:


import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, MATCH, ALL
import pandas as pd
import base64
import io


# Declare Constants
DROPDOWN_LIST = ["GOOG", "FB", "AAPL", "AMZN", "BABA"]


# App Layout
app = dash.Dash(
    __name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Dash Tool"
server = app.server


def parse_data(contents, filename) -> pd.DataFrame:
    content_type, content_string = contents.split(",")

    decoded = base64.b64decode(content_string)
    try:
        if "csv" in filename:
            # Assume that the user uploaded a CSV or TXT 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))
        elif "txt" or "tsv" in filename:
            # Assume that the user upl, delimiter = r'\s+'oaded an excel file
            df = pd.read_csv(io.StringIO(decoded.decode("utf-8")), delimiter=r"\s+")
    except Exception as e:
        print(e)
        return html.Div(["There was an error processing this file."])

    return df


app.layout = html.Div(
    [
        # empty Div to trigger javascript file for graph resizing
        html.Div(id="output-clientside"),
        html.Div(
            [
                html.Div(
                    [
                        html.Img(
                            src=app.get_asset_url("dash-logo.png"),
                            id="plotly-image",
                            style={
                                "height": "60px",
                                "width": "auto",
                                "margin-bottom": "25px",
                            },
                        )
                    ],
                    className="one-third column",
                ),
                html.Div(
                    [
                        html.Div(
                            [html.H3("Dash Tool", style={"margin-bottom": "0px"},),]
                        )
                    ],
                    className="one-half column",
                    id="title",
                ),
            ],
            id="header",
            className="row flex-display",
            style={"margin-bottom": "25px"},
        ),
        html.Div(
            [
                html.Div(
                    [
                        html.P("Number of Dynamic Objects:", className="control_label"),
                        dcc.Slider(
                            id="dynamic_objects",
                            min=2.0,
                            max=10.0,
                            value=2.0,
                            step=1.0,
                            marks={
                                2: "2",
                                3: "3",
                                4: "4",
                                5: "5",
                                6: "6",
                                7: "7",
                                8: "8",
                                9: "9",
                                10: "10",
                            },
                            className="dcc_control",
                        ),
                        html.P("Load Dynamic Objects:", className="control_label"),
                        dcc.Checklist(
                            id="load_flag",
                            options=[{"label": "Yes", "value": "Y"},],
                            value=["Y"],
                            labelStyle={"display": "inline-block"},
                        ),
                        html.Div(id="dropdown_container", children=[]),
                        html.Div(id="dropdown_container_output"),
                        html.Div(id="file_container", children=[]),
                        html.Div(id="file_container_output"),
                    ],
                    className="pretty_container four columns",
                    id="cross-filter-options",
                ),
                html.Div(
                    [
                        html.Div(
                            [dcc.Graph(id="count_graph")],
                            id="countGraphContainer",
                            className="pretty_container",
                        ),
                    ],
                    id="right-column",
                    className="eight columns",
                ),
            ],
            className="row flex-display",
        ),
    ],
    id="mainContainer",
    style={"display": "flex", "flex-direction": "column"},
)


# Define callbacks
@app.callback(
    Output(component_id="dropdown_container_output", component_property="children"),
    [
        Input(component_id="dynamic_objects", component_property="value"),
        Input(component_id="load_flag", component_property="value"),
    ],
)
def update_source_dropdowns(n_dynamic_objects: int, flag: list) -> list:
    """Controls the number of drop-downs available"""
    if flag == ["Y"]:
        children = []
        for i in range(0, n_dynamic_objects):
            new_dropdown = html.Div(
                [
                    dcc.Dropdown(
                        id={
                            "index": f"""source_dropdown_{str(i)}""",
                            "type": "dynamic-dropdown",
                        },
                        options=[{"label": v, "value": v} for v in DROPDOWN_LIST],
                    ),
                    dcc.Store(
                        id={
                            "type": "dynamic-store",
                            "index": f"""source_dropdown_{str(i)}""",
                        }
                    ),
                    dcc.Upload(
                        id={
                            "type": "dynamic-button",
                            "index": f"""source_dropdown_{str(i)}""",
                        },
                        children=html.Button("Upload File"),
                    ),
                ]
            )
            children.append(new_dropdown)
        return children


@app.callback(
    Output({"type": "dynamic-store", "index": MATCH}, "data"),
    [
        Input({"type": "dynamic-button", "index": MATCH}, "contents"),
        Input({"type": "dynamic-button", "index": MATCH}, "filename"),
    ],
    State({"type": "dynamic-dropdown", "index": MATCH}, "value"),
)
def save_data_to_store(contents, filename, dd_value):
    print(filename)
    if contents:
        df = parse_data(contents, filename)
        data = {"dropdown": dd_value, "df": df.to_dict("records")}
        return data


@app.callback(
    Output("file_container_output", "children"),
    Input({"type": "dynamic-store", "index": ALL}, "data"),
)
def display_output(data):
    output = ""
    if data is []:
        return dash.no_update
    for d in data:

        dropdown = "" if d is None else d["dropdown"]
        uploaded_df = "" if d is None else d["df"]

        print(dropdown)
        print(uploaded_df)

        # create whatever you want to display with the data for each
        output = html.Div("Output data")

    return output


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

1 Like