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

Seaborn分面直方图实现同行轴共享、跨列分箱共享且保留hue图例的方法

我尝试基于pd.DataFrame绘制一系列直方图,希望不同统计量(如下例中的fare)分布在不同行,不同类别(如下例中的class)分布在不同列,实现代码如下:

import seaborn as sns
from matplotlib import pyplot as plt

titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])
sns.displot(
    data=df,
    x="value",
    row="variable",
    col="class",
    hue="sex",
    facet_kws={"sharex": "row", "sharey": "row"},
)
plt.show()

运行效果示意图
但受common_bins=True参数影响,坐标轴会在所有行和列维度全局共享,不符合需求,因为不同行对应不同统计量,数值范围可能差异极大。设置common_bins=False后代码如下:

import seaborn as sns
from matplotlib import pyplot as plt

titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])
sns.displot(
    data=df,
    x="value",
    row="variable",
    col="class",
    hue="sex",
    facet_kws={"sharex": "row", "sharey": "row"},
    common_bins=False,
)
plt.show()

运行效果示意图
此时坐标轴仅在同一行内共享,适配不同数值范围的统计量,但分箱不再共享。我希望分箱可以跨列共享,至少在同一个直方图内共享,优先选择跨列共享的方案。
我也尝试直接调用sns.FacetGrid实现,但根据GitHub上的相关讨论,该场景下无法生成基于hue的图例。如下代码可以实现同行坐标轴共享、同一直方图内分箱共享,但无法生成hue对应的图例:

g = sns.FacetGrid(df, col="class", row="variable", sharex="row", sharey="row")
g.map_dataframe(sns.histplot, x="value",  hue="sex").add_legend()

运行效果示意图
请问有没有简单的方法可以同时实现同行坐标轴共享、分箱跨列共享,且保留基于hue的图例? 本质上就是要达到第三张图的效果,同时具备前两张图的图例,最好可以实现同一行内的分箱共享。


解决方案

最简方案(seaborn 0.11.0+版本支持)

common_bins参数不止支持布尔值,还可以直接指定分箱共享的维度,设置为"row"即可实现同一行跨列共享分箱、不同行独立分箱,同时原生保留hue图例:

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

titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])
sns.displot(
    data=df,
    x="value",
    row="variable",
    col="class",
    hue="sex",
    facet_kws={"sharex": "row", "sharey": "row"},
    common_bins="row", # 核心配置:按行维度共享分箱
)
plt.show()

旧版本兼容方案

如果你的seaborn版本较低,不支持common_bins传入维度参数,可以通过手动计算分箱+正确配置FacetGrid的hue参数实现:

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

titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])

# 按行维度(variable)预计算统一分箱
bins_map = {}
for var in df["variable"].unique():
    valid_data = df[df["variable"] == var]["value"].dropna()
    bins_map[var] = pd.cut(valid_data, bins=10, retbins=True)[1]

# 初始化FacetGrid时指定hue,解决图例不显示问题
g = sns.FacetGrid(df, col="class", row="variable", hue="sex", sharex="row", sharey="row")
# 绘图时传入对应行的统一分箱
g.map_dataframe(lambda data, **kw: sns.histplot(data, bins=bins_map[data["variable"].iloc[0]], **kw), x="value")
g.add_legend()

plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 21:06:06