Dash 2.16.1: dcc.Graph clickData callback never executed

I must be missing something obvious but after reading through documentation and forums for a couple of hours, I am still not able to get a clickData callback. Code is below. No error in the JS console either. Any help would be appreciated. Thank you.

import dash
from dash.dependencies import Input, Output
from dash import html, dcc

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Graph(
        id='graph',
    ),
    html.Div(id='coordinates')
])

@app.callback(Output('coordinates', 'children'),
              Input('graph', 'clickData'),
              prevent_initial_call=True)
def never_called(click_data):
    if click_data is None:
        print('No click data')
        return 'never called'

    print(click_data)
    return "never called either"

if __name__ == '__main__':
    app.run_server(debug=True)

Hello @nielsp,

Welcome to the community!

clickData must be based on data in the graph, if there is none, then this event won’t trigger.

:grin:

Ouch. That hurts :slight_smile: Thank you for your quick reply.

If you might indulge me a little further, the real problem I am trying to solve is to get the click coordinates from a user on an image. I wrapped the image in an EventListener and am getting the clientX and clientY properties from the event.

In Javascript, I would do something like this:

const image = document.getElementById('image-id');
const imageRect = image.getBoundingClientRect();

to get the offset and compute the image relative coordinates from clientX and clientY. I have been unable to make progress on this as well. I don’t know how to get any information from Javascript to the Python code. My attempts to even get access to any of the DOM have failed, too. Even when waiting for DOMContentLoaded, none of the DOM elements seem to exist.

Any suggestions? Thank you!

To addEventListener to an element, dom content isn’t loaded the same way as you would think.

In dash, the apps layout is loaded. Then a post request is sent to load the layout that you set. Thus anything that you want to add a listener to would be in a response on the post request. That’s why dom content loaded doesn’t work.

What I typically do for this is have a callback on the id of the component as an input, then when that is triggered because of loading the component to the layout, set a timeout of 300ms to then perform the addEventListener.

Hope this helps.

Thank you. I ended up storing the bounding rectangle via a client side callback:

app.clientside_callback(
    ClientsideFunction(namespace='clientside', function_name='store_rect_coords'),
    Output('rect-data', 'data'),
    Input('image', 'src')
)

and then made the dcc.Store(‘rect-data’) a State dependency on the click callback. This seems to work alright. Thank you!!!

1 Like

Also, if you need to send stuff to the dash eco system, you can use dash_clientside.set_props(id,props) from js.