在Plotly(Python)折线图中实现悬停高亮(非Jupyter环境)
Plotly折线图悬停高亮整条轨迹(兼容PyCharm环境)
因为无法使用FigureWidget,我们可以通过注入自定义JavaScript回调来实现悬停时高亮对应轨迹的效果,以下是兼容px.line和go.Scatter的解决方案:
基于Plotly Express的实现
import plotly.express as px # 加载并筛选数据 df = px.data.gapminder() df = df[df['country'].isin(['Canada', 'USA', 'Norway', 'Sweden', 'Germany'])] # 创建折线图 fig = px.line(df, x='year', y='lifeExp', color='country') # 设置所有轨迹的初始样式:灰色、宽度3 fig.update_traces(line=dict(color='grey', width=3)) # 添加自定义JS实现悬停高亮 fig.update_layout( hovermode='x unified', id='hover-highlight-plot', # 给图表设置唯一ID,方便JS定位 # 注入隐藏的JS脚本处理悬停事件 template=dict( layout=dict( annotations=[ dict( text=f""" <script> document.addEventListener('DOMContentLoaded', function() {{ const plotDiv = document.getElementById('hover-highlight-plot'); const traceCount = {len(fig.data)}; // 悬停事件处理 plotDiv.on('plotly_hover', function(data) {{ const hoveredIndex = data.points[0].curveNumber; // 重置所有轨迹样式 Plotly.restyle(plotDiv, 'line.width', [3], Array.from({{length: traceCount}}, (_, i) => i)); Plotly.restyle(plotDiv, 'line.color', ['grey'], Array.from({{length: traceCount}}, (_, i) => i)); // 高亮当前悬停的轨迹 Plotly.restyle(plotDiv, 'line.width', [6], [hoveredIndex]); Plotly.restyle(plotDiv, 'line.color', [data.points[0].fullData.line.color], [hoveredIndex]); }}); // 离开悬停时恢复样式 plotDiv.on('plotly_unhover', function() {{ Plotly.restyle(plotDiv, 'line.width', [3], Array.from({{length: traceCount}}, (_, i) => i)); Plotly.restyle(plotDiv, 'line.color', ['grey'], Array.from({{length: traceCount}}, (_, i) => i)); }}); }}); </script> """, showarrow=False, xref="paper", yref="paper", x=0, y=0, xanchor="left", yanchor="bottom", font=dict(size=0) # 隐藏脚本文本 ) ] ) ) ) fig.show()
基于Plotly Graph Objects的实现
如果偏好使用go.Scatter,代码逻辑一致:
import plotly.graph_objects as go import plotly.express as px df = px.data.gapminder() df = df[df['country'].isin(['Canada', 'USA', 'Norway', 'Sweden', 'Germany'])] fig = go.Figure() # 逐个添加轨迹并设置初始样式 for country in df['country'].unique(): country_data = df[df['country'] == country] fig.add_trace(go.Scatter( x=country_data['year'], y=country_data['lifeExp'], name=country, line=dict(color='grey', width=3) )) # 复用相同的JS高亮逻辑 fig.update_layout( hovermode='x unified', id='hover-highlight-plot', template=dict( layout=dict( annotations=[ dict( text=f""" <script> document.addEventListener('DOMContentLoaded', function() {{ const plotDiv = document.getElementById('hover-highlight-plot'); const traceCount = {len(fig.data)}; plotDiv.on('plotly_hover', function(data) {{ const hoveredIndex = data.points[0].curveNumber; Plotly.restyle(plotDiv, 'line.width', [3], Array.from({{length: traceCount}}, (_, i) => i)); Plotly.restyle(plotDiv, 'line.color', ['grey'], Array.from({{length: traceCount}}, (_, i) => i)); Plotly.restyle(plotDiv, 'line.width', [6], [hoveredIndex]); Plotly.restyle(plotDiv, 'line.color', [data.points[0].fullData.line.color], [hoveredIndex]); }}); plotDiv.on('plotly_unhover', function() {{ Plotly.restyle(plotDiv, 'line.width', [3], Array.from({{length: traceCount}}, (_, i) => i)); Plotly.restyle(plotDiv, 'line.color', ['grey'], Array.from({{length: traceCount}}, (_, i) => i)); }}); }}); </script> """, showarrow=False, xref="paper", yref="paper", x=0, y=0, xanchor="left", yanchor="bottom", font=dict(size=0) ) ] ) ) ) fig.show()
效果说明
- 初始状态:所有折线为灰色,宽度3
- 悬停时:对应国家的折线会恢复原本的颜色,宽度增加到6,其余折线保持灰色窄线
- 离开悬停区域后,所有折线恢复初始样式
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

