Coordinating a Dash line chart with Mapbox graph

I am trying to visualize workout data and I’ve uploaded some .fit files from my fitness watch. I have 2 graphs: a line plot containing speed, heart rate, running power, etc… and a Mapbox graph containing GPS coordinates.

I would like to be able to hover over parts of the heart rate line plot, then see which coordinate that part is associated with. Is there a way to coordinate the 2 charts together? Preferably without having to use the Mapbox API multiple times (don’t want to overuse my license)?

This is what it looks like so far:

I want to follow the GPS coordinates as I hover over the top line chart (and vice versa).

Code is here: https://github.com/vzeddie/fit-data-comparer/blob/feature/mapbox/run.py#L298

Hovering the map and getting the hover on the cartesian graph is definitely doable, see my post here. It might be doable to have the reverse as well I have not tried it.

Thank you! That really helps and I’ve used your code to do what I had set out to do.

I’m now looking at how to do the reverse (metrics graph hover → mapbox hover). Would you have any leads on how to do this? I’ve looked at a bunch of previous community posts and codepens but I can’t find a way that utilizes Python- only pure JS. I reckon you would set curveNumber and pointNumber (Hover Events | JavaScript | Plotly) but I’m not sure what the first parameter in Plotly.Fx.hover() is. I keep getting the error _uid is undefined when I set the first parameter to the id of my Mapbox graph. I can’t find documentation on what each parameter means too.

Try this:

Plotly.Fx.hover(graph_id, {curveNumber: curveNumber, pointNumber:pointNumber}, "mapbox")

It doesn’t seem to work. This is what it looks like:

This is my HTML layout:

    app.layout = html.Div(id="outer_div", children=[
        dcc.Markdown('\n'.join(loaded_files_markdown)),
        dcc.Checklist(
            id = "yaxes_selection",
            options = [ {"label": x, "value": x} for x in yaxes ],
            value = ["speed"],
            labelStyle={"display": "inline-block"}
        ),
        dcc.Dropdown(
            id = "xaxis_selection",
            options = [ {"label": x, "value": x} for x in xaxes ],
            value = ["rel_time"]
        ),
        dcc.Graph(id="metrics_graph"),
        html.P(id="yaxes_warning", children=["OK"]),
        dcc.Graph(id="mapbox_graph"),
        html.Div(id="metrics_dummy"),
        html.Div(id="mapbox_dummy")
    ])

This is my callback (I used 2 hovers just to see if any of them would work without having to reload):

    app.clientside_callback(
        """
        function(hoverData){
            var myPlot = document.getElementById("mapbox_graph")

            if (!myPlot.children[1]) {
                return window.dash_clientside.no_update
            }
            myPlot.children[1].id = "mapbox_js"

            if (hoverData) {
                console.log(hoverData)
                Plotly.Fx.hover("mapbox_graph", {curveNumber:1, pointNumber:100}, "mapbox_graph")
                Plotly.Fx.hover("mapbox_graph", {curveNumber:1, pointNumber:100}, "mapbox")
            }
            console.log("AAAA")
            return window.dash_clientside.no_update
        }
        """,
        Output("mapbox_dummy", "data-hover"),
        [Input("metrics_graph", "hoverData")],
    )

I hardcoded curveNumber and pointNumber just to see if it would work but nada. What’s the difference between argument 1 and argument 3?

The first argument should be "mapbox_js" which is the one you define above.

The third argument is the type of graph you’re trying to hover on. The default value is "xy" for cartesian graphs.

That really helps! I could not figure out what that 3rd argument was. I must’ve missed that permutation :stuck_out_tongue:

I’m getting a different error:

I’ll try to figure this one out. Looks like with your help, I’m at least getting closer to the intended behavior. Thank you very much!

I found this thread almost a year later while running into the same problem…

The following unfortunately does not work on the map. It creates a single hover label and a some point but not the one specified with pointNumber.

Plotly.Fx.hover(graph_id, {curveNumber: curveNumber, pointNumber:pointNumber}, "mapbox")

With this, i.e. second arg as an array, i also get the error shown in the pic above (Invalid LngLat object)

Plotly.Fx.hover(graph_id, [{curveNumber: curveNumber, pointNumber:pointNumber}], "mapbox")

Anyone has a solution here?
Unfortunately i cannot hover via xval/yval since my coords are not unique, so matching the point only via coords is not enough.