Vertical line on hover in all subplots

I have 8 different graphs (all time series) in a sub-plot and I am trying to create a vertical line on hover that shows up on all the graphs, which is essentially acting as a crosshair across the different charts.

Currently I have something like this but this only works on one of the subplot graphs.
fig['layout']['xaxis1'].update(rangeslider=dict(visible = False), showspikes= True, spikemode = 'across', spikedash = 'solid', spikecolor = '#A9A9A9', spikethickness=2, spikesnap = 'cursor')

I tried setting up a callback, which saves the x-axis value (the date) and then feed it as an input to create a vertical line shape. However, the issue with this is that in the initial run, there is no hover data so the input id does not exist when feeding it to the graph callback.

@app.callback(
    [dash.dependencies.Output('oi_graphs','figure')],
    [dash.dependencies.Input('oi_ticker-dropdown', 'value'),
    dash.dependencies.Input('oi_hours', 'value'),
    dash.dependencies.Input('oi-interval-component', 'n_intervals'),
    dash.dependencies.Input('oi-hover-data', 'children')]
    )

def oi_create_graph(coin, h,n_update):
    .... code that creates the graph ....
    oi_hover_line = [{'type': 'line','xref': 'x1','yref': 'y1','x0': hover_date ,'y0': min(df['low']),'x1': hover_date,
        'y1': max(df['high']),'opacity': 1,'line': {'width': 1,'color': 'black','dash': 'dot'}}]

@app.callback(
    dash.dependencies.Output('oi-hover-data', 'children'),
    [dash.dependencies.Input('oi_graphs', 'hoverData')])

def display_hover_data(hoverData):
    if hoverData != None:
        print("hover data:", hoverData['points'][0]['x'])
        return json.dumps(hoverData['points'][0]['x'], indent=2)
    else:
        return("")
1 Like

Hi @shubox,

I think you have the right idea here to use a line shape object to draw the line. I changed the topic of your post to “Dash” since I think the core of your question has to do with the Dash callback structure.

-Jon

What is the error you are getting, or are you getting an error? Your first function has four Inputs but only three function parameters.

Maybe you could use State('oi_graphs','figure) as an input to display_hover_data.
When the hoverData is updated:

  • check if the y data for the last thing in the figure’s data list has identical items (i.e. y[0]==y[-1], i.e. there’s already a vertical line)
  • if it does, just pop it off the end of the list
  • add a go.Scatter(marker=dict(...,mode='line') to the list of data at the hoverData's x coordinate with x and y vertical like in How do i plot vertical line over a timeseries curve in plotly?
  • return the new figure with the new vertical line

Using subplots make this harder, but I think the general idea would work, and it should be relatively fast.