我有一个数据框,我正在使用 sns.histplot 绘制约 9 个子图。我不希望这个人物有 9 个图例。我想要整个人物的 1 个图例,因为无论如何大多数图例都是相同的。然而,由于并非所有子图都 100% 相同(有些子图有额外的“裁剪”或缺少一个),所以我不能简单地删除除 1 之外的所有图例。
我能够对 sns.barplot 执行此操作,但相同的代码行似乎不适用于 sns.histplot (并且这些数据需要使用 sns.histplot 进行绘制)。
我下面有一些虚拟代码可以修改。我注释掉了我的行
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# Create a dummy DataFrame with random data
crops = [
"apple",
"banana",
"orange",
"potato",
"zucchini",
"kale",
"strawberry",
"raspberry",
"turnip",
"onion",
]
farms = [
"n",
"s",
"e",
"w",
]
np.random.seed(42)
n_samples = 100
counts = np.random.randint(1, 200, size=n_samples)
choices = np.random.choice(crops, size=n_samples)
locations = np.random.choice(farms, size=n_samples)
df = pd.DataFrame({"counts": counts, "crops": choices, "farms": locations})
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
h = [] # Initialize an empty list to collect handles
l = [] # Initialize an empty list to collect labels
rowindex = [0, 0, 1, 1]
colindex = [0, 1, 0, 1]
selection = ["farms == 'n'", "farms == 's'", "farms == 'e'", "farms == 'w'"]
for row, col, sele in zip(rowindex, colindex, selection):
g = sns.histplot(
data=df.query(sele),
x="counts",
kde=True,
stat="count",
hue="crops", # Add the hue parameter
ax=axes[row, col],
)
handles, labels = g.get_legend_handles_labels()
h.extend(handles)
l.extend(labels)
axes[row, col].get_legend().remove() # Remove individual legends from subplots
# Create a single legend for the entire figure
by_label = dict(zip(l, h))
g.legend(by_label.values(), by_label.keys(), bbox_to_anchor=(0.9,0.65), loc='upper right')
plt.show()
通过以下几行,我尝试收集每个子图中的所有图例并将其放入handles[]和labels[]中,然后将其转换为字典(以删除重复的条目)。我尝试过
g.get_legend_handles_labels()
和 axes[row,col].get_legend_handles_labels()
,以及 fig.
、ax.
,但是当我打印手柄和标签的内容时,每个东西都变成空的。我真的很困惑,因为这确实适用于 sns.barplot (但也许他们对艺术家的定义不同?或者以不同的方式存储它们?)。
handles, labels = g.get_legend_handles_labels()
h.extend(handles)
l.extend(labels)
axes[row, col].get_legend().remove() # Remove individual legends from subplots
# Create a single legend for the entire figure
by_label = dict(zip(l, h))
g.legend(by_label.values(), by_label.keys(), bbox_to_anchor=(0.9,0.65), loc='upper right')
将这些行注释掉,这就是情节:
代码中的这些行,我没有得到图例:
理想情况下,我有 1 个图例(在图之外),其中所有“作物”都列出一次(顺序并不重要)。有谁知道我做错了什么?
如前所述,这适用于 sns.barplot。如果将
g =
位更改为:
g = sns.barplot(
data=df.query(sele),
x="counts",
y="counts",
hue="crops", # Add the hue parameter
ax=axes[row, col],
)
保持其余部分相同,然后我得到如下图所示的图形,这基本上就是我想要的:1 个图例,其中所有“作物”仅列出一次,并带有各自的标签标记。所以它必须可以通过 sns.histplot ....对吗?
创建此类图的推荐方法是使用“图形级别”版本的图。对于
sns.histplot()
,这是 sns.displot(kind='hist', ...)
。
请注意,
sns.histplot()
返回已创建绘图的子图(ax
),而sns.displot()
返回FacetGrid
,即子图网格。 使用图形级函数时,不应创建图形或轴。
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
# Create a dummy DataFrame with random data
crops = ["apple", "banana", "orange", "potato", "zucchini", "kale", "strawberry", "raspberry", "turnip", "onion"]
farms = ["n", "s", "e", "w"]
np.random.seed(42)
n_samples = 100
counts = np.random.randint(1, 200, size=n_samples)
choices = np.random.choice(crops, size=n_samples)
locations = np.random.choice(farms, size=n_samples)
df = pd.DataFrame({"counts": counts, "crops": choices, "farms": locations})
g = sns.displot(kind='hist', data=df, x="counts", hue="crops", col="farms", col_wrap=2)
plt.show()