MSalty
MSalty

Reputation: 4604

Change Color of an Entire Trace on Hover/Click in Plotly

I have the current figure in plotly (jupyter notebook code below), and was hoping to create the effect whereby when you hover or click over each trace, the whole trace is highlighted a different colour (in this example red). I tried implementing these examples from SOF: Plotly in Python: how to highlight a trace on hover? & How do I highlight an entire trace upon hover in Plotly for Python? with no luck. If anyone could help that would be amazing. Currently each trace remains lightgrey.

import plotly.graph_objects as go

teams_list = sorted(teams_list,key=str.lower)
default_linewidth = 2
highlighted_linewidth_delta = 2

fig = go.FigureWidget() 
f.layout.hovermode = 'closest'
f.layout.hoverdistance = -1 #ensures no "gaps" for selecting sparse data

for t in teams_list:
    fig.add_trace(go.Scatter(x=elo_all.index, 
                             y=elo_all[t],
                             name=t,
                             mode='lines',
                             text=elo_all['Round'], # hover text goes here
                             line={'width': default_linewidth, 'color':'lightgrey'}))

    
fig.update_layout(
    xaxis = dict(
        tickmode = 'array',
        tickvals = [0,29,58,87,117,146],
        ticktext = [2015,2016,2017,2018,2019,2020]
    )
)


# our custom event handler
def update_trace(trace, points, selector):
    # this list stores the points which were clicked on
    # in all but one event they it be empty
    if len(points.point_inds) > 0:
        for i in range( len(fig.data) ):
            fig.data[i]['line']['color'] = 'red'



# we need to add the on_click event to each trace separately       

for i in range(len(fig.data)):
    fig.data[i].on_hover(update_trace)

# show the plot
fig.show()

enter image description here

Upvotes: 4

Views: 4250

Answers (1)

MSalty
MSalty

Reputation: 4604

So this was a problem in 2 parts as it turns out:

  1. The problem for me was that the widgets extension had not been enabled correctly (as I could check from executing jupyter nbextension list, the output was empty), which is why the fig would not render without .show() and why the on_click function did not work. You can fix this by first checking jupyter nbextension list, if it’s empty can you try in your conda env:
jupyter nbextension enable --py widgetsnbextension
  1. I fixed my script above to the below which works perfectly, sadly I don't have a gif of it in action yet.
    import plotly.graph_objects as go
    
    teams_list = sorted(teams_list,key=str.lower)
    default_linewidth = 2
    highlighted_linewidth = 3
    
    fig = go.FigureWidget() # hover text goes here
    fig.layout.hovermode = 'closest'
    fig.layout.hoverdistance = -1 #ensures no "gaps" for selecting sparse data
    
    for t in teams_list:
        fig.add_trace(go.Scatter(x=elo_all.index, 
                                 y=elo_all[t],
                                 name=t,
                                 mode='lines',
                                 text=elo_all['Round'],
                                 opacity=0.3,
                                 line={'width': default_linewidth, 'color':'grey'}))
    
        
    fig.update_layout(
        xaxis = dict(
            tickmode = 'array',
            tickvals = [0,29,58,87,117,146],
            ticktext = [2015,2016,2017,2018,2019,2020]
        )
    )
    
    fig.update_yaxes(range=[1350, 1650])
    
    # our custom event handler
    def update_trace(trace, points, selector):
        if len(points.point_inds)==1:
            i = points.trace_index
            for x in range(0,len(fig.data)):
                fig.data[x]['line']['color'] = 'grey'
                fig.data[x]['opacity'] = 0.3
                fig.data[x]['line']['width'] = default_linewidth
            #print('Correct Index: {}',format(i))
            fig.data[i]['line']['color'] = 'red'
            fig.data[i]['opacity'] = 1
            fig.data[i]['line']['width'] = highlighted_linewidth
    
    # we need to add the on_click event to each trace separately       
    for x in range(0,len(fig.data)):
        fig.data[x].on_click(update_trace)
    
    # show the plot
    fig

Upvotes: 4

Related Questions