Mouse position on the layout

Hey, all!
I have a graph with 1 xaxis (timestamp) and 3 yaxis (power DB, Distance, Altitude).
Distancce and Altitude have one scatter plot each, and power DB has about 100 scatter plots.
So i cannot use hoverdata because it is messy and provide not usefull information.
I would like to capture mouse position according to all axis and provide popup with all 4 dimensions coordinates in real time.
To be more presice: i dont want to get this info from scatter plots points. i just need it according to layou, even if it is empty.

I’ve been trying to search for solution for last 2 days. And cannot find one.
Seems this should be able through some clientside callback.
Would appreciate some help!

Hey @katafalk2009 welcome to the community.

Could you add some information/code and/or explain your problem differently? I’m having problems to understand the issue.

Well i cannot share real graphs so i drew one. Hope this helps :slight_smile:
so i want to have this small popup with all axis info whereever my mouse is.

Something like this?

thank you for your reply!
ive seen that. it works fine on simple example. but for my purpose it seems not to be working well:

should i create 3 invisible scatters fully filled with points for every axis? what about timestamp?
also consider i have about 100 traces on my graph with many thousands points of real data. and it already is a bit slow.

Hello @katafalk2009,

Could you please post an example of the chart that you are wanting to know? If might be possible to add an event listener that can give you back the coordinates.

I actually don’t understand, how you want to manage the information shown in the hover. Unfortunately I don’t understand your use case.

well, i’ve drawn it on my picture

Actually, i may consider as a solution not to track it in real time, but at least create popup on mousewheel click.

Here is a version which will print the data to the console on a plotly chart when you mousewheel click:

from dash import *
import plotly.express as px


app = Dash(__name__)
df = px.data.tips()
fig = px.scatter(df, x="total_bill", y="tip", trendline="ols")

app.layout = html.Div([dcc.Graph(figure=fig, id='figure')])

app.clientside_callback("""
        (fig, id) => {
            setTimeout(() => {
                dragInfo = document.querySelector(`#${id} > .js-plotly-plot .nsewdrag`)
                plot = document.querySelector(`#${id} > .js-plotly-plot`)
                dragInfo.addEventListener('click', (event) => {
                    if ((event.which == 2 || event.button == 4 )) {
                        data = {x: event.layerX, y: event.y, height: dragInfo.getBoundingClientRect().height}
                        calcX = ((data.x - dragInfo.x.animVal.value)/dragInfo.attributes.width.value)
                        calcY = (1-((data.y - dragInfo.getBoundingClientRect().y)/data.height))
                        xLoc = (plot.layout.xaxis.range[1] - plot.layout.xaxis.range[0]) * calcX + plot.layout.xaxis.range[0]
                        yLoc = (plot.layout.yaxis.range[1] - plot.layout.yaxis.range[0]) * calcY + plot.layout.yaxis.range[0]
                        console.log(xLoc, yLoc)
                    }
                })
            }, 300)
            return window.dash_clientside.no_update
        }
    """,
    Output('figure', 'id'),
    Input('figure', 'figure'),
    State('figure', 'id'))

app.run(debug=True)

You need to alter your data accordingly, and this I believe will only work on a graph with just one subplot, multiple subplots would be a lot harder.

You can take the data and use it to display some hoverdata at that specific point. Probably be easier to add an element at that point then try to do it through Dash and the plotly chart.

4 Likes

holy borsch, thank you a lot! i will adapt it a bit and definitely use.

1 Like

for anyone who may search this in future, to track mouse movement instead of clicking just change event type

dragInfo.addEventListener('mousemove', (event) => {

and remove this

if ((event.which == 2 || event.button == 4 )) {

Correct, mousemove was a lot more code executing, and depending upon your use-case, would really bog things down. :slight_smile: