I am trying to build a plot that displays the price of a stock as a line plot, overlaid against the corresponding sum of volumes at that price point as a horizontal bar chart. Upon altering the view via zoom/pan, the bar chart should be redrawn according to the portion of the data in the line plot now visible on the screen. I have been trying to implement the dcc.Graph.extendData API with no success. Essentially, I want to completely overwrite the previous hbar trace data without affecting the view of the now-zoomed line plot. Here is what I have so far:
# abstractly defining the stuff that happens during initialization
x0_data, y0_data = ...
static_line_plot = go.Scatter(x=x0_data, y=y0_data, ...)
x1_data, y1_data = ...
initial_hbar = go.Bar(x=x1_data, y=y1_data, ...)
layout = go.Layout(...)
fig = make_subplots()
fig.update_layout(layout)
fig.add_trace(static_line_plot)
fig.add_trace(initial_hbar)
graph = dcc.Graph(figure=fig, id="stacked charts")
# the part I'm stuck on
@app.callback(
Output("stacked charts", "extendData"),
Input("stacked charts", "relayoutData"),
)
def redraw_hbar_on_zoom(relayout_data):
# retrieve current visible timeseries range from json
data = json.loads(json.dumps(relayout_data, indent=2))
# if graph has just been initialized
if data is None:
return [dict(x=[[y1_data.numpy()]], y=[[x1_data.numpy()]]), [1]]
# if user uses autoscale to reset view, hbar is set to the default range
data_keys = data.keys()
if "xaxis.range[0]" not in data_keys:
return [dict(x=[[y1_data.numpy()]], y=[[x1_data.numpy()]]), [1]]
# get the current x axis datetime range
xmin = data["xaxis.range[0]"]
xmax = data["xaxis.range[1]"]
# do some math to extract volume data from this corresponding
# timespan and rebuild the hbar
this_x1_data, this_y1_data = ...
# failed attempt to overwrite the old graph's figure's data before
# invoking extendData
graph.figure.data[1].x = []
graph.figure.data[1].y = []
# now "extend" this now empty plot with the data we just calculated
return [dict(x=this_y1_data.numpy(), y=this_x1_data.numpy()), [1]]
However, nothing seems to happen during the callback. The callback does run when it’s supposed to, and I have confirmed that the new data is calculated correctly.
Thanks for the help