Matplotlib图例可视化异常求助:折线图图例显示问题排查
Seaborn折线图图例异常问题排查
我用Seaborn绘制折线图时遇到图例异常,具体问题如下:
- 图例第2、4位置出现两个矩形
- 仅显示黑色、蓝色、红色三种线条,黄色和绿色线条未正常显示
- 已显示的三条线条颜色和代码中定义的不匹配
相关代码
var = 'eta_contraente' target = 'target_accettazione' DF = df_pred[[var,'target_accettazione','prediction_ret_1', 'prediction_ret_2', 'prediction_ret_3','prediction_ret_4_no_crawler']] DF['pred_decili'] = pd.qcut(DF[var], list(np.linspace(0, 1, n))) fig=plt.figure(figsize=(8, 5)) ax = fig.add_subplot(111) mean_val = DF.groupby("pred_decili").mean().reset_index() sns.lineplot(x=mean_val.index, y= target, data=mean_val, marker='s', color = 'black') sns.lineplot(x=mean_val.index, y= "prediction_ret_1", data=mean_val, marker='s', color = 'blue') sns.lineplot(x=mean_val.index, y= 'prediction_ret_2', data=mean_val, marker='s', color = 'red') sns.lineplot(x=mean_val.index, y= "prediction_ret_3", data=mean_val, marker='s', color = 'yellow') sns.lineplot(x=mean_val.index, y= 'prediction_ret_4_no_crawler', data=mean_val, marker='s', color = 'green') ax.set_xticks(mean_val.index) ax.set_xticklabels(mean_val[var].round(), rotation = 60) ax.legend([ 'black line', "blue line", "red line","yellow line","green line" ], loc='lower right', fontsize = 14);
问题截图

问题原因
这是代码使用方式错误导致的,和matplotlib/pandas版本无关。核心问题在于手动调用ax.legend()的逻辑:
- Seaborn的
lineplot默认会自动生成图例条目,手动传入自定义图例列表时,会和自动生成的条目冲突,出现重复矩形 - 手动指定图例时,未正确对应每个
lineplot返回的线条对象,导致颜色不匹配、部分线条图例丢失
解决方案
方案1:手动收集线条对象,精准对应图例
每次调用sns.lineplot时保存返回的线条对象,再将对象与自定义标签一一对应:
var = 'eta_contraente' target = 'target_accettazione' DF = df_pred[[var,'target_accettazione','prediction_ret_1', 'prediction_ret_2', 'prediction_ret_3','prediction_ret_4_no_crawler']] DF['pred_decili'] = pd.qcut(DF[var], list(np.linspace(0, 1, n))) fig=plt.figure(figsize=(8, 5)) ax = fig.add_subplot(111) mean_val = DF.groupby("pred_decili").mean().reset_index() # 保存每个lineplot返回的线条对象 line1 = sns.lineplot(x=mean_val.index, y=target, data=mean_val, marker='s', color='black') line2 = sns.lineplot(x=mean_val.index, y="prediction_ret_1", data=mean_val, marker='s', color='blue') line3 = sns.lineplot(x=mean_val.index, y='prediction_ret_2', data=mean_val, marker='s', color='red') line4 = sns.lineplot(x=mean_val.index, y="prediction_ret_3", data=mean_val, marker='s', color='yellow') line5 = sns.lineplot(x=mean_val.index, y='prediction_ret_4_no_crawler', data=mean_val, marker='s', color='green') ax.set_xticks(mean_val.index) ax.set_xticklabels(mean_val[var].round(), rotation=60) # 传入线条对象和对应标签 ax.legend([line1.lines[0], line2.lines[0], line3.lines[0], line4.lines[0], line5.lines[0]], ['black line', "blue line", "red line","yellow line","green line"], loc='lower right', fontsize=14)
方案2:用Seaborn的hue参数统一绘制(更简洁)
将数据整理成长格式,通过hue区分不同系列,自动生成正确图例:
var = 'eta_contraente' target = 'target_accettazione' DF = df_pred[[var,'target_accettazione','prediction_ret_1', 'prediction_ret_2', 'prediction_ret_3','prediction_ret_4_no_crawler']] DF['pred_decili'] = pd.qcut(DF[var], list(np.linspace(0, 1, n))) mean_val = DF.groupby("pred_decili").mean().reset_index() # 转换为长格式数据 mean_val_long = mean_val.melt(id_vars='pred_decili', value_vars=[target, "prediction_ret_1", 'prediction_ret_2', "prediction_ret_3", 'prediction_ret_4_no_crawler'], var_name='series', value_name='value') fig=plt.figure(figsize=(8, 5)) ax = fig.add_subplot(111) # 用hue区分系列,指定自定义颜色 sns.lineplot(x=mean_val_long.index, y='value', hue='series', data=mean_val_long, marker='s', palette={'target_accettazione':'black', 'prediction_ret_1':'blue', 'prediction_ret_2':'red', 'prediction_ret_3':'yellow', 'prediction_ret_4_no_crawler':'green'}) ax.set_xticks(mean_val.index) ax.set_xticklabels(mean_val[var].round(), rotation=60) # 自定义图例标签 handles, labels = ax.get_legend_handles_labels() ax.legend(handles, ['black line', "blue line", "red line","yellow line","green line"], loc='lower right', fontsize=14)
关键说明
- 方案1通过手动绑定线条对象与图例,彻底解决冲突问题
- 方案2是Seaborn推荐的用法,长格式数据+
hue参数能更高效地管理多系列绘图,代码更简洁不易出错
内容的提问来源于stack exchange,提问作者Francis
相关产品推荐
相关产品推荐

