Hi, hoping someone can help me here.
Here's a minimal version for the problem… I'm encountering. I'm developing an app that will have multiple plots (seismic traces) where a user needs to be able to add a vertical line for arrival times. I need to get actual mouse position in data coordinates, not nearest clickData.
I assign an EventListener to each plot when I dynamically create them. The code here doesn't work until I make a trivial edit/unedit and save again in debug mode - in which case it starts registering the alt-click and draws a dashed vertical line (see screen-shot).
Is the Graph initialization preventing the propagation of the click event, and then subsequent debug reloads capture it again? What can I do to make it work after Graph initialization, or am I using the wrong approach, or is this not possible in Dash?
Thanks for any help.

---
```
from dash import Dash, dcc, html, State, Input, Output, callback, no_update, MATCH
from dash.exceptions import PreventUpdate
from dash_extensions import EventListener
import plotly.express as px
import numpy as np
click = {"event": "click", "props": ['srcElement.attributes.class.value', 'srcElement.height.animVal.value','srcElement.attributes.width.value','srcElement.attributes.x.value', 'srcElement.attributes.y.value', 'clientX', 'clientY','offsetX', 'offsetY', 'layerX', 'layerY', 'altKey', 'ctrlKey', 'shiftKey']}
app = Dash(__name__)
df = px.data.tips()
app.layout = html.Div([
html.Button('Plot', id='btn_plot', n_clicks=0),
html.Div([], id='holder'),
])
@app.callback(
Output('holder','children'),
Input('btn_plot','n_clicks'),
prevent_initial_call=True
)
def OnPlot(n_clicks):
evls = []
rx = np.arange(0.0,4*np.pi,0.1)
for i in range(2):
x = rx[(i+1)*10:(i+1)*10+100]
y = np.sin(x+i*5)
fig = px.scatter(x=x, y=y, range_x = [rx[0], rx[-1]])
fig.add_vline(x=0.0, line_dash="dot", line={'color':'grey', 'width': 0.75}, name='tP', opacity=0.0)
graph = dcc.Graph(figure=fig, id={'type':'graph', 'value':i})
evls.append(EventListener(graph, events=[click], logging=True, id={'type':'evl', 'value':i}))
return evls
@app.callback(
Output({'type':'graph', 'value':MATCH}, 'figure'),
Input({'type':'evl', 'value':MATCH}, "n_events"),
State({'type':'evl', 'value':MATCH}, "event"),
State({'type':'graph', 'value':MATCH}, 'figure'),
State({'type':'graph', 'value':MATCH}, 'id'), prevent_initial_call=True
)
def OnPlotClick(n_events, e, figure, idGraph):
if e is None:
raise PreventUpdate()
if not 'srcElement.attributes.class.value' in e:
raise PreventUpdate() # outside plot area
if e['srcElement.attributes.class.value'] != 'nsewdrag drag':
raise PreventUpdate() # outside plot area
if not e['altKey']:
raise PreventUpdate() # no alt key
# calc x,y
x_min, x_max = figure['layout']['xaxis']['range']
y_min, y_max = figure['layout']['yaxis']['range']
x_rel = float(e['offsetX']-int(e['srcElement.attributes.x.value']))/float(e['srcElement.attributes.width.value'])
y_rel = 1.0-float(e['offsetY']-int(e['srcElement.attributes.y.value']))/float(e['srcElement.height.animVal.value'])
x = x_min + x_rel*(x_max-x_min)
y = y_min + y_rel*(y_max-y_min)
print('Graph #: %d, x=%1.3f y=%1.3f' % (idGraph['value'], x, y))
vline = shapes = figure['layout']['shapes'][0]
vline['x0'] = x
vline['x1'] = x
vline['opacity'] = 1.0
if (0.0 <= x_rel <= 1.0) and (0.0 <= y_rel <= 1.0):
return figure
else:
return no_update
app.run(debug=True)
```