Plotly Express散点图添加均值趋势线实现方法(含颜色匹配)
实现方案
Plotly Express 内置trendline参数目前仅支持OLS线性拟合、LOWESS局部加权拟合、滚动平均等预设趋势线,没有直接生成分组按维度分段均值线的内置选项,手动追加均值线的实现思路是可行的,以下是两种更简便、鲁棒性更强的优化写法,可避免手动匹配颜色带来的错位问题:
方案1:复用散点自动分配的配色
手动调用默认色板匹配颜色的写法存在隐患:如果自定义散点配色、分组数量超过默认色板长度、分组排序变动,很容易出现颜色错位。更稳妥的方式是绘制完散点后,直接从已生成的散点trace中读取对应分组的配色,无需手动维护色板映射。
注:原测试代码未导入plotly.graph_objects,直接运行会触发NameError,以下代码已补全依赖:
import plotly.express as px import plotly.graph_objects as go import pandas as pd df = pd.DataFrame({'date' : ['01/01/2022','01/01/2022','01/01/2022','01/01/2022','01/01/2022','01/01/2022', '02/01/2022','02/01/2022','02/01/2022','02/01/2022', '03/01/2022','03/01/2022','03/01/2022','03/01/2022'], 'value': [12,15,5,9,22,27,12,16,6,2,18,16,17,19], 'color' : ['yes','yes','yes','no','no','maybe', 'yes','no','no','yes', 'no','maybe','maybe','yes']}) df['date'] = pd.to_datetime(df['date']) fig = px.scatter(df, x="date", y="value", color='color') # 预计算各分组各日期的均值 mean_df = df.groupby(['color', 'date'], as_index=False)['value'].mean() # 遍历现有散点trace,直接复用其颜色绘制对应均值线 for trace in fig.data: group_name = trace.name group_mean = mean_df[mean_df['color'] == group_name] fig.add_trace( go.Scatter( name=f'{group_name} 均值', mode='lines', x=group_mean['date'], y=group_mean['value'], line_color=trace.marker.color, showlegend=True ) ) fig.show()
该写法不受自定义配色、分组数量变动影响,同组均值线和散点颜色永远保持一致。
方案2:预计算均值后一次性绘图(代码量最少)
无需手动循环追加trace,提前将原始数据和预计算的均值数据合并打标,直接调用Plotly Express接口一次性完成绘制,颜色、图例会自动完成同组匹配:
import plotly.express as px import pandas as pd df = pd.DataFrame({'date' : ['01/01/2022','01/01/2022','01/01/2022','01/01/2022','01/01/2022','01/01/2022', '02/01/2022','02/01/2022','02/01/2022','02/01/2022', '03/01/2022','03/01/2022','03/01/2022','03/01/2022'], 'value': [12,15,5,9,22,27,12,16,6,2,18,16,17,19], 'color' : ['yes','yes','yes','no','no','maybe', 'yes','no','no','yes', 'no','maybe','maybe','yes']}) df['date'] = pd.to_datetime(df['date']) df['data_type'] = '原始值' # 计算分组均值 mean_df = df.groupby(['color', 'date'], as_index=False)['value'].mean() mean_df['data_type'] = '均值' # 合并数据后一次性绘图 plot_df = pd.concat([df, mean_df]) fig = px.line( plot_df, x='date', y='value', color='color', line_dash='data_type', # 均值线自动设为虚线,和原始点做区分 markers={'原始值': True, '均值': False} # 原始值显示散点标记,均值仅显示折线 ) fig.show()
该写法无需手动处理trace和颜色映射,代码维护成本最低,可通过调整line_dash、markers参数自定义原始值和均值线的样式差异。
内容的提问来源于stack exchange,提问作者darkuss
相关产品推荐
相关产品推荐

