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.

1 Like

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")
1 Like

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.

1 Like

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.