Hi and thank you for reading!
I’m playing with the Serverside component in a dash app and I’m facing with a problem.
I’m not the best with this component and there is no much documentations about my issue.
I have a div with several dcc.Graph and dcc.Store. One to display the traces and one to store the figures. When the user click on a button, I add a trace to each dcc.Graph in a callback and I want to return these new figures to the dcc.Store. Here is a little code to experiment:
Code without Serverside
# Import required libraries
import dash
from dash import html, dcc, Input, Output, State, callback_context, ALL, MATCH
import plotly.graph_objects as go
import uuid
#app = DashProxy(transforms=[ServersideOutputTransform()])
app = dash.Dash()
app.layout = html.Div([
html.Div([], id='container-graph'),
html.Button('Add Graphs', id='add-graph'),
html.Button('Add Traces', id='add-traces')
])
@app.callback(
Output('container-graph', 'children'),
Input('add-graph', 'n_clicks'),
State('container-graph', 'children'),
prevent_initial_call=True
)
def addGraphs(_, children):
uid = str(uuid.uuid4())
if callback_context.triggered_id == 'add-graph':
children.append(html.Div([
dcc.Graph(id={'type': 'graph', 'index': uid}, figure=go.Figure()),
dcc.Store(id={'type': 'store', 'index': uid}),
dcc.Interval(id={'type': 'interval', 'index': uid}, interval=1, max_intervals=1)
]))
return children
@app.callback(
Output({'type': 'graph', 'index': MATCH}, 'figure'),
Output({'type': 'store', 'index': MATCH}, 'data'),
Input({'type': 'interval', 'index': MATCH}, 'n_intervals'),
prevent_initial_call=True
)
def displayGraph(_):
fig = go.Figure()
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[1, 2, 3]))
return fig, fig.to_plotly_json()
@app.callback(
Output({'type': 'graph', 'index': ALL}, 'figure', allow_duplicate=True),
Output({'type': 'store', 'index': ALL}, 'data', allow_duplicate=True),
Input('add-traces', 'n_clicks'),
State({'type': 'store', 'index': ALL}, 'data'),
prevent_initial_call=True
)
def addNewTrace(_, figures_data):
store_list = []
for index in range(len(figures_data)): # fig is a go.Figure()
figures_data[index]['data'].append(go.Scatter(x=[3, 4, 5], y=[6, 5, 4]))
store_list.append(figures_data[index])
return figures_data, figures_data
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0')
And now with the Serverside I want:
Code with Serverside
# Import required libraries
from dash import html, dcc, Input, Output, State, callback_context, ALL, MATCH
from dash_extensions.enrich import DashProxy, Output, Input, State, Serverside, html, dcc, ServersideOutputTransform
import plotly.graph_objects as go
import uuid
app = DashProxy(transforms=[ServersideOutputTransform()])
app.layout = html.Div([
html.Div([], id='container-graph'),
html.Button('Add Graphs', id='add-graph'),
html.Button('Add Traces', id='add-traces')
])
@app.callback(
Output('container-graph', 'children'),
Input('add-graph', 'n_clicks'),
State('container-graph', 'children'),
prevent_initial_call=True
)
def addGraphs(_, children):
uid = str(uuid.uuid4())
if callback_context.triggered_id == 'add-graph':
children.append(html.Div([
dcc.Graph(id={'type': 'graph', 'index': uid}, figure=go.Figure()),
dcc.Store(id={'type': 'store', 'index': uid}),
dcc.Interval(id={'type': 'interval', 'index': uid}, interval=1, max_intervals=1)
]))
return children
@app.callback(
Output({'type': 'graph', 'index': MATCH}, 'figure'),
Output({'type': 'store', 'index': MATCH}, 'data'),
Input({'type': 'interval', 'index': MATCH}, 'n_intervals'),
prevent_initial_call=True
)
def displayGraph(_):
fig = go.Figure()
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[1, 2, 3]))
return fig, Serverside(fig)
@app.callback(
Output({'type': 'graph', 'index': ALL}, 'figure', allow_duplicate=True),
Output({'type': 'store', 'index': ALL}, 'data', allow_duplicate=True),
Input('add-traces', 'n_clicks'),
State({'type': 'store', 'index': ALL}, 'data'),
prevent_initial_call=True
)
def addNewTrace(_, figures_data):
store_list = []
for index in range(len(figures_data)): # fig is a go.Figure()
figures_data[index].add_trace(go.Scatter(x=[3, 4, 5], y=[6, 5, 4]))
store_list.append(figures_data[index])
# or create a list of Serverside(figures_data[index]) doesn't work too
return figures_data, Serverside(store_list)
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0')
This code create two buttons, one to add a div with graphs and a dcc.Store and plot a go.Scatter.
The second one is to add a new trace to all the dcc.Graph.
As you can see I am not able to do the same with Serverside.
I want to know if there is another method to do the same thing and what I am doing wrong.
Thank you all!