Hi,
Welcome to the community!
This sounds like a tough problem… So let me start with the easy part:
for example, the callback has to define the id of the figure in the callback decorator, however I don’t know this when the app is registering, since its unknown until the page is rendered
If you are looking for a generic callback that would work for some (or all) dcc.Graph
components in the page, you can use a pattern matching callback with MATCH
. So instead of define dcc.Graph(id=chart_id)
, you should use dcc.Graph(id={"type": "chart", "index": chart_id})
, then the callback can use the pattern Input({"type": "chart", "index": MATCH}, "figure")
(or Output/State, or other prop)…
The solution that you shared in the link will not work outside FigureWidgets
(jupyter notebooks), so for Dash you need to do something slightly different. A good starting point is a callback like this:
@app.callback(
Output({"type": "chart", "index": MATCH}, "figure"),
Input({"type": "chart", "index": MATCH}, "relayoutData"),
State({"type": "chart", "index": MATCH}, "figure"),
prevent_initial_update=True,
)
def update_figure(relayout_data, fig):
if (relayout_data is None) or ("xaxis.range[0]" not in relayout_data):
raise PreventUpdate # from dash.exceptions import PreventUpdate
in_view = df.loc[relayout_data["xaxis.range[0]"] : relayout_data["xaxis.range[1]"]]
# You must have layout_yaxis_autorange set to False
fig["layout"]["yaxis"]["range"] = [
in_view.min(),
in_view.max(),
]
return fig
Your rangeselector buttons will trigger a relayoutData
update that in some cases will come with the new range for x axis (as well as when you zoom a portion of the timeseries). I use the xaxis range to figure out which points are “in view”, just like in @jmmease example. Knowing that, you can redefine the yaxis range and return the modified figure dict.
Note that 1- I haven’t added any extra spacing in the min/max, so you might want to adapt it a bit to your convenience, and 2- this is supposed to be a first working example of such functionality and the performance is bad (data is sent back-and-forth to the client, which is slow).
The way to solve point 2 is to write a clientside callback to do this update. Here is a much simplified version of such figure update on the javascript side.