Hello all. I’m trying to update a Plotly graph in a Dash app. I’d like to update just the figure’s data while preserving the layout. Specifically for my application, I’d like to update the figure data while preserving the axes types (linear, log, etc), but I’ve been unable to do that.
Working minimal code:
#!/usr/env/python3
# -*- coding: utf-8 -*-
import pandas as pd
import plotly.express as px
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
df = pd.DataFrame([[1, 2, 3], [5, 4, 5], [5, 6, 3], [7, 8, 5]],
columns=['a', 'b', 'c'])
fig_px = px.line(df, x='a', y='b', color='c')
# building dash app
header = [ html.H1(children='Example') ]
fig = [ dcc.Graph(id='fig', figure=fig_px) ]
opt_radio = [
dcc.RadioItems(
id='opt',
options=[ { 'label': v, 'value': v } for v in range(0,5) ],
value=3
)
]
dbg = [
html.Label('Button Debug:'),
html.Div(id='dbg_lbl', children=''),
html.Button('Print Y axis attributes', id='dbg_btn', n_clicks=0)
]
app = dash.Dash('example')
app.title = 'Example'
app.layout = html.Div(children=header + fig + opt_radio + dbg)
# callbacks
@app.callback(
Output(component_id='fig', component_property='figure'),
[Input(component_id='opt', component_property='value')]
)
def create_fig(opt):
# toy dataframe
df = pd.DataFrame([[opt, 2, 3], [5, 4, 5], [5, 6, 3], [7, 8, 5]],
columns=['a', 'b', 'c'])
# figure creation
fig = px.line(df, x='a', y='b', color='c', log_y=True)
log_linear = [{
'y': 1, 'x': 0,
'xanchor': 'left', 'yanchor': 'top',
'type': 'dropdown',
'buttons': [
{'label': 'log',
'method': 'relayout',
'args': ['yaxis', {'type': 'log'}]
},
{'label': 'linear',
'method': 'relayout',
'args': ['yaxis', {'type': 'linear'}]
}
]
}, {
'y': 0, 'x': 1,
'xanchor': 'right', 'yanchor': 'bottom',
'type': 'dropdown', 'direction': 'left',
'buttons': [
{'label': 'log',
'method': 'relayout',
'args': ['xaxis', {'type': 'log'}]
},
{'label': 'linear',
'method': 'relayout',
'args': ['xaxis', {'type': 'linear'}]
}
]
}]
fig.update_layout(updatemenus=log_linear)
return fig
@app.callback(
Output(component_id='dbg_lbl', component_property='children'),
[Input(component_id='dbg_btn', component_property='n_clicks')]
)
def button_press(n_clicks):
fig = app.layout.children[1].figure
return str(fig['layout']['yaxis'])
app.run_server(debug=True)
In this app, if I
- change the axis type (say, change the Y axis type from log to linear) through the updatemenu button; then
- change the radio button underneath the plot,
the data changes (as it should), but its axes also change back to the default type (in this case, to a loglog plot). I’d like them to stay the same (in this example, I’d like the Y axis type to stay linear as the callback changes the figure’s data).
In this case, simply reaching outside the callback to read the yaxis_type
attribute doesn’t work, because updatemenu
doesn’t seem to change the figure’s attributes (i.e. the figure yaxis
is the same, regardless of the actual figure, as exemplified by the button below the radio buttons).
Can it be done? Do I have to refactor my app somehow? Any help is appreciated!
Versions:
>>> dash.__version__
'1.12.0'
>>> dcc.__version__
'1.10.0'
>>> html.__version__
'1.0.3'
>>> plotly.__version__
'4.8.1'
>>> sys.version
'3.8.2 | packaged by conda-forge | (default, Apr 24 2020, 07:34:03) [MSC v.1916 64 bit (AMD64)]'
Cheers!