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
相关产品推荐
相关产品推荐

