A nonexistent object was used in an `State` of

Hello, I am new to the forum and new to Dash. I love it a lot and plan to work mostly on it and join this community.

I recently learned to work with multipage apps, but sometimes I struggle with callbacks. I am using Dash to create engineering models and based on the selection, display different plots with different parameters.

A simple example is when I input a speed of 20 mph, and it plots the distance over time. Here is my callback. My app starts with the model set to value ‘A’, everything works perfectly. I am changing the value to ‘B’, and it works well again. But when I try to switch the shear option back to ‘A’, it gives me the following error:

A nonexistent object was used in an State of a Dash callback. The id of this object is gas_velocity and the property is value. The string ids in the current layout are: [_pages_location, _pages_content, _pages_store, _pages_dummy, pH-slider-norsok, shear-dropdown-norsok, display-options, corrosion-plot-norsok, liq_density, liq_viscosity, liq_velocity, calculate-button]

this is how i defined my input states in main layout:

                        dbc.CardHeader("Shear option", style={"margin-top": "10px"}),
                        dcc.Dropdown(id='shear-dropdown-norsok', multi = False, clearable = False, disabled = False,
                                options=[{'label': 'Neglect shear (S=19)',        'value': 'A'},
                                         {'label': "Norsok's original method",    'value': 'B'},
                                         {'label': 'Single-phase simplification', 'value': 'C'}, ], value='A',
                                style={"margin-bottom": "20px", 'color': 'black',}),
                        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
                        html.Div(id='display-options'),
                        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # NORSOK
                        dbc.Input(id="liq_velocity",  style={"display": "none"}),
                        dbc.Input(id="gas_velocity",  style={"display": "none"}),
                        dbc.Input(id="liq_density",   style={"display": "none"}),
                        dbc.Input(id="gas_spg",       style={"display": "none"}),
                        dbc.Input(id="liq_viscosity", style={"display": "none"}),
                        dbc.Input(id="gas_viscosity", style={"display": "none"}),
                        dbc.Button(id="calculate-button",   style={"display": "none"}),

first callback that updates dropdown and selections

@callback(
    Output('display-options', 'children'),
    [Input('shear-dropdown-norsok', 'value')]
)

and this is my second callback with plot display

@callback(Output('corrosion-plot-norsok', 'figure'),
        [Input('calculate-button',      'n_clicks')],
         [State('shear-dropdown-norsok', 'value'),
         State('pH-slider-norsok',      'value'),     
         State('liq_velocity',  'value'),
         State('gas_velocity',  'value'),
         State('liq_density',   'value'),
         State('gas_spg',       'value'),
         State('liq_viscosity', 'value'),
         State('gas_viscosity', 'value'),
])

def update_plot(n_clicks, shear_option, selected_pH, liq_vel, gas_vel, liq_dens, gas_spg, liq_myu, gas_myu):
    
    if shear_option == 'B':
        if n_clicks is None:
            raise PreventUpdate
        else:
            fig = get_plot_neglect(shear_option, selected_pH)

    if shear_option == 'norsok':
        if n_clicks is None:
            raise PreventUpdate
            # n_clicks = None
        else:
            fig = get_plot_default(shear_option, selected_pH, liq_vel, gas_vel, liq_dens, gas_spg, liq_myu, gas_myu)
            
            
    if shear_option == 'C':
        if n_clicks is None:
            raise PreventUpdate
        else:
            fig = get_plot_homogen(shear_option, selected_pH, liq_vel, liq_dens, liq_myu) # they will be set to be mixture values

    return fig

Welcome to the community, @MrEngineer.

Which version of dash are you using? Most likely it’s not related to this, just in case.

Other than that it’s hard to tell. Could you provide a minimal example which reproduces the error?

here is full simplified page:

app worsk fine and i can make adjustments, i can switch from ‘neglect’ shear option to ‘norsok’
but i am getting error if i want to switch back. please see small gif also attached:
ezgif-5-b2ec1478d5

dash.register_page(__name__, name="Norsok M506 model")

layout = html.Div([
    dbc.Row([
            dbc.Col([
                dbc.Card([ 
                    dbc.CardHeader("Model's Daldan menu", style={"margin-bottom": "0px", 'font-size': '18px'}),
                    dbc.CardBody([
                        dbc.CardHeader("pH slider", style={"margin-bottom": "7px", 'font-size': '16px'}),
                        dcc.Slider(id='pH-slider-norsok', min=3.5, max=6.5, step=0.5, value=3.5,
                            tooltip={"placement": "top", "always_visible": True, }),
                        dbc.CardHeader("Shear option", style={"margin-top": "10px"}),
                        dcc.Dropdown(id='shear-dropdown-norsok', multi = False, clearable = False, disabled = False,
                                options=[{'label': 'Neglect shear (S=19)',        'value': 'neglect'},
                                         {'label': "Norsok's original method",    'value': 'norsok'},], value='neglect',
                                style={"margin-bottom": "20px", 'color': 'black',}),
                        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
                        html.Div(id='display-options'),
                        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # NORSOK
                        dbc.Input(id="liq_velocity",  style={"display": "none"}),
                        dbc.Input(id="gas_velocity",  style={"display": "none"}),
                        dbc.Button(id="calculate-button",   style={"display": "none"}),
                        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # HOMOGENIOUS  
                        ])
                        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #  
                        ], outline=True, color="primary" )],          # Close card
                        width={'size': 3, 'order': 1, 'offset': 0}),  # Close column
            dbc.Col([
                dbc.Card([
                    dbc.CardHeader("Norsok M506 model", style={"margin-bottom": "0px", 'font-size': '18px'}),
                    dcc.Graph(id='corrosion-plot-norsok')], outline=True, color="primary")  ],  width={'size': 9, 'order': 2, 'offset': 0}, 
                    )
            ]) #Close 2nd row
])

@callback(
    Output('display-options', 'children'),
    [Input('shear-dropdown-norsok', 'value')]
)

# Callback for multi density option
def display_mixture_density_input(selected_option):
    if selected_option == 'neglect':
        return [dbc.Col(
                        dbc.Button("Calculate", id="calculate-button", color="primary", className="mr-1",
                                   style={"margin-top": "20px", "margin-left": "130px", "width": "160px"}),)]
    
    if selected_option == 'norsok':
        return [dbc.Row([
                    dbc.Col([
                        dbc.CardHeader("Oil velocity (m/s)", style={"margin-top": "10px"}),
                        dbc.Input(id="liq_velocity", value=0.1, placeholder="Default value: ~", type="number"),
                        ], width={'size': 6, 'order': 1, 'offset': 0}),
                    dbc.Col([
                        dbc.CardHeader("Gas velocity (m/s)",    style={"margin-top": "10px"}),
                        dbc.Input(id="gas_velocity", value=0.9, placeholder="Default value: ~", type="number"),
                        ], width={'size': 6, 'order': 2, 'offset': 0}),]),
                    dbc.Col(
                        dbc.Button("Calculate", id="calculate-button", color="primary", className="mr-1",
                                   style={"margin-top": "20px", "margin-left": "130px", "width": "160px"}),)]
    else:
        return []
    
@callback(Output('corrosion-plot-norsok', 'figure'),
        [Input('calculate-button',      'n_clicks')],
        [State('shear-dropdown-norsok', 'value'),
         State('pH-slider-norsok',      'value'),  
         State('liq_velocity',  'value'),
         State('gas_velocity',  'value'),
])

def update_plot(n_clicks, shear_option, selected_pH, liq_vel, gas_vel):
    if n_clicks is None:
        raise PreventUpdate

    if shear_option == 'neglect':
        fig = get_plot_neglect(shear_option, selected_pH)

    elif shear_option == 'norsok':
        fig = get_plot_default(shear_option, selected_pH, liq_vel, gas_vel, 850, 0.8, 1.53, 0.03)

    else:
        raise ValueError("Invalid shear option")
    return fig

I assume this to be the problem. What you are doing here is creating content dynamically. But instead of using pattern matching ID’s and callbacks, you have a fixed ID for the components.

Instead of creating the components on each call (on each change of selected_option) I would just toggle the visibility of the components via the style parameter.

Here an example:

Applied to your use case:

import dash
from dash import dcc, html, Input, Output


app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.Div(
            [
                dcc.Dropdown(
                    id='main_dropdown',
                    options=[1, 2],
                    multi=False,
                    value=1
                )
            ]
        ),
        html.Div(
            id='additional_content',
            children=[
                dcc.Dropdown(
                    id='additional_dropdown_1',
                    options=[3, 4],
                    multi=False,
                ),
                dcc.Dropdown(
                    id='additional_dropdown_2',
                    options=[5, 6],
                    multi=False,
                )
            ]
        ),
        html.Button(id='btn', children='dummy')
    ]
)


@app.callback(
    Output('additional_content', 'style'),
    Input('main_dropdown', 'value'),
)
def show_hide(selection):
    if selection == 1:
        return {}
    return {'display': 'none'}


if __name__ == '__main__':
    app.run(debug=True, port=8070)

this is nice example on how to try solve but won’t it complicate the look of my layout ?
i decided to use callback with display option to make the look and debug simpler

Not sure, how my suggestion is different in terms of your layout.

I just hide certain components and show them when necessary. Pretty much as you are trying to do with either returning components or an empty list.

As I said, I’m pretty sure the error is caused by this, at least from what I’ve seen from your app until now.

thank you very much for your time and help. i am working on adjustments now. and i think i have an issue in understanding how to interpret your method for three options case with updating plot

My bad, i am newbie and trying to get this right, i thought advanced, chained callbacks is way to got to keep everything simple.

Could you please suggest me on how to make case with tree options.
for example:

when main dropdown is = 1:
returns figure, and doesn’t display additional dropdowns , slider’s etc.

when dropdown value is = 2 :
i want to display additional content with updated plot

when dropdown value is = 3 :
i want to display additional content with updated plot

hey @MrEngineer.

If you tag me using @AIMPED I’ll see your posts earlier. Concerning the choices, are you referring to my example?

Here an extended example:

import dash
from dash import dcc, html, Input, Output
import numpy as np
import plotly.graph_objects as go


def create_figure():
    return go.Figure(
        go.Scatter(
            x=np.arange(10),
            y=np.random.randint(1, 10, size=10),
            mode='markers+lines'
        )
    )


app = dash.Dash(
    __name__,
    external_stylesheets=[
        "https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css",
    ]
)

app.layout = html.Div(
    className='row',
    children=[
        html.Div(
            className='col-3',
            children=[
                html.Div(
                    [
                        dcc.Dropdown(
                            id='main_dropdown',
                            options=[1, 2, 3],
                            multi=False,
                            value=1
                        )
                    ]
                ),
                html.Div(
                    id='additional_content',
                    children=[
                        dcc.Dropdown(
                            id='additional_dropdown_1',
                            options=[4, 5],
                            multi=False,
                        ),
                        dcc.Dropdown(
                            id='additional_dropdown_2',
                            options=[6, 7],
                            multi=False,
                        )
                    ]
                ),
                html.Button(id='btn', children='dummy')
            ]
        ),
        html.Div(
            className='col-8',
            children=[
                dcc.Graph(id='graph', figure=create_figure())
            ]
        )
    ]
)


@app.callback(
    Output('additional_content', 'style'),
    Output('graph', 'figure'),
    Input('main_dropdown', 'value'),
)
def show_hide(selection):
    show_optional_components = {'display': 'initial'}
    hide_optional_components = {'display': 'none'}
    default_config = {'display': 'none'}

    if selection == 1:
        return hide_optional_components, create_figure()

    elif selection == 2:
        return show_optional_components, create_figure()

    elif selection == 3:
        return show_optional_components, create_figure()

    else:
        return default_config, create_figure()


if __name__ == '__main__':
    app.run(debug=True, port=8070)

Your suggestion helped me to figure out how to solve my task.

Thank you very much

1 Like