✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Callback continuously getting called when sharing data between callbacks

I’m essentially doing this example from the user guide, with a few changes (this is just an example to give you an idea, it won’t run)

app.layout = html.Div([id = 'main',
    children = [
          html.Div([id = 'dropdown',
                ...
      ])
  ]
])

def update_layout(m):
    ...design layout...
    return app.layout

@app.callback(Output('intermediate-value', 'children'), [Input('dropdown', 'value')])
def clean_data(value):
     return value

@app.callback(Output('main', 'children'), [Input('intermediate-value', 'children')])
def update_graph(value):
    app.layout = update_layout(m = int(value))
    return app.layout

for n in range(m):
    @app.callback(
        Output('graph' + str(n+1), 'figure'),
        [Input('my-range-slider' + str(n+1), 'value')])
    def update_output(value):
        ...do stuff and output data...
        return fig

Only instead of the second output being to graph I output to id = main div tag from my app.layout. So essentially I want the dropdown in my app to be able to select how many graphs appear in the layout. The way I went about this is I pass the value from the dropdown to an empty div tag and then bring that data back in and if that value is (say, 3) I will output 3 graphs in my layout.

The issue is when this runs it constantly keeps hitting the callback so my app just continues to update on a loop. I’m not sure where this is coming from.

can you create a simple reproducible example from scratch that demonstrates the issue?

This one displays the issue:

import plotly.plotly as py
import plotly.graph_objs as go

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

app = dash.Dash()

app.layout = html.Div(id = 'main', 
            children = [
                html.Div([
                    html.H2(id='title'), 
                    html.Div(id='intermediate-value', style={'display': 'none'}),
                    html.Div([
                        html.Div([
                            dcc.Dropdown(
                                id='dropdown',
                                options=[
                                    {'label': '1', 'value': 1},
                                    {'label': '2', 'value': 2}
                                ],
                                value=2
                            ),
                        ], className="six columns"),
                        html.Div([
                            html.Div(id='slider-output-container1'),
                            html.Div([
                                dcc.Slider(id='my-range-slider1', min=1, max=10, step=1, value=2),
                                dcc.Graph(
                                    id='slide1', figure = dict(data = [])), 
                                dcc.Graph(
                                    id = 'graph1', figure = dict(data = [dict(x=0, y=0)]))
                            ])
                        ], className="six columns")
                    ], className="row")
                ], className="banner")
            ])

def update_layout(m):
    if (m == 1):
        app.layout = html.Div(id = 'main', 
            children = [
                html.Div([
                    html.H2(id='title'), 
                    html.Div(id='intermediate-value', style={'display': 'none'}),
                    html.Div([
                        html.Div([
                            dcc.Dropdown(
                                id='dropdown',
                                options=[
                                    {'label': '1', 'value': 1},
                                    {'label': '2', 'value': 2}
                                ],
                                value=2
                            ),
                        ], className="six columns"),
                        html.Div([
                            html.Div(id='slider-output-container1'),
                            html.Div([
                                dcc.Slider(id='my-range-slider1', min=1, max=10, step=1, value=2),
                                dcc.Graph(
                                    id='slide1', figure = dict(data = [])), 
                                dcc.Graph(
                                    id = 'graph1', figure = dict(data = [dict(x=0, y=0)]))
                            ])
                        ], className="six columns")
                    ], className="row")
                ], className="banner")
            ])
    if (m == 2):
        app.layout = html.Div(id = 'main', 
            children = [
                html.Div([
                    html.H2(id='title'), 
                    html.Div(id='intermediate-value', style={'display': 'none'}),
                    html.Div([
                        html.Div([
                            dcc.Dropdown(
                                id='dropdown',
                                options=[
                                    {'label': '1', 'value': 1},
                                    {'label': '2', 'value': 2}
                                ],
                                value=2
                            ),
                        ], className="six columns"),
                        html.Div([
                            html.Div(id='slider-output-container1'),
                            html.Div([
                                dcc.Slider(id='my-range-slider1', min=1, max=10, step=1, value=2),
                                dcc.Graph(
                                    id='slide1', figure = dict(data = [])), 
                                dcc.Graph(
                                    id = 'graph1', figure = dict(data = [dict(x=0, y=0)]))
                            ])
                        ], className="six columns"),
                        html.Div([
                            html.Div(id='slider-output-container2'),
                            html.Div([
                                dcc.Slider(id='my-range-slider2', min=1, max=10, step=1, value=2),
                                dcc.Graph(
                                    id='slide2', figure = dict(data = [])), 
                                dcc.Graph(
                                    id = 'graph2', figure = dict(data = [dict(x=0, y=0)]))
                            ])
                        ], className="six columns")
                    ], className="row")
                ], className="banner")
            ])
    return app.layout

@app.callback(Output('intermediate-value', 'children'), [Input('dropdown', 'value')])
def clean_data(value):
     return value

@app.callback(Output('main', 'children'), [Input('intermediate-value', 'children')])
def update_graph(value):
    app.layout = update_layout(m = int(value))
    return app.layout

if (len(app.layout) == 18): 
    m = 1
elif (len(app.layout) == 24): 
    m = 2
else:
    m = 1

for n in range(m):
    @app.callback(
        Output('graph' + str(n+1), 'figure'),
        [Input('my-range-slider' + str(n+1), 'value')])
    def update_output(value):

        data = go.Mesh3d(
                x = [0, 0, value, value, 0, 0, value, value],
                y = [0, value, value, 0, 0, value, value, 0],
                z = [0, 0, 0, 0, value, value, value, value]),
        
        layout = go.Layout(
            dict(
                scene = dict(
                        xaxis = dict(range = [0,50]),
                        yaxis = dict(range = [0,50]),
                        zaxis = dict(range = [0,50])),
                xaxis = dict(
                    range = [0, 50]), 
                yaxis = dict(
                    range = [0, 50]), 
                shapes = []
            )
        ) # close layout

        fig = dict(data = data, layout = layout)

        return fig

app.run_server(debug=True)

So I figured out how to stop the looping updates: I just wrapped the graphs in another Div and updated that Div rather than the whole app.layout. But now the question is how do I pass the value from the dropdown to the for loop around the last callback so the right number of graphs get outputted?