Dash DataTable dropdown options determined in callback

I’m working on a dash app in which I need to include row dropdowns in a DataTable where the content of the dropdown is specific to the row. However, because I’m dealing with a large amount of data, I’m only identifying the contents of the DataTable (and the dropdown options) after a few selections have been made by the user.
Issue: I can’t get the dropdowns to populate with options unless the options are defined before the app.layout section.

Below is a simplified example with the issue. The data describes products offered to different customers where each customer has certain colors they can choose for each product (colors offered are not always the same for each product / customer). For simplicity of the example, the data used does not change based on the A/B/C dropdown, but in my real use case the available data does change.

I’ve only successfully populated the dropdowns when the data manipulation is done before the app is initiated. Is it possible to have the dropdown options defined dynamically while the app is operating?

import pandas as pd
from dash import Dash, html, dash_table, callback, Output, Input, dcc

# Create a dictionary to map row_id to the list of colors for each row
rowid_colors = {}

app = Dash(__name__)

app.layout = html.Div(
    children = [
        dcc.Dropdown(
            id = 'election_dropdown',
            options=['A','B','C'],
        ),
        dash_table.DataTable(
            id="dropdown_per_row",
            columns=[
                {"id": "customer_id", "name": "Customer ID"},
                {"id": "product_id", "name": "Product ID"},
                {"id": "row_id", "name": "Row ID"},
                {"id": "product_colors", "name": "Product Colors", "presentation": "dropdown"}
            ],
            hidden_columns=["row_id"],
            editable=True,            
            dropdown_conditional=[
                {
                    "if": {
                        "column_id": "product_colors",
                        "filter_query": "{{row_id}} eq {}".format(rowid),
                    },
                    "options": [{"label": i, "value": i} for i in colors],
                }
                for rowid, colors in rowid_colors.items()
            ],
        ),
        html.Div(id="dropdown_per_row_container"),
    ]
) 

@callback(   
    Output("dropdown_per_row", "data")
    , Input("election_dropdown", "value")
)
def define_dropdown(election_value):
    df = pd.DataFrame()
    df['customer_id'] = [305, 305, 305, 305, 305, 402, 402]
    df['product_id'] = [101, 101, 101, 109, 109, 101, 101]
    df['cust_prod_colors'] = ['Blue', 'Green', 'Yellow', 'Blue', 'Orange', 'Blue', 'Red']

    agg_colors_df = df.groupby(['customer_id', 'product_id'])['cust_prod_colors'].apply(list).reset_index()
    # Add a row_id column to the aggregated positions DataFrame using the index as a string
    agg_colors_df['row_id'] = agg_colors_df.index.astype(str)
    
    # Define the colors for each row's dropdown
    global rowid_colors
    rowid_colors.clear() 
    for i in range(len(agg_colors_df)):
        # for the record with row_id = i, get the position list
        pos_list = agg_colors_df.at[i, 'cust_prod_colors']
        row_id = agg_colors_df.at[i, 'row_id']
        rowid_colors[row_id] = pos_list

    # Remove the cust_prod_colors from agg_colors_df
    agg_colors_df = agg_colors_df.drop(columns=['cust_prod_colors'])

    return agg_colors_df.to_dict('records')

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

Hey @jenren26 welcome to the forums.

I actually have no solution for your problem. I just read “big data” and wanted to encourage you to take a look at ag-grid. It’s way more capable than dash tables.

Thanks for the suggestion - I’ll check it out!