I’ve created a one-page Plotly Dash app with four graphs. Among these, three graphs come with submit buttons and dropdowns to facilitate changes. When I modify a graph and press its submit button, the data gets updated in the database, and the changes are reflected in that specific graph. However, the changes don’t appear in other graphs all the graphs are based on the same dataset. Despite having implemented everything using callbacks, the changes made and saved in the dataset do not appear in the other graphs unless I manually reload the web page.
Hello @smhamza,
Welcome to the community!
It sounds like you need to reload your data into the graphs.
If you could post your code we will be able to help more.
HI @jinnyzor,
Thanks for you reply.
Below is a snippet of my complete code. I’m posting the specific code section where I require assistance.
app.layout = html.Div([
# Section 1 html.Div([ # Add a graph to Section 1 dcc.Graph( id='graph', ), ], className="multi-graph"), # Section 2 html.Div([ html.Div([ # First div with dropdowns and buttons html.Div([ html.Label('Unique ID', style={'color': 'white'}), dcc.Dropdown( id='unique-id-dropdown', options=[{'label': str(uid), 'value': uid} for uid in df['unique_id'].unique()], placeholder="Select a unique ID" ), html.Label('shift', style={'color': 'white'}), dcc.Dropdown( id='dmon-dropdown', options=[{'label': date, 'value': date} for date in df['cal_month'].unique()], placeholder="Select a cal_month value" ), # html.A(html.Button('Submit', id='submit-button'),href='/') it also reloads the page html.Button('Submit', id='submit-button') ], className='dropdown-container'), # Second div with graph html.Div([ dcc.Graph( id='graph_here', config={'displayModeBar': False}, # Hide the plotly mode bar ) ], className='graph-container') ], className='section2-content') ], className="section_2")
,])
Preformatted text
@callback(Output(‘graph’, ‘figure’),
Input(‘graph’, ‘fig’))
def update_graph(fig,n):
df = data()
# dash app instanceapp = dash.Dash(name)
first_chart = visual(df) return first_chart
#call back for section 2
#Add the callback function to handle the dropdown inputs and update the graph:
@callback(Output(‘graph_here’, ‘figure’),
Input(‘submit-button’, ‘n_clicks’),
State(‘unique-id-dropdown’, ‘value’),
State(‘dmon-dropdown’, ‘value’),
)
def update_graph_(n_clicks, unique_id, dmon):
global df
df = data()
if unique_id is None or dmon is None:
fig = visual(df)
return figdf = shift_stack(df, dmon, unique_id) update_database(df) fig = visual(df) )
return fig
In the initial callback, I’m visualizing a graph. In the second callback, there are two associated dropdowns and a submit button. When the button is pressed, the dataset is updated, and only this specific graph should reflect the changes. However, the first graph doesn’t show the modifications made to the dataset, even though the dataset is the same. To view the changes in the first graph, I have to manually refresh the page. I would like to achieve this without refreshing/reloading the page and without using the interval approach. Your assistance in this matter would be greatly appreciated.
Here is a version that is a little more runable:
from dash import Dash, html, dcc, Input, Output, callback, State
app = Dash(__name__)
app.layout = html.Div([
# Section 1
html.Div([
# Add a graph to Section 1
dcc.Graph(
id='graph',
),
], className="multi-graph"),
# Section 2
html.Div([
html.Div([
# First div with dropdowns and buttons
html.Div([
html.Label('Unique ID', style={'color': 'white'}),
dcc.Dropdown(
id='unique-id-dropdown',
options=[{'label': str(uid), 'value': uid} for uid in df['unique_id'].unique()],
placeholder="Select a unique ID"
),
html.Label('shift', style={'color': 'white'}),
dcc.Dropdown(
id='dmon-dropdown',
options=[{'label': date, 'value': date} for date in df['cal_month'].unique()],
placeholder="Select a cal_month value"
),
# html.A(html.Button('Submit', id='submit-button'),href='/') it also reloads the page
html.Button('Submit', id='submit-button')
], className='dropdown-container'),
# Second div with graph
html.Div([
dcc.Graph(
id='graph_here',
config={'displayModeBar': False}, # Hide the plotly mode bar
)
], className='graph-container')
], className='section2-content')
], className="section_2")
,])
@callback(Output('graph', 'figure'),
Input('graph_here', 'figure'))
def update_graph(fig,n):
df = data()
# dash app instance
# app = dash.Dash(__name__)
first_chart = visual(df)
return first_chart
#call back for section 2
#Add the callback function to handle the dropdown inputs and update the graph:
@callback(Output('graph_here', 'figure'),
Input('submit-button', 'n_clicks'),
State('unique-id-dropdown', 'value'),
State('dmon-dropdown', 'value'),
)
def update_graph_(n_clicks, unique_id, dmon):
df = data()
if unique_id is None or dmon is None:
fig = visual(df)
return fig
df = shift_stack(df, dmon, unique_id)
update_database(df)
fig = visual(df)
return fig
On this version, if the figure in the second graph changes, the first one will change.
I sincerely thank you @jinnyzor for your invaluable assistance; it has proven to be effective. I have encountered a situation where I am dealing with five graphs that are all derived from the same source. The approach of using the component_id and component_property of the second and third graphs as input for the first graph, and similarly, the component_id and component_property of the third graph as input for the second graph, works seamlessly. Consequently, when changes are made to the third graph, they are appropriately reflected in both the second and first graphs.
However, I am now faced with the challenge of achieving the reverse scenario. I intend to display changes made in the second graph when updating the third graph. When I attempt to input the component_id and component_property of the second graph into the third graph, I encounter an error: “Error: Dependency Cycle Found.”
I kindly request your guidance on resolving this matter as well. Once again, I deeply appreciate your assistance, your time, and the thoughtful consideration you’ve provided.
from dash import Dash, html, dcc, Input, Output, callback, State
app = Dash(__name__)
app.layout = html.Div([
# Section 1
html.Div([
# Add a graph to Section 1
dcc.Graph(
id='graph',
),
], className="multi-graph"),
# Section 2
html.Div([
html.Div([
# First div with dropdowns and buttons
html.Div([
html.Label('Unique ID', style={'color': 'white'}),
dcc.Dropdown(
id='unique-id-dropdown',
options=[{'label': str(uid), 'value': uid} for uid in df['unique_id'].unique()],
placeholder="Select a unique ID"
),
html.Label('shift', style={'color': 'white'}),
dcc.Dropdown(
id='dmon-dropdown',
options=[{'label': date, 'value': date} for date in df['cal_month'].unique()],
placeholder="Select a cal_month value"
),
# html.A(html.Button('Submit', id='submit-button'),href='/') it also reloads the page
html.Button('Submit', id='submit-button')
], className='dropdown-container'),
# Second div with graph
html.Div([
dcc.Graph(
id='graph_here',
config={'displayModeBar': False}, # Hide the plotly mode bar
)
], className='graph-container')
], className='section2-content')
], className="section_2")
,
# ....section 3
html.Div([
html.Div([
# First div with dropdowns and buttons
html.Div([
html.Label('Select member', style={'color': 'white'}),
dcc.Dropdown(
id='member-dropdown_2',
options=member_options,
value=df['me_id'].unique()[0] if len(df['me_id'].unique()) > 0 else None,
clearable=True,
),
html.Label('Select Project', style={'color': 'white'}),
dcc.Dropdown(
id='unique-id-dropdown_2',
placeholder='Projects',
style={'width': '200px', 'background': 'transparent', 'color': 'black', 'border': '1px solid white'}
),
html.Label('Where to shift', style={'color': 'white'}),
dcc.Dropdown(
id='dmon-dropdown_2',
options=[{'label': date, 'value': date} for date in df['cal_month'].unique()],
),
html.Button('Submit', id='submit-button_2'),
], className='dropdown-container'),
])
@callback(Output('graph', 'figure'),
Input('graph_here', 'figure'),
Input('my-graph_section_3', 'figure'))
def update_graph(fig, n):
df = data()
# dash app instance
# app = dash.Dash(__name__)
first_chart = visual(df)
return first_chart
# call back for section 2
@callback(Output('graph_here', 'figure'),
Input('submit-button', 'n_clicks'),
Input('my-graph_section_3', 'figure'),
State('unique-id-dropdown', 'value'),
State('dmon-dropdown', 'value'),
)
def update_graph_(n_clicks, unique_id, dmon):
df = data()
if unique_id is None or dmon is None:
fig = visual(df)
return fig
df = shift_stack(df, dmon, unique_id)
update_database(df)
fig = visual(df)
return fig
#section 3
# Add the callback function to handle the dropdown inputs and update the graph
@callback(Output('my-graph_section_3', 'figure'),
Input('submit-button_2', 'n_clicks'),
Input('member-dropdown_2', 'value'),
Input('graph_here', 'figure'),
State('unique-id-dropdown_2', 'value'),
State('dmon-dropdown_2', 'value'))
def update_graph_sec_3(n_clicks, member_id, fig, unique_id, dmon):
df = get_data()
global actual_df
if member_id is None or unique_id is None or dmon is None:
#code...
#code....
return fig
# code...
# code....
return fig
If you want all the graphs to change when any of the others are, then you’ll need to use ctx
.
Something like this:
from dash import ctx, Input, Output
@app.callback(
Output('chart1', 'figure'),
Output('chart2', 'figure'),
Output('chart3', 'figure')
Output('chart4', 'figure'),
Input('chart1', 'figure'),
Input('chart2', 'figure'),
Input('chart3', 'figure')
Input('chart4', 'figure'),
prevent_initial_call=True
)
def updateGraphs(chart1, chart2, chart3, chart4):
if ctx.triggered_id == 'chart1':
return no_update, new_chart2, new_chart3, new_chart4
if ctx.triggered_id == 'chart2':
return new_chart1, no_update, new_chart3, new_chart4
...
This should take it out of the cycle of callbacks.
Thanks for this @jinnyzor . Could you please elaborate how can I implement this in my code.
Replace this line right here with what I mentioned above:
from dash import ctx, Input, Output
@app.callback(
Output('chart1', 'figure', allow_duplicate=True),
Output('chart2', 'figure', allow_duplicate=True),
Output('chart3', 'figure', allow_duplicate=True)
Output('chart4', 'figure', allow_duplicate=True),
Input('chart1', 'figure'),
Input('chart2', 'figure'),
Input('chart3', 'figure')
Input('chart4', 'figure'),
prevent_initial_call=True
)
def updateGraphs(chart1, chart2, chart3, chart4):
if ctx.triggered_id == 'chart1':
return no_update, new_chart2, new_chart3, new_chart4
if ctx.triggered_id == 'chart2':
return new_chart1, no_update, new_chart3, new_chart4
...