Black Lives Matter. Please consider donating to Black Girls Code today.

Highlighting the plot (change of colour or size etc) on 1 graph when I hover on 2nd graph's plot

Hi I have 2 graphs.

1st graph : Gps plots. (x-axis : Longitude, Y-axis: Latitude, text: Time in seconds)

2nd graph : some analysis plot (x-axis : Time in seconds)

When I hover on the plot of 2nd graph, plot on 1st graph with same value (text: Time in seconds) should be highlighted. Below is the code block and the figure with 2 graphs.

Please assist me with this.

def plot_map(self):

app = dash.Dash()
df = pd.read_csv(‘csv_files\combine.csv’)
df.head()

time = df[‘time’]
rasp_time = df[‘rasp_time’]
latitude = df[‘latitude’]
longitude = df[‘longitude’]

data = [
go.Scattermapbox(
lat=latitude,
lon=longitude,
text=rasp_time,
mode=‘markers’,
marker=dict(size=8))
]

layout = go.Layout(
autosize=True,
hovermode=‘closest’,
mapbox=dict(
bearing=0,
accesstoken=mapbox_access_token,
center=dict(lat=48.5069, lon=9.2038),
pitch=0,
zoom=12.5)
)

data2 = [{‘x’: time, ‘y’: rasp_time}]
layout2 = go.Layout(autosize=True, hovermode=‘closest’)

fig = dict(data=data, layout=layout)
fig2 = dict(data=data2, layout=layout2)

app.layout = html.Div([
dcc.Graph(id=‘graph’, figure=fig),
dcc.Graph(id=‘sa’, figure=fig2)
])

app.run_server(debug=True)

You can use the hover event with dash.dependencies.Event to make a callback, the information about the data which is hovered is available in the hoverData attribute of the dcc.Graph component. I am not sure if there is an automated way to higlight a point on the Scattermapbox, what I would do is draw another line which only has one point with a different color

from dash.dependencies import Input, Output, State, Event

@app.callback(
    Output('sa', 'figure'),
    [],
    [
        State('graph', 'figure'),
        State('sa', 'figure'),
        State('graph', 'hoverData'),
    ],
    [
        Event('graph', 'hover')
    ]
)
def update_graph(fig1, fig2, data):

    print(data)
    print(fig2)

   # use information contained within data to highlight the point within fig2

    return fig2

hope it helps

grafik

Could you please check if the above code is right. I am new to dash and plotly and don’t even to know to update the graph too…

Output here specifies for which one of the two dcc.Graph the prop figure will be modified, so you should not create more components within the callback, but use the id of the components you created earlier.

I would suggest reading https://dash.plot.ly/getting-started-part-2 for more information on callbacks :slight_smile:

Let me know if you need more help then

1 Like

Here is an example

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State, Event

app = dash.Dash(__name__)
server = app.server
app.config.suppress_callback_exceptions = False
app.scripts.config.serve_locally = True

x = np.arange(1, 10, 1)
data = [
    go.Scatter(
        x=x,
        y=x**2,
        mode='lines+markers',
        name='curve 1',
        line={
            'color': '#EF553B',
            'width': 2
        }
    ),
    go.Scatter(
        x=x,
        y=x,
        mode='lines+markers',
        name='curve 2',
        line={
            'color': 'blue',
            'width': 2
        }
    )
]

data2 = [
    go.Scatter(
        x=x,
        y=x**2,
        mode='lines+markers',
        name='curve 1',
        line={
            'color': '#EF553B',
            'width': 2
        }
    ),
    go.Scatter(
        x=x,
        y=x,
        mode='lines+markers',
        name='curve 2',
        line={
            'color': 'blue',
            'width': 2
        }
    ),
    go.Scatter(
        x=[],
        y=[],
        mode='markers',
        name='highlight',
        marker={
            'color': 'black',
            'size': 15
        },
        showlegend=False
    )
]

layout = go.Layout(
    autosize=True,
    hovermode="closest",
)

fig = dict(data=data, layout=layout)
fig2 = dict(data=data2, layout=layout)

app.layout = html.Div(
    [
        dcc.Graph(
            id='graph1',
            figure=fig,
            hoverData=None,
            clear_on_unhover=True
        ),
        dcc.Graph(
            id='graph2',
            figure=fig2,
            hoverData=None
        )
    ]
)


@app.callback(
    Output('graph2', 'figure'),
    [],
    [
        State('graph2', 'figure'),
        State('graph1', 'hoverData'),
    ],
    [
        Event('graph1', 'hover'),
        Event('graph1', 'unhover')
    ]
)
def update_graph(fig2, data):

    if data is not None:
        # get the information about the hover point
        hover_curve_idx = data['points'][0]['curveNumber']
        hover_pt_idx = data['points'][0]['pointIndex']
        data_to_highlight = fig2['data'][hover_curve_idx]

        # change the last curve which is reserved for highlight
        fig2['data'][-1]['x'] = [data_to_highlight['x'][hover_pt_idx]]
        fig2['data'][-1]['y'] = [data_to_highlight['y'][hover_pt_idx]]

    else:
        fig2['data'][-1]['x'] = []
        fig2['data'][-1]['y'] = []

    return fig2

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

1 Like

Thank you so much :slight_smile: Will try this example and let you know once I succeed with my implementations

Just to note here, we’re trying to move away from the Event pattern. Instead, you should be able to just set hoverData as an Input: [Input('graph1', 'hoverData').

We also have a section that is dedicated to graph highlighting. It’s part 5 of the Dash Tutorial https://dash.plot.ly/interactive-graphing (and I recommend going through each section of the tutorial).

1 Like

It worked. Thanks alot both of you :slight_smile:

Hello, and sorry for reviving this old thread, but I need help. :slight_smile: From the description, the code should do exactly what I need, but it doesn’t work as written because the Event pattern is no longer available. If I try to change that part of the code to a single Input like chriddyp suggests, I get the following error message:

TypeError: callback() takes from 2 to 4 positional arguments but 5 were given

Could someone please help me out and post an updated version of the code? Thanks in advance.

Event is outdated, it would be nice to have a state-of-the-art working example.