import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import numpy as np
# 创建 Dash 应用
app = dash.Dash(__name__)
# 生成随机数据(1000组)
np.random.seed(42)
n_groups = 1000
n_points = 50
X = np.linspace(0, 10, n_points)
Y = np.random.randn(n_groups, n_points).cumsum(axis=1)
colors = ['rgba(255,0,0,0.1)' for _ in range(n_groups)] # 初始透明度为0.1
labels = [f'Line {i}' for i in range(n_groups)]
# 预生成所有轨迹
traces = [
go.Scattergl(
x=X,
y=Y[i],
mode='lines',
name=labels[i],
line=dict(color=colors[i], width=1),
hoverinfo='name+x+y',
opacity=0.1 # 初始透明度
) for i in range(n_groups)
]
# 创建初始图表
def create_figure():
fig = go.Figure(data=traces)
fig.update_layout(
title='多组折线图 - 悬停高亮',
xaxis_title='X轴',
yaxis_title='Y轴',
hovermode='closest',
showlegend=False,
template='plotly_white'
)
return fig
app.layout = html.Div([
dcc.Graph(
id='line-plot',
figure=create_figure()
),
dcc.Store(id='last-highlighted', data=None) # 用于存储上一次高亮的线索引
])
@app.callback(
Output('line-plot', 'restyleData'),
Output('last-highlighted', 'data'),
Input('line-plot', 'hoverData'),
State('last-highlighted', 'data')
)
def highlight_line(hover_data, last_highlighted):
if hover_data and hover_data.get('points'):
# 获取当前悬停的线索引
curve_number = hover_data['points'][0]['curveNumber']
# 如果当前悬停的线和上一次高亮的线相同,则不更新
if curve_number == last_highlighted:
return dash.no_update, dash.no_update
# 增量更新:只更新当前悬停的线和上一次高亮的线
restyle_data = []
trace_indices = []
# 恢复上一次高亮的线
if last_highlighted is not None:
print(">> last_highlighted", last_highlighted)
restyle_data.extend([
{'opacity': [0.1]},
{'line.width': [1]},
{'line.color': ['rgba(255,0,0,0.1)']}
])
trace_indices.append(last_highlighted)
# 高亮当前悬停的线
restyle_data.extend([
{'opacity': [1.0]},
{'line.width': [100]},
{'line.color': ['blue']}
])
trace_indices.append(curve_number)
# 返回增量更新的数据和当前高亮的线索引
print(">> curve_number", curve_number)
return (restyle_data, trace_indices), curve_number
else:
# 如果没有悬停数据,恢复上一次高亮的线
if last_highlighted is not None:
return [
{'opacity': [0.1]},
{'line.width': [1]},
{'line.color': ['rgba(255,0,0,0.1)']}
], [last_highlighted], None
else:
return dash.no_update, dash.no_update
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0', port=8050)
I wrote a callback to change the line to blue when hovering , and only updating the last and the current hovering line to save costs, but why doesn’t it work? The following is the output log, which shows that the line width and color of the hovering line have been modified.
>> last_highlighted 24
>> curve_number 550
>> restyle_data [{'opacity': [0.1]}, {'line.width': [1]}, {'line.color': ['rgba(255,0,0,0.1)']}, {'opacity': [1.0]}, {'line.width': [100]}, {'line.color': ['blue']}]
>> trace_indices [24, 550]
>> last_highlighted 550
>> curve_number 360
>> restyle_data [{'opacity': [0.1]}, {'line.width': [1]}, {'line.color': ['rgba(255,0,0,0.1)']}, {'opacity': [1.0]}, {'line.width': [100]}, {'line.color': ['blue']}]
>> trace_indices [550, 360]
>> last_highlighted 360
>> curve_number 467
>> restyle_data [{'opacity': [0.1]}, {'line.width': [1]}, {'line.color': ['rgba(255,0,0,0.1)']}, {'opacity': [1.0]}, {'line.width': [100]}, {'line.color': ['blue']}]
>> trace_indices [360, 467]
>> last_highlighted 467
>> curve_number 513
>> restyle_data [{'opacity': [0.1]}, {'line.width': [1]}, {'line.color': ['rgba(255,0,0,0.1)']}, {'opacity': [1.0]}, {'line.width': [100]}, {'line.color': ['blue']}]
>> trace_indices [467, 513]
>> last_highlighted 513
>> curve_number 350
>> restyle_data [{'opacity': [0.1]}, {'line.width': [1]}, {'line.color': ['rgba(255,0,0,0.1)']}, {'opacity': [1.0]}, {'line.width': [100]}, {'line.color': ['blue']}]
>> trace_indices [513, 350]