Plotly散点图实现双下拉菜单切换数据及动态相关性标注
问题根源
你的代码中按钮配置里的相关性标注是在生成按钮的循环阶段就提前计算完成的,取值永远是初始化时x=A、y=A的计算结果,所有按钮的标注参数从生成时就是固定值,自然不会随点击动态更新。Plotly的静态updatemenus配置是预定义所有点击后要更新的参数,不会在点击时实时执行Python函数读取当前图表的x/y数据。
解决方案1:使用ipywidgets实现(Jupyter环境适用)
这种方案逻辑最贴合你原本的思路,每次下拉选择后都会实时计算最新的相关性,代码改动量小:
import pandas as pd import numpy as np import plotly.graph_objects as go from scipy import stats from ipywidgets import interact, Dropdown # 准备随机数据 data = pd.DataFrame(dict( A=np.random.randint(11, size=10), B=np.random.randint(11, size=10), C=np.random.randint(11, size=10), D=np.random.randint(11, size=10) )) def corr_annotation(x, y): pearsonr = stats.pearsonr(x, y) return 'r = {:.2f} (p = {:.3f})'.format(pearsonr[0], pearsonr[1]) # 初始化图表 fig = go.FigureWidget() fig.add_trace(go.Scatter( x=data['A'], y=data['A'], mode='markers', )) fig.add_annotation(dict( text=corr_annotation(data['A'], data['A']), showarrow=False, yref='paper', xref='paper', x=0.99, y=0.95 )) # 定义下拉回调函数 def update_plot(x_col, y_col): with fig.batch_update(): fig.data[0].x = data[x_col] fig.data[0].y = data[y_col] fig.layout.annotations[0].text = corr_annotation(data[x_col], data[y_col]) # 生成下拉菜单 x_drop = Dropdown(options=data.columns, value='A', description='X轴:') y_drop = Dropdown(options=data.columns, value='A', description='Y轴:') interact(update_plot, x_col=x_drop, y_col=y_drop) # 显示图表 fig
解决方案2:纯Plotly静态实现(可导出为独立HTML)
如果需要生成不需要Python内核也能运行的HTML图表,可预生成所有x/y列组合的散点轨迹和对应标注,通过按钮控制轨迹显隐实现联动:
import pandas as pd import numpy as np import plotly.graph_objects as go from scipy import stats # 准备随机数据 data = pd.DataFrame(dict( A=np.random.randint(11, size=10), B=np.random.randint(11, size=10), C=np.random.randint(11, size=10), D=np.random.randint(11, size=10) )) def corr_annotation(x, y): pearsonr = stats.pearsonr(x, y) return 'r = {:.2f} (p = {:.3f})'.format(pearsonr[0], pearsonr[1]) # 预生成所有列组合的轨迹和标注 cols = data.columns.tolist() traces = [] annotations = [] for x_col in cols: for y_col in cols: traces.append(go.Scatter( x=data[x_col], y=data[y_col], mode='markers', visible=(x_col=='A' and y_col=='A') )) annotations.append(dict( text=corr_annotation(data[x_col], data[y_col]), showarrow=False, yref='paper', xref='paper', x=0.99, y=0.95 )) # 初始化图表 fig = go.Figure(data=traces) fig.layout.annotations = [annotations[0]] # 生成按钮 x_buttons = [] for idx, x_col in enumerate(cols): visible_mask = [False]*len(traces) for y_idx in range(len(cols)): visible_mask[idx*len(cols)+y_idx] = True x_buttons.append(dict( method='update', label=x_col, args=[ {'visible': visible_mask}, {'annotations': [annotations[i] for i, v in enumerate(visible_mask) if v]} ] )) y_buttons = [] for idx, y_col in enumerate(cols): visible_mask = [False]*len(traces) for x_idx in range(len(cols)): visible_mask[x_idx*len(cols)+idx] = True y_buttons.append(dict( method='update', label=y_col, args=[ {'visible': visible_mask}, {'annotations': [annotations[i] for i, v in enumerate(visible_mask) if v]} ] )) # 更新布局 fig.update_layout( updatemenus=[ dict(buttons=x_buttons, direction='up', x=0.5, y=-0.1), dict(buttons=y_buttons, direction='right', x=-0.01, y=0.5) ] ) fig.show()
内容的提问来源于stack exchange,提问作者danpl
相关产品推荐
相关产品推荐

