Hi,
Maybe this will help…
Jimmybow wrote a custom component you can install, to do just this. You can find it at
https://github.com/jimmybow/mydcc look under “3. mydcc.Relayout”
Hi,
Maybe this will help…
Jimmybow wrote a custom component you can install, to do just this. You can find it at
https://github.com/jimmybow/mydcc look under “3. mydcc.Relayout”
This is correct. Right now, there is not a way to update a nested attribute of a property.
Ideally, I’d like to support this more generally through two different solutions:
@app.callback(Output('my-graph', 'figure.layout.range'))
Plotly.react
to provide incremental updates to the figure, see https://github.com/plotly/plotly.js/pull/2341#issuecomment-364257543
For now, you can use jimmybow’s dcc
package or you’ll just have to return the entire figure each time.
Very interesting topic!
I have quite a few issues with slow response in Dash when updating minor figure layout elements or using events, probably caused by re-loading the entire data on each callback.
I have looked a bit into “build your own dash component”, thinking that some of these tasks could be transferred “back” to the faster JS side (such as updating a color, height, get hover information etc) without invoking a “costly” Dash callback (and leave those for more data related, Python-based stuff).
Now I understand (sorry, I’m new to React as well as relatively new to JS…) that I could build sort of custom-made graph components using Plotly.js and Plotly.newPlot();
(as done here: https://academy.plot.ly/react/3-with-plotly/) and work for example with Plotly.restyle
or Plotly.relayout
(as shown here: https://plot.ly/javascript/plotlyjs-function-reference/#plotlyrestyle).
However - here comes Plotly.react (
as @chriddyp posted: https://github.com/plotly/plotly.js/pull/2341#issuecomment-364257543), which sounds to be faster and may work better/cleaner(?) together with React. BUT on the main plotly.react page it says that “This component currently creates a new plot every time the input changes” (https://github.com/plotly/react-plotly.js/)
So, my question is - what do you think is the way forward? After all Plotly.js is the base library, which ultimately should allow most customisation - yet Plotly.react seems really attractive. In terms of building a custom-made Dash component, what would be the most sensible approach?
Thanks for shedding some light onto my current Plotly confusion…!
I am also interested in what will be the way forward here. Right now in my app i have a figure where I am animating a moving vertical line along the time axis. I am returning the entire figure each time, which works ok as long as the figure stays simple. However as figure get more complex the animation delay gets longer and longer.
Also mydcc.relayout works well for a simple example, but when I tried to use it in my case i get into some sort of infinite loop of callbacks, because I also i have callbacks that listen to chart relayout data and then update the chart to zoom in/out. Which leaves me not sure if the issue is with my callbacks or with mydcc.relayout and I don’t know to debug it.
this also seems ideal to me:
Allow the developer to update nested properties in callbacks with something like
@app.callback(Output(‘my-graph’, ‘figure.layout.range’))
For now it seems like I am stuck with “returning the entire figure each time”, until solution 1 or 2 is created (not soon?) or I learn more React/JS and custom components and can make some sort of custom hack.
Is there any update on this issue?
Your first soluction would be perfect.
Thanks!
No updates. This is actually quite a bit project and we’d likely need commercial sponsorship of the feature in order to move it forward
Sorry I can not help with that. I don´t belong to any company.
I believe this is now possible to some extent thanks to State
callback.
@app.callback(Output('graph', 'figure'),
[Input('graph', 'relayoutData')], # this triggers the event
[State('graph', 'figure')])
def graph_event(select_data, fig):
fig['layout'] = [YOUR STUFF]
return fig
This is sorely needed for large plots e.g. choropleths that have megabytes of data to be overlaid on the map, which at the present need to be sent repeatedly when a layout change such as zoom level is made to the figure via callback.
After facing a similar issue it seems like client side callbacks are the best way to step around this issue!
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, ClientsideFunction
app = dash.Dash(__name__)
fig_data = {
"data": [{"type": "bar", "x": [1, 2, 3], "y": [1, 3, 2]}],
"layout": {"title": {"text": ""}}
}
app.layout = html.Div([
dcc.Store("fig-data", data=fig_data),
dcc.Dropdown(
id="city",
options=[ {'label': z, "value": z} for z in ["Sydney", "Montreal"] ],
value="Sydney"
),
dcc.Graph(id="graph")
])
app.clientside_callback(
ClientsideFunction("clientside", "figure"),
Output(component_id="graph", component_property="figure"),
[Input("fig-data", "data"), Input("city", "value")],
)
app.run_server(host="0.0.0.0", debug=True)
if (!window.dash_clientside) {
window.dash_clientside = {}
}
window.dash_clientside.clientside = {
figure: function (fig_dict, title) {
if (!fig_dict) {
throw "Figure data not loaded, aborting update."
}
// Copy the fig_data so we can modify it
// Is this required? Not sure if fig_data is passed by reference or value
fig_dict_copy = {...fig_dict};
fig_dict_copy["layout"]["title"] = title;
return fig_dict_copy
},
}
This example is a bit more involved so I put it in a repl.it
I am still new to Dash Plotly. I do not know any Javascript. The solution proposed by tracek works (without external script).
This is what I have in my script. I can update the title of the graph. Hopefully this can help anyone who is struggling with this aspect.
@app.callback(
Output(component_id='my-div', component_property='figure'),
[Input(component_id='variable', component_property='value')],
[State('my-div', 'figure')]
)
def update_output_div(input_value, fig):
fig['layout'] = {"title": input_value}
return fig
Hi,
I’m wondering how @tracek solution improve performance compared to reloading at each call back. Does changing the state only reload the changed attribute or it reloads the whole figure?
Thank you
Any Update here ? I’m trying to update the annotation text of my Graph , is that possible?
The best workaround right now is to use a clientside callback to add or change the smaller pieces of the figure. See the example here: https://dash.plotly.com/clientside-callbacks
Just a minor addition to your great example: You have to make a deep copy of the figure object. Otherwise you might run into issues when adding elements to an existing list, e.g. such as traces.
I was able to completely decouple any figure modification (e.g. adding descriptive shapes, traces, annotations etc.) while keeping the original (large) figure data in a dcc.Store
object and not resend it on every update (of the auxiliary data).
Would you mind sharing code on your example? I am facing a similar issue.
Yes, can you show us your example, please?
I’m trying to make a choropleth with ~40k polygons that gets recolored depending on the value of a dropdown menu.
I want to the menu choice to trigger a server-side recomputation of the choropleth values, colors, and legend, then send only that info to the client and not the large amount of geodata again.
Any suggestions?