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

如何将Seaborn kdeplot子图图例设为整个图表的全局图例?

Seaborn子图全局图例获取问题

问题说明

用Seaborn给子图画kdeplot(带hue参数)时,想做一个全局图例代替每个子图的单独图例,但调用ax.get_legend_handles_labels()得到的是空列表,没法靠原始数据重新做图例——颜色匹配没保障。复现代码如下:

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

# 构造包含hue列的测试数据
data = pd.DataFrame(
    {"A": np.random.random(20),
     "B": np.random.random(20),
     "C": ["c", "C"] * 10
    })

# 创建2行1列的子图
fig, [ax1, ax2] = plt.subplots(2, 1)

# 在两个子图上分别绘制kdeplot
sns.kdeplot(data=data, x="A", hue="C", ax=ax1)
ax2 = sns.kdeplot(data=data, x="B", hue="C", ax=ax2)

# 尝试从轴对象提取图例信息(结果为空列表)
handles_1, labels_1 = ax1.get_legend_handles_labels()
handles_2, labels_2 = ax2.get_legend_handles_labels()

# 尝试基于原始数据设置全局图例
fig.legend(labels=data["C"].unique(), loc="upper right")

# 尝试用提取的空数据设置全局图例
fig.legend(handles=handles_1, labels=labels_1, loc="center right")

# 显示调试信息
plt.suptitle(f"ax1 legend: {len(labels_1)}, ax2 legend: {len(labels_1)} labels")
plt.savefig("legend_issues.png")

运行后子图显示图例,但轴对象提取的handles和labels是空的,这不是bug,是找错了获取位置。

问题原因

Seaborn绘制带hue的图表时,会把自动生成的图例对象存在轴的legend_属性里,而不是matplotlib默认的图例容器中。get_legend_handles_labels()只能获取手动添加到轴的图例元素,读不到Seaborn存在legend_里的内容,所以返回空列表。

解决方法

方法1:从轴的legend_属性提取(最稳妥)

直接从子图的legend_属性里拿handles和labels,再创建全局图例,同时关掉子图自带的图例:

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

data = pd.DataFrame(
    {"A": np.random.random(20),
     "B": np.random.random(20),
     "C": ["c", "C"] * 10
    })

fig, [ax1, ax2] = plt.subplots(2, 1)

# 绘制子图
sns.kdeplot(data=data, x="A", hue="C", ax=ax1)
sns.kdeplot(data=data, x="B", hue="C", ax=ax2)

# 移除子图自带的图例
ax1.legend_.remove()
ax2.legend_.remove()

# 从任意一个子图的legend_中提取图例元素
handles, labels = ax1.legend_.get_handles_labels()

# 创建全局图例
fig.legend(handles=handles, labels=labels, loc="upper right")

plt.suptitle("全局图例已正确生成")
plt.savefig("global_legend.png")
plt.show()

方法2:绘图时关闭子图图例,直接复用绘图元素

如果绘图时设置legend=False,可以直接从轴的线条/填充元素提取,再创建全局图例:

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

data = pd.DataFrame(
    {"A": np.random.random(20),
     "B": np.random.random(20),
     "C": ["c", "C"] * 10
    })

fig, [ax1, ax2] = plt.subplots(2, 1)

# 绘制子图时关闭自带图例
sns.kdeplot(data=data, x="A", hue="C", ax=ax1, legend=False)
sns.kdeplot(data=data, x="B", hue="C", ax=ax2, legend=False)

# 从第一个子图提取线条和填充元素(对应hue的类别)
handles = ax1.lines + ax1.patches
labels = data["C"].unique()

# 创建全局图例
fig.legend(handles=handles, labels=labels, loc="upper right")

plt.suptitle("全局图例已正确生成")
plt.savefig("global_legend_2.png")
plt.show()

注意要点

  • 只要所有子图的hue类别一致,从任意一个子图提取图例元素即可
  • 一定要移除子图自带的图例,避免重复显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:55:42