Plotly下拉交互时散点图水平中位数线未正确更新问题
问题解决:Plotly下拉切换Y轴后水平中位数线不更新
问题原因
你的下拉菜单仅更新了散点图的trace数据(x/y值、标题等),但水平中位数线是布局(layout)中的shape元素,而非trace数据,原代码没有在下拉切换时同步更新这部分内容,导致水平中线始终停留在初始变量的中位数。垂直中线正常是因为rows列的中位数固定不变。
修复代码
import pandas as pd import plotly.graph_objects as go def plot_dq_scatter_dropdown(df): fig = go.Figure() # 初始化默认视图 default_y = df.columns[1] median_x = df["rows"].median() median_y_default = df[default_y].median() # 添加初始散点 fig.add_trace(go.Scatter( x=df["rows"], y=df[default_y], mode='markers', marker=dict(color=df['outlier_prob'], colorscale='viridis', showscale=True, colorbar=dict(title='Outlier Probability')), hoverinfo='text', text=df.index, name=f'{default_y} vs rows', showlegend=False )) # 添加初始中位数线 fig.add_vline(x=median_x, line=dict(color="orange", dash="dash", width=2), annotation_text="Median rows", annotation_position="top left") fig.add_hline(y=median_y_default, line=dict(color="orange", dash="dash", width=2), annotation_text=f"Median {default_y}, {median_y_default}", annotation_position="top left") # 更新布局和下拉菜单 fig.update_layout( title=f"Scatter Plot: rows vs {default_y}", xaxis_title="rows", yaxis_title=default_y, autosize=True, updatemenus=[dict( type="dropdown", x=0.17, y=1.15, showactive=True, buttons=[ dict( label=f"{y}", method="update", args=[ # 更新散点trace数据 { 'y': [df[y]], 'x': [df["rows"]], 'marker': dict(color=df['outlier_prob'], colorscale='viridis', showscale=True, colorbar=dict(title='Outlier Probability')), 'name': f'{y} vs rows' }, # 更新布局:标题、Y轴标签、中位数线 { 'title': f"Scatter Plot: rows vs {y}", 'yaxis.title': y, # 重新生成中位数线的shape数组 'shapes': [ # 垂直中线(固定) dict( type='line', x0=median_x, x1=median_x, y0=0, y1=1, yref='paper', line=dict(color="orange", dash="dash", width=2) ), # 水平中线(随Y变量变化) dict( type='line', y0=df[y].median(), y1=df[y].median(), x0=0, x1=1, xref='paper', line=dict(color="orange", dash="dash", width=2) ) ], # 更新中位数线的注释 'annotations': [ dict( x=median_x, y=1, xref='x', yref='paper', text="Median rows", showarrow=False, xanchor='left', yanchor='bottom' ), dict( x=0, y=df[y].median(), xref='paper', yref='y', text=f"Median {y}, {df[y].median():.2f}", showarrow=False, xanchor='left', yanchor='bottom' ) ] } ] ) for y in df.columns if y not in ["rows", "outlier_prob"] ] )] ) fig.show() # 测试数据 df_input = pd.DataFrame({ 'rows': range(1, 101), 'column_a': [i + (i % 10) for i in range(1, 101)], 'column_b': [i * 2 for i in range(1, 101)], 'column_c': [i ** 0.5 for i in range(1, 101)], 'outlier_prob': [0.01 * (i % 10) for i in range(1, 101)] }) # 调用函数 plot_dq_scatter_dropdown(df_input)
关键修改点
- 手动定义中位数线的shape:
add_hline/add_vline本质是在fig.layout.shapes中添加元素,手动定义shape可以更灵活地在下拉切换时替换整个shapes数组。 - 下拉菜单同步更新布局的shapes和annotations:在每个按钮的
args第二个参数(布局更新)中,重新计算当前Y变量的中位数,生成新的水平中线shape和对应的注释文本。 - 固定垂直中线:因为
rows列的中位数固定,所以垂直中线的shape可以直接复用,无需重新计算。
内容的提问来源于stack exchange,提问作者PeCaDe
相关产品推荐
相关产品推荐

