Renaming object properties for multiple input/states during callbacks

So I have the following problem:
I have an app where I can upload my data as a csv file.
I want to make a graph which should be subdivided by a classifier column. I want the user to be able to pick what kind of graph he wants to plot from a selection and also which column does contain the classifier.

I have created a RadioItem object for picking the graph and a dropdown menu for selecting the classifier column and I would pass the chosen graph as the input and the chosen classifier as a state.

No the problem is, that the selected item from both, the RadioItem as well as the dropdown menu is called ‘value’. So I would get something like this:

def RadioItems():
    return dcc.RadioItems(
    options=[
        {'label': 'lineplot', 'value': 'lineplot'},
        {'label': 'None', 'value' : 'None'}

    ],
    value='None',
    id='graph_selector')
def classifier_choice(df):
    '''
    called when data is uploaded
    '''
    columns=df.columns
    classifieroptions= [{'label' :k, 'value' :k} for k in columns]
    return dcc.Dropdown(
            #label='Classifier Column',
            id='classifier_choice',
            options=classifieroptions,
            placeholder='select the classifier column')
app.layout = html.Div([
    
    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'
        },
        # Allow multiple files to be uploaded
        multiple=True
    ),
    html.Table(id='output-data-upload'),
    RadioItems(),
    
    dcc.Graph(id='migration_data'),
    #hidden divs for storing data
    html.Div(id='shared_data', style={'display':'none'})
])
graph_options={'None':print(), 'lineplot':GD.lineplot}
@app.callback(Output('migration_data', 'figure'),
              [Input('graph_selector', 'value')],
              [State('classifier_choice', 'value')])
                

def get_value(value, value):
    return graph_options[value](df, value, testmode=True)

Despite me getting the error:
“AttributeError: ‘Div’ object has no attribute ‘keys’”

this of course does not make any sense, since there is no way to differentiate between the two values.
Is there a way to rename the value attribute of a dropdown menu, or assign it’s value to another variable in a way of:

classifier=classifier_choice.value()

or something like that?

change def get_value(value, value) to def get_value(graph_value, classifier_value) - or whatever param names you like - the param names can be whatever you want…just make sure the order matches the order shown in @app.callback

So the actual naming does not matter at all, it is just about the order? Alright, thanks!
Unfortunately the Error message still persists.
Hoped it was caused by the naming problem.
Maybe relevant for that is, that the dropdown menu, which is defined in classifier_choice(df) is first called in the upload function, as it does require the data to get it’s options.

def parse_contents(contents, filename, date):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        global df
        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 html.Div([
            'There was an error processing this file.'
        ])
    #selection of graphs
    return html.Div([
        html.H5(filename),
        html.H6(datetime.datetime.fromtimestamp(date)),

        generate_table(df),
        classifier_choice(df),
        html.Hr(),  # horizontal line

        # For debugging, display the raw contents provided by the web browser
        html.Div('Raw Content'),
        html.Pre(contents[0:200] + '...', style={
            'whiteSpace': 'pre-wrap',
            'wordBreak': 'break-all'
        })
    ])

I think I’ve tracked the issue down and it seems to be caused by exactly the fact, that the dropdown menu does not exist when the app is initially started.
As I just explained, I want the dropdown menus to only be initialized after data is uploaded, because the choices depend on the data.
Is there a way around this, or do I need to initialize them with a sample dataframe in the beginning?

Set the following in order to allow you to define callbacks for elements not rendered when the page loads. See dcc.Tabs: Filling tabs with dynamic content. How to organize the callbacks? for more detail and possibly some helpful links.

app.config['suppress_callback_exceptions'] = True
1 Like