You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib中如何保留折线图配色并自定义含分组信息的图例?

Matplotlib/Seaborn折线图图例分组归属与配色保留问题

问题描述

我在同一坐标轴上绘制了两组折线图,每组对应一个分组,包含代表两种条件的两条折线:Group 1使用Blues配色方案,Group 2使用Reds配色方案。自动生成的图例仅保留了各折线的配色,但缺失分组信息。

当尝试通过以下代码手动修改图例以添加分组归属时:

plt.legend(title='Legend', labels=['Group 1: C1', 'Group 1: C2', 'Group 2: C1', 'Group 2: C2'])

图例中的其中一组配色信息丢失。现寻求解决方法:如何在手动修改图例时保留两组折线的原有配色,或是否有其他方法在Matplotlib中为图例添加分组维度?

所用数据集:

data = {'group': [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2],
        'block': [1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3],
        'cond': ['c1', 'c2', 'c1', 'c2', 'c1', 'c2', 'c1', 'c2', 'c1', 'c2', 'c1', 'c2'],
        'value': [1, 2, 1.2, 2.1, 1.1, 2.2, 3, 4, 3.3, 4.1, 3.1, 4]}

原绘图代码:

sns.lineplot(data=df.loc[df['group'] == 1], x='block', y='value', hue='cond',
             palette='Blues', marker='o')

sns.lineplot(data=df.loc[df['group'] == 2], x='block', y='value', hue='cond',
             palette='Reds', marker='o')
plt.show()

解决方法

方法1:手动修正图例,保留原有配色

直接调用plt.legend()会重置整个图例,覆盖Seaborn生成的原有图例元素。正确做法是先获取当前图例的所有图形元素(handles),再修改标签:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame(data)

# 绘制两组折线
sns.lineplot(data=df.loc[df['group'] == 1], x='block', y='value', hue='cond',
             palette='Blues', marker='o')
sns.lineplot(data=df.loc[df['group'] == 2], x='block', y='value', hue='cond',
             palette='Reds', marker='o')

# 获取当前图例的handles(图形元素)
handles, _ = plt.gca().get_legend_handles_labels()
# 设置新的标签文本
new_labels = ['Group 1: C1', 'Group 1: C2', 'Group 2: C1', 'Group 2: C2']
# 更新图例,传入原handles和新labels
plt.legend(title='Legend', handles=handles, labels=new_labels)

plt.show()

方法2:通过组合列自动生成带分组的图例

先给数据集添加一个分组+条件的组合列,将分组和条件信息合并,再用这个列作为hue参数,并指定对应配色,Seaborn会自动生成包含分组信息的图例:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame(data)
# 创建分组与条件的组合列,格式化显示文本
df['group_cond'] = df.apply(lambda row: f"Group {row['group']}: {row['cond'].upper()}", axis=1)

# 自定义配色:Group1的C1/C2取Blues调色板的颜色,Group2取Reds调色板
palette = {
    'Group 1: C1': sns.color_palette('Blues')[2],
    'Group 1: C2': sns.color_palette('Blues')[4],
    'Group 2: C1': sns.color_palette('Reds')[2],
    'Group 2: C2': sns.color_palette('Reds')[4]
}

# 一次性绘制所有折线,用组合列作为hue
sns.lineplot(data=df, x='block', y='value', hue='group_cond',
             palette=palette, marker='o')

plt.legend(title='Legend')
plt.show()

方法3:构建嵌套分组图例

如果想要更清晰的分组展示(比如先按Group分类,再按Cond子分类),可以手动创建嵌套的Matplotlib图例:

import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.legend import Legend
import pandas as pd

df = pd.DataFrame(data)

# 分别绘制四条折线,并保存每个折线的对象
line1_c1, = sns.lineplot(data=df.loc[(df['group'] ==1) & (df['cond']=='c1')], 
                         x='block', y='value', color=sns.color_palette('Blues')[2], marker='o')
line1_c2, = sns.lineplot(data=df.loc[(df['group'] ==1) & (df['cond']=='c2')], 
                         x='block', y='value', color=sns.color_palette('Blues')[4], marker='o')
line2_c1, = sns.lineplot(data=df.loc[(df['group'] ==2) & (df['cond']=='c1')], 
                         x='block', y='value', color=sns.color_palette('Reds')[2], marker='o')
line2_c2, = sns.lineplot(data=df.loc[(df['group'] ==2) & (df['cond']=='c2')], 
                         x='block', y='value', color=sns.color_palette('Reds')[4], marker='o')

# 获取当前画布和坐标轴对象
fig, ax = plt.gcf(), plt.gca()

# 创建Group1的子图例
leg1 = Legend(ax, [line1_c1, line1_c2], ['C1', 'C2'], title='Group 1', 
              loc='upper left', bbox_to_anchor=(1, 1))
# 创建Group2的子图例
leg2 = Legend(ax, [line2_c1, line2_c2], ['C1', 'C2'], title='Group 2', 
              loc='upper left', bbox_to_anchor=(1, 0.7))

# 将子图例添加到坐标轴
ax.add_artist(leg1)
ax.add_artist(leg2)

plt.show()

内容的提问来源于stack exchange,提问作者Jorgo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:20:55