dash-core-components
dash-core-components copied to clipboard
Config attribute of dcc.Graph does not respond to callbacks (is read-only)
When using a callback to control the modebar settings on a chart through the config property of a dcc.Graph, the graph does not update but retains the initial setting.
Note: I have not (yet) tested with other config settings.
Minimal example
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.express as px
app = dash.Dash()
server = app.server
app.layout = html.Div(
[
dcc.Graph(
id="line-graph",
figure=px.line(x=[1, 2, 3], y=[1, 2, 3]),
),
dcc.RadioItems(
options=[
{"label": "Show modebar", "value": 1},
{"label": "Hide modebar", "value": 0},
],
value=1, # Note that if this value is set to 0 then the modebar will stay turned off rather than turned on.
id="radio",
),
html.Div([html.H3("Current config"), html.P(id="cur-config")]),
]
)
@app.callback(
[Output("line-graph", "config"), Output("cur-config", "children")],
[Input("radio", "value")],
)
def toggle_modebar(i):
vals = [False, True]
config = {"displayModeBar": vals[i]}
return config, str(config)
if __name__ == "__main__":
app.run_server(debug=True, port=8050)
Screen recording
https://user-images.githubusercontent.com/38958867/107691811-edb77d00-6c79-11eb-8488-c750b635f815.mov
One workaround for this is generating a new dcc.Graph in a callback with the same id and using the state of the existing figure to prevent needing to regenerate it.
Screen recording of this (and the expected behaviour)
https://user-images.githubusercontent.com/38958867/107695876-2f96f200-6c7f-11eb-880a-e4c9459a8ca1.mov
Code
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.express as px
app = dash.Dash()
server = app.server
app.layout = html.Div(
[
html.Div(
dcc.Graph(id="line-graph"),
id="graph",
),
dcc.RadioItems(
options=[
{"label": "Show modebar", "value": 1},
{"label": "Hide modebar", "value": 0},
],
value=1,
id="radio",
),
dcc.RadioItems(
options=[
{"label": "Bar", "value": 1},
{"label": "Line", "value": 0},
],
value=1,
id="fig-type",
),
]
)
@app.callback(Output("line-graph", "figure"), [Input("fig-type", "value")])
def create_fig(i):
figures = [px.line(x=[1, 2, 3], y=[1, 2, 3]), px.bar(x=[1, 2, 3], y=[1, 2, 3])]
return figures[i]
@app.callback(
Output("graph", "children"),
[Input("radio", "value")],
[State("line-graph", "figure")],
)
def toggle_modebar(i, fig):
vals = [False, True]
config = {"displayModeBar": vals[i]}
return dcc.Graph(id="line-graph", figure=fig if fig else {}, config=config)
if __name__ == "__main__":
app.run_server(debug=True, port=8050)