Duplicate callback outputs when restarting the dash app

Hi,

In my dash app, when I run it the first time, everything works well. But when I stop it and run t again, I get the error:

Duplicate callback outputs
In the callback for output(s):
plot-explain.children
Output 0 (plot-explain.children) is already in use.
Any given output can only have one callback that sets it.
To resolve this situation, try combining these into
one callback function, distinguishing the trigger
by using dash.callback_context if necessary.

In the callback for output(s):
plot.figure
Output 0 (plot.figure) is already in use.
Any given output can only have one callback that sets it.
To resolve this situation, try combining these into
one callback function, distinguishing the trigger
by using dash.callback_context if necessary.

I have to close the python sheet and open it again for it to run well, but again for the first time only. What could be the problem?

Here is the dash code (not all figure plots in the first callback are included):

app.layout = dbc.Container([
     #Main Row
     dbc.Row([
         
         #Left Column
         dbc.Col([
             
             #DashBoard Heading
             dbc.Row([
                 
                 #heading logo
                 dbc.Col([html.Img( src=app.get_asset_url('theon-logo-horizontal-white.webp'),
                                     height='56px',
                                     className='mt-5')
                         ], sm=4, lg=12, md=3),
                 
                     ], id="heading"),
                 
             dbc.Row(html.Br()),
             #Plots pick
                         
             dbc.Row([ 
                 dbc.Card(dbc.CardBody([html.H4("Chose Plot Type", className="card-title", style = {'color':'#CFFF00'}),
                                        dcc.RadioItems(plots_names, plots_names[0], id="plot-picker", labelStyle={'display': 'block'}, inputStyle={"margin-right": "20px"})]
                                       ),
                          color = 'black', inverse=True, outline= False, )
                     ]), 
                                
                               
             dbc.Row(dbc.Card(dbc.CardBody([html.H4("Plot Description", className="card-title", style = {'color':'#CFFF00'}),
                                         dcc.Markdown(id='plot-explain',  link_target="_blank", className='card-text')]), 
                         color = 'black', inverse=True, outline= False)
                     )
             ], width = {'size': 3, 'offset':0, 'order': 'first' }, md={'size': 3, 'offset':0, 'order': 'first' }),
                         
        
         # Right Column
         dbc.Col([
             dbc.Row(html.Br()),
             dbc.Row(html.Br()),
             dbc.Row(html.Br()),
             dbc.Row(html.Br()),
             dbc.Row(html.Br()),
             dbc.Row(html.Br()),
 
             
             dbc.Card(dbc.CardBody([html.P("Chose tests from dropdwon menu:", className="card-title", style = {'color':'#CFFF00'}),
                     dcc.Dropdown(names, names[0], id="test-picker", multi = True, style = {'color':'black'}) ]), 
                      color = 'black', inverse=True, outline= False),
             
             dbc.Card(dcc.Graph(id="plot",  style={'width':'100%','height': '150hv', 'float': 'left','display':'inline-block'})  , 
                      color = 'black', inverse=True, outline= False         
                     )
  
             ], width= {'size':9, 'offset':0, 'order': 'first' }, md={'size': 9, 'offset':0, 'order': 'first' })
             
             ], className='mx-auto', justify='around')
 ])   
 
 #dbc.Row(dbc.Col(html.H4('Dieharder Plots', className='Dieharder-title', style = {'color':'#CFFF00'}), )),
 

 @app.callback(
     Output("plot", "figure"), 
     [Input("plot-picker", "value"), Input("test-picker", "value")])
 def update_bar_chart(plot_picker, picker_test):
     i=0
     if plot_picker == 'weakness':              
         data = []
         for test in picker_test:
             df = df_lists[test]
             p_value = [x for x in df.columns if x.startswith('pva')]
             n_rounds = len(p_value)
             trace = go.Bar(x=df.test_name, y = df.weak_rate, name  = '{}'.format(test))
             data.append(trace)
         
         layout = go.Layout(title = 'Fraction of weak and failed results per each Dieharder test', template = 'plotly_dark', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)')
         fig = go.Figure(data, layout)
         fig.update_yaxes(title_text='Failed/weak fractions', showgrid=False)
         fig.update_xaxes(tickfont_size=8, showgrid=False)
         fig.update_yaxes(tickfont_size=8)
         #fig.update_layout(legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01))
         return fig

 
 @app.callback(Output('plot-explain', 'children'), [Input("plot-picker", "value")])
 def update_chart_info(picker_test):
     if picker_test == 'weakness':
         text = "This plot counts how many weak/fail rounds are there for each test and divides it by the total number of rounds."
     elif picker_test == 'std':
         text = "This plot claculates the standard deviation of the p_values of each test. \nThe expected value for uniform distribution is std = 1/sqrt(12) = 0.2886..."
     elif picker_test == 'std_average':
         text = "This plot claculates the standard deviation of the p_values averaged over each test's repitition."
     elif picker_test == 'std_weak':
         text = "This plot returns the fraction of rounds for each Dieharder tests that have their standard deviations less than a specific threshold."
     elif picker_test == 'p_average':
         text = "This plot returns the average p_values for all Dieharder tests on the x-axis. \nFor a high number of rounds, the expected value for a uniform distribution is 0.5."
     elif picker_test == 'p_repitition_average':
         text = "This plot returns the average p_values over tests's rounds and then averages the values over each Dieharder test's repitition."
     elif picker_test == 'p_median':
         text = "This plot returns the median of the p_values of each Dieharder test. \nFor a high number of rounds, the expected value for a uniform distribution is 0.5."
     elif picker_test == 'p_median_all':
         text = "This plot returns the median of the p_values for all Dieharder tests on the x-axis."
     elif picker_test == 'p_median_average':
         text = "This plot returns the median of the p_values averaged over each Dieharder test's repitition."
     elif picker_test == 'p_range':
         text = "This plot returns the range of the p_values for each Dieharder test. \nFor a high number of rounds, the expected value for a uniform distribution is 1."
     elif picker_test == 'p_range_average':
         text = "This plot returns the range of the p_values averaged over each Dieharder test's repitition."
     else:
         return ""
     return [text]

I see in your code this callback showed 2 times so I think it could be a reason. Try to delete one and I think it could work. If you want to use duplicate_callback you could refer this link about 2.9 version of Dash.

1 Like

Oh… that is only a paste mistake here in the question… Sorry. in the real code there is no duplicates. I corrected it in the above code.

1 Like

Can you share sample df_list for us to try to run?

unfortunately this is a data from my company and i can’t share it. one thing i noticed though, is that this problem seems to started when i specified the width in the dbc.Col component. Not sure what is the relationship though. as a note, when i deploy the app to Heroku, the problem is not there.