Search code examples
pythongraphplotly

how to add a vertical line to a graph by mouse position dynamically. In Plotly library


I have some graphs plotted on top of each other.

I would like to analyze a point in one of the graphs and then analyze the same point in the graph below.

For that I just want to add a vertical line at the mouse position in all the graphs.

I am using plotly https://plotly.com/ and dash library.

I saw a way to do that getting in the follow link:

https://community.plotly.com/t/capturing-mouse-events-position/4616/3

But it is too slow because I need to recreate all graphics all the time.

That is the code to add one line in one graph:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go

import numpy as np

x_data = np.linspace(0,500,500)
y_data = np.random.rand(500)
height = max(y_data)

app = dash.Dash()

app.layout = html.Div([
    dcc.Graph(id='basic_graph')])

@app.callback(dash.dependencies.Output('basic_graph', 'figure'),
              [dash.dependencies.Input('basic_graph', 'hoverData')])
def update_graph(hoverData):
    if not hoverData:
        x_value=x_data[250]
        opacity = 0
    else:
        x_value = hoverData['points'][0]['x']
        opacity = 0.8
    data = [go.Scatter(
                x=x_data,
                y=y_data,
                line={'color': '#235ebc'},
                opacity=0.8,
                name="Graph"
            ),
            go.Scatter(
                x=[x_value, x_value],
                y=[0, height],
                line={'color': '#a39999'},
                opacity=opacity,
                name='Moving Line')
            ]
    layout = go.Layout(
                xaxis={'type': 'linear', 'title': "Timestep"},
                yaxis={'type': 'linear', 'title': "Value"},
                margin={'l': 60, 'b': 40, 'r': 10, 't': 10},
                hovermode="False"
                )
    
    return {'data': data, 'layout': layout}

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

What is the best and fast way to do it using ploty without need recreate the graph all the time?

 The gree line is using showspikes=True, I need also the red

The ideia to work with:

fig.update_xaxes(
        #showspikes=True,
        #spikecolor="green",
        #spikesnap="cursor",
        #spikemode="across",
        #spikedash="solid",
        #)

Is pretty good , but just add line to one graph. i need that it appear in all graph simultaneously.


Solution

  • I think in your case you're looking for spike lines, no callback needed for that:

    Plotly supports "spike lines" which link a point to the axis on hover, and can be configured per axis.

    https://plotly.com/python/hover-text-and-formatting/

    Minimal example:

    import plotly.express as px
    
    df = px.data.gapminder().query("continent=='Oceania'")
    
    fig = px.line(df, x="year", y="lifeExp", color="country", title="Styled Spike Lines")
    fig.update_traces(mode="lines")
    fig.update_xaxes(
        showspikes=True,
        spikecolor="green",
        spikesnap="cursor",
        spikemode="across",
        spikedash="solid",
    )
    fig.show()
    

    The fig.show() call is for demo purposes, you would just need to pass the fig to the figure property of your Graph.