# Click event on anywhere in a graph

**URL:** <https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933>\
**Category:** Dash Python\
**Tags:** question\
**Created:** [June 30, 2025, 1:42pm UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933 "2025-06-30T13:42:34Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Galaktik](https://avatars.discourse-cdn.com/v4/letter/g/6f9a4e/32.png) [@Galaktik](https://community.plotly.com/u/Galaktik)\
**Post date:** [June 30, 2025, 1:42pm UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933/1 "2025-06-30T13:42:34Z")

</div>

Hello everyone,

I was wondering if it is possible to add a click event on a graph (specifically a map) that would capture any click the user makes, even if it is not on a known point.  
I’ve searched numerous docs and forums but I couldn’t find anything that answers my question, even the plotly docs ( [Event handlers in JavaScript](https://plotly.com/javascript/plotlyjs-events/)) on event handlers in JS do not seem to have a suitable solution.  
With the exemple below, you can see a callback linked to the clickData property of my scatter-geo graph. But if the user clicks somewhere on the map that is not associated with a point, I would need the app to display the coordinates anyway.

```python
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.express as px

# Load the gapminder data for the year 2007
df = px.data.gapminder().query("year == 2007")

# Create the ScatterGeo plot with Plotly Express
fig = px.scatter_geo(
    df,
    locations="iso_alpha",
    size="pop",
    hover_name="country", # display country name on hover
    title="Countries in 2007",
    template="plotly",
    color="continent",
)

app = dash.Dash( __name__ )

app.layout = html.Div(
    [dcc.Graph(id="scatter-geo", figure=fig), html.Div(id="click-output")]
)

# Callback to display the clicked country
@app.callback(Output("click-output", "children"), Input("scatter-geo", "clickData"))
def display_click_data(click_data):
    if click_data is None:
        return "Click on a country to get more information."

    country = click_data["points"][0]
    return f"You clicked on: {country['hovertext']} with coordinates ({country['lat']}°, {country['lon']}°)"

if __name__ == " __main__":
    app.run(debug=True)

```

---

<div class="post-metadata">

**Author:** ![AIMPED](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/aimped/32/21758_2.png) [@AIMPED](https://community.plotly.com/u/AIMPED)\
**Post date:** [July 1, 2025, 8:21am UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933/2 "2025-07-01T08:21:52Z")

</div>

Hi @Galaktik we had this topic quite a few times, [here](https://community.plotly.com/t/how-to-add-new-data-point-to-graph-canvas-by-single-mouse-click/73039/10) for example

What is the use case for this?

I’m not sure there is a built-in way to do this. You would have to track the cursor within the div and then calculate the coordinates in your graph. If adding possible zoom state into the mix this could be really tricky.

---

<div class="post-metadata">

**Author:** ![Galaktik](https://avatars.discourse-cdn.com/v4/letter/g/6f9a4e/32.png) [@Galaktik](https://community.plotly.com/u/Galaktik)\
**Post date:** [July 1, 2025, 12:49pm UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933/3 "2025-07-01T12:49:15Z")

</div>

Hello @AIMPED, thank you for responding.

I’m trying to make a function to calculate the distance between two points that the user choose on the map. I already got a map with traces but the user must be able to place new points on the map as he wishes.

I already saw this post, but the problem is I’m working with a ScatterGeo plot, and as you can see in my previous exemple, the callback simply doesn’t fire with clickData as an input.  
I was afraid that there was no easy way for me to do this, thanks for the tips.

I find that quite sad thought that ScatterGeo plots cannot track the clicks of user as well as Scatter plots.

Thanks you.

---

<div class="post-metadata">

**Author:** ![AIMPED](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/aimped/32/21758_2.png) [@AIMPED](https://community.plotly.com/u/AIMPED)\
**Post date:** [July 1, 2025, 3:11pm UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933/4 "2025-07-01T15:11:20Z")

</div>

I understand. You are tying to implement something like this, right?

> **[Measure distances | Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/example/measure/)**
>
> Click points on a map to create lines that measure distanced using turf.length.

Not sure if one of these components might be helpful:

> [@Show and Tell: Pip Install Python September Update](https://community.plotly.com/t/show-and-tell-pip-install-python-september-update/87415):
>
> [image] Welp, I’ve been having too much fun building out components and projects in Dash. Wanted to give an overview about some of these projects I’ve recently created to show that a lot more is possible in this framework than just Data Science. This initial .gif of a dynamic layout, is my newest project I’ve been working on building out. Trying to improve on dash-dynamic-grid and dash-resizable-panels. Really enjoy both of these components and I feel like this new package I’m creating takes g…

---

<div class="post-metadata">

**Author:** ![Galaktik](https://avatars.discourse-cdn.com/v4/letter/g/6f9a4e/32.png) [@Galaktik](https://community.plotly.com/u/Galaktik)\
**Post date:** [July 2, 2025, 7:15am UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933/5 "2025-07-02T07:15:39Z")

</div>

Yes this is what I’m trying to implement.

The problem is that I really need to implement it in a ScatterGeo plot so I can’t use the leaflet library.  
I’ve looked into the link you gave me but it doesn’t seem like there is a component that suits me.

---

<div class="post-metadata">

**Author:** ![Galaktik](https://avatars.discourse-cdn.com/v4/letter/g/6f9a4e/32.png) [@Galaktik](https://community.plotly.com/u/Galaktik)\
**Post date:** [July 2, 2025, 10:08am UTC](https://community.plotly.com/t/click-event-on-anywhere-in-a-graph/92933/6 "2025-07-02T10:08:33Z")

</div>

I have implemented a solution. I’ve looked at pretty much every properties of the graph object and I have found some useful info. Since the lonRange and latRange of the map doesn’t update when scrolling and zooming, we have to use the scale and the center point of the current view of the map to adjust our ranges.  
However, i don’t know how precise this solution is, but I think it gets the work done.

Here is a minimal app implementing the solution for anyone willing to track the click of an user on a map  
app.py

```auto
import dash
from dash import dcc, html
import plotly.graph_objects as go

app = dash.Dash( __name__ , assets_folder="assets")

fig = go.Figure(go.Scattergeo(lat=[], lon=[], mode='markers'))
fig.update_layout(
    geo=dict(
        scope='world', 
        projection_type='mercator',
        showland=True,
        landcolor="lightgray",
        coastlinecolor="Black"
    ),
    margin=dict(l=0, r=0, t=0, b=0),
)

app.layout = html.Div([
    dcc.Graph(
        id="map",
        figure=fig,
        config={"scrollZoom": True},
        style={"height": "80vh"}
    ),
    html.Div("Click on the map", id="click-output", style={"fontSize": "20px", "marginTop": "10px"}),
])

if __name__ == " __main__":
    app.run(debug=True)

```

assets/clickMap.js

```js
function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

async function clickOnMap() {
    await sleep(5000);

    const graphDiv = document
        .getElementById("map")
        .getElementsByClassName("js-plotly-plot")[0];
    const outDiv = document.getElementById("click-output");

    graphDiv.addEventListener("click", function (event) {
        const bb = graphDiv.getBoundingClientRect();
        const xPx = event.clientX - bb.left;
        const yPx = event.clientY - bb.top;

        const gd = graphDiv._fullLayout;
        const geo = gd.geo;

        // Getting scale, center, and rotation info from geo projection
        const scale = geo.projection.scale;
        const centerLat = geo.center.lat;
        const centerLon = geo.center.lon;

        // Getting current ranges for lon and lat from the geo component
        const lonRange = geo.lonaxis.range;
        const latRange = geo.lataxis.range;

        // Adjust lonRange and latRange based on the center and scale
        const adjustedLonRange = [
            centerLon - (lonRange[1] - lonRange[0]) / (2 * scale),
            centerLon + (lonRange[1] - lonRange[0]) / (2 * scale),
        ];

        const adjustedLatRange = [
            centerLat - (latRange[1] - latRange[0]) / (2 * scale),
            centerLat + (latRange[1] - latRange[0]) / (2 * scale),
        ];

        // Calculate longitude and latitude based on click position
        const lon =
            adjustedLonRange[0] +
            (xPx / bb.width) * (adjustedLonRange[1] - adjustedLonRange[0]);
        const lat =
            adjustedLatRange[0] +
            (yPx / bb.height) * (adjustedLatRange[1] - adjustedLatRange[0]);

        // Display the coordinates
        outDiv.innerText = `Lat: ${lat.toFixed(5)}, Lon: ${lon.toFixed(5)}`;
        console.log("Coordinates:", lat, lon);
    });
}

clickOnMap();

```
