在 matplotlib、seaborn 中为多个绘图创建单个图例
Create a single legend for multiple plot in matplotlib, seaborn
我正在使用 "iris.csv" 数据制作箱线图。我试图通过测量(即花瓣长度、花瓣宽度、萼片长度、萼片宽度)将数据分成多个数据框,然后在 forloop 上制作箱线图,从而添加子图。
最后,我想一次为所有箱形图添加一个通用图例。但是,我做不到。我已经使用几个 Whosebug 问题尝试了几个教程和方法,但我无法修复它。
这是我的代码:
import seaborn as sns
from matplotlib import pyplot
iris_data = "iris.csv"
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class']
dataset = read_csv(iris_data, names=names)
# Reindex the dataset by species so it can be pivoted for each species
reindexed_dataset = dataset.set_index(dataset.groupby('class').cumcount())
cols_to_pivot = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width']
# empty dataframe
reshaped_dataset = pd.DataFrame()
for var_name in cols_to_pivot:
pivoted_dataset = reindexed_dataset.pivot(columns='class', values=var_name).rename_axis(None,axis=1)
pivoted_dataset['measurement'] = var_name
reshaped_dataset = reshaped_dataset.append(pivoted_dataset, ignore_index=True)
## Now, lets spit the dataframe into groups by-measurements.
grouped_dfs_02 = []
for group in reshaped_dataset.groupby('measurement') :
grouped_dfs_02.append(group[1])
## make the box plot of several measured variables, compared between species
pyplot.figure(figsize=(20, 5), dpi=80)
pyplot.suptitle('Distribution of floral traits in the species of iris')
sp_name=['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
setosa = mpatches.Patch(color='red')
versi = mpatches.Patch(color='green')
virgi = mpatches.Patch(color='blue')
my_pal = {"Iris-versicolor": "g", "Iris-setosa": "r", "Iris-virginica":"b"}
plt_index = 0
# for i, df in enumerate(grouped_dfs_02):
for group_name, df in reshaped_dataset.groupby('measurement'):
axi = pyplot.subplot(1, len(grouped_dfs_02), plt_index + 1)
sp_name=['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
df_melt = df.melt('measurement', var_name='species', value_name='values')
sns.boxplot(data=df_melt, x='species', y='values', ax = axi, orient="v", palette=my_pal)
pyplot.title(group_name)
plt_index += 1
# Move the legend to an empty part of the plot
pyplot.legend(title='species', labels = sp_name,
handles=[setosa, versi, virgi], bbox_to_anchor=(19, 4),
fancybox=True, shadow=True, ncol=5)
pyplot.show()
剧情如下:
如何在主图中添加一个普通的图例,在主图之外,在"main suptitle"旁边?
要定位图例,重要的是设置 loc
参数作为锚点。 (默认的 loc
是 'best'
,这意味着您事先不知道它会在哪里结束)。位置是从0,0
(当前斧头的左下角)到1,1
:当前斧头的左上角。这不包括标题等的填充,因此值可能会超出 0, 1
范围。 "current ax" 是最后激活的。
请注意,除了 plt.legend
(使用轴),您还可以使用 plt.gcf().legend
,它使用 "figure"。然后,坐标为完整图左下角的0,0
(即"figure")和右上角的1,1
。缺点是不会为图例创建额外的 space,因此您需要手动设置顶部填充(例如 plt.gcf().subplots_adjust(top=0.8)
)。一个缺点是您不能再使用 plt.tight_layout()
,并且很难将图例与轴对齐。
import seaborn as sns
from matplotlib import pyplot as plt
from matplotlib import patches as mpatches
import pandas as pd
dataset = sns.load_dataset("iris")
# Reindex the dataset by species so it can be pivoted for each species
reindexed_dataset = dataset.set_index(dataset.groupby('species').cumcount())
cols_to_pivot = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
# empty dataframe
reshaped_dataset = pd.DataFrame()
for var_name in cols_to_pivot:
pivoted_dataset = reindexed_dataset.pivot(columns='species', values=var_name).rename_axis(None, axis=1)
pivoted_dataset['measurement'] = var_name
reshaped_dataset = reshaped_dataset.append(pivoted_dataset, ignore_index=True)
## Now, lets spit the dataframe into groups by-measurements.
grouped_dfs_02 = []
for group in reshaped_dataset.groupby('measurement'):
grouped_dfs_02.append(group[1])
## make the box plot of several measured variables, compared between species
plt.figure(figsize=(20, 5), dpi=80)
plt.suptitle('Distribution of floral traits in the species of iris')
sp_name = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
setosa = mpatches.Patch(color='red')
versi = mpatches.Patch(color='green')
virgi = mpatches.Patch(color='blue')
my_pal = {"versicolor": "g", "setosa": "r", "virginica": "b"}
plt_index = 0
# for i, df in enumerate(grouped_dfs_02):
for group_name, df in reshaped_dataset.groupby('measurement'):
axi = plt.subplot(1, len(grouped_dfs_02), plt_index + 1)
sp_name = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
df_melt = df.melt('measurement', var_name='species', value_name='values')
sns.boxplot(data=df_melt, x='species', y='values', ax=axi, orient="v", palette=my_pal)
plt.title(group_name)
plt_index += 1
# Move the legend to an empty part of the plot
plt.legend(title='species', labels=sp_name,
handles=[setosa, versi, virgi], bbox_to_anchor=(1, 1.23),
fancybox=True, shadow=True, ncol=5, loc='upper right')
plt.tight_layout()
plt.show()
- 以下实现将重构代码以生成绘图并根据 how do I make a single legend for many subplots with matplotlib? 添加图例
- Matplotlib: Legend Guide
- matplotlib.pyplot.legend
loc
bbox_to_anchor
- 鸢尾花数据集已经是
seaborn
的一部分,它作为数据框加载。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# load iris data
iris = sns.load_dataset("iris")
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
# create figure
fig = plt.figure(figsize=(20, 5), dpi=80)
# add subplots
for i, col in enumerate(iris.columns[:-1], 1):
plt.subplot(1, 4, i)
ax = sns.boxplot(x='species', y=col, data=iris, hue='species')
ax.get_legend().remove()
plt.title(col)
# add legend
handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc='upper right', ncol=3, bbox_to_anchor=(.75, 0.98))
# add subtitle
fig.suptitle('Distribution of floral traits in the species of iris')
plt.show()
我正在使用 "iris.csv" 数据制作箱线图。我试图通过测量(即花瓣长度、花瓣宽度、萼片长度、萼片宽度)将数据分成多个数据框,然后在 forloop 上制作箱线图,从而添加子图。
最后,我想一次为所有箱形图添加一个通用图例。但是,我做不到。我已经使用几个 Whosebug 问题尝试了几个教程和方法,但我无法修复它。
这是我的代码:
import seaborn as sns
from matplotlib import pyplot
iris_data = "iris.csv"
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class']
dataset = read_csv(iris_data, names=names)
# Reindex the dataset by species so it can be pivoted for each species
reindexed_dataset = dataset.set_index(dataset.groupby('class').cumcount())
cols_to_pivot = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width']
# empty dataframe
reshaped_dataset = pd.DataFrame()
for var_name in cols_to_pivot:
pivoted_dataset = reindexed_dataset.pivot(columns='class', values=var_name).rename_axis(None,axis=1)
pivoted_dataset['measurement'] = var_name
reshaped_dataset = reshaped_dataset.append(pivoted_dataset, ignore_index=True)
## Now, lets spit the dataframe into groups by-measurements.
grouped_dfs_02 = []
for group in reshaped_dataset.groupby('measurement') :
grouped_dfs_02.append(group[1])
## make the box plot of several measured variables, compared between species
pyplot.figure(figsize=(20, 5), dpi=80)
pyplot.suptitle('Distribution of floral traits in the species of iris')
sp_name=['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
setosa = mpatches.Patch(color='red')
versi = mpatches.Patch(color='green')
virgi = mpatches.Patch(color='blue')
my_pal = {"Iris-versicolor": "g", "Iris-setosa": "r", "Iris-virginica":"b"}
plt_index = 0
# for i, df in enumerate(grouped_dfs_02):
for group_name, df in reshaped_dataset.groupby('measurement'):
axi = pyplot.subplot(1, len(grouped_dfs_02), plt_index + 1)
sp_name=['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
df_melt = df.melt('measurement', var_name='species', value_name='values')
sns.boxplot(data=df_melt, x='species', y='values', ax = axi, orient="v", palette=my_pal)
pyplot.title(group_name)
plt_index += 1
# Move the legend to an empty part of the plot
pyplot.legend(title='species', labels = sp_name,
handles=[setosa, versi, virgi], bbox_to_anchor=(19, 4),
fancybox=True, shadow=True, ncol=5)
pyplot.show()
剧情如下:
如何在主图中添加一个普通的图例,在主图之外,在"main suptitle"旁边?
要定位图例,重要的是设置 loc
参数作为锚点。 (默认的 loc
是 'best'
,这意味着您事先不知道它会在哪里结束)。位置是从0,0
(当前斧头的左下角)到1,1
:当前斧头的左上角。这不包括标题等的填充,因此值可能会超出 0, 1
范围。 "current ax" 是最后激活的。
请注意,除了 plt.legend
(使用轴),您还可以使用 plt.gcf().legend
,它使用 "figure"。然后,坐标为完整图左下角的0,0
(即"figure")和右上角的1,1
。缺点是不会为图例创建额外的 space,因此您需要手动设置顶部填充(例如 plt.gcf().subplots_adjust(top=0.8)
)。一个缺点是您不能再使用 plt.tight_layout()
,并且很难将图例与轴对齐。
import seaborn as sns
from matplotlib import pyplot as plt
from matplotlib import patches as mpatches
import pandas as pd
dataset = sns.load_dataset("iris")
# Reindex the dataset by species so it can be pivoted for each species
reindexed_dataset = dataset.set_index(dataset.groupby('species').cumcount())
cols_to_pivot = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
# empty dataframe
reshaped_dataset = pd.DataFrame()
for var_name in cols_to_pivot:
pivoted_dataset = reindexed_dataset.pivot(columns='species', values=var_name).rename_axis(None, axis=1)
pivoted_dataset['measurement'] = var_name
reshaped_dataset = reshaped_dataset.append(pivoted_dataset, ignore_index=True)
## Now, lets spit the dataframe into groups by-measurements.
grouped_dfs_02 = []
for group in reshaped_dataset.groupby('measurement'):
grouped_dfs_02.append(group[1])
## make the box plot of several measured variables, compared between species
plt.figure(figsize=(20, 5), dpi=80)
plt.suptitle('Distribution of floral traits in the species of iris')
sp_name = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
setosa = mpatches.Patch(color='red')
versi = mpatches.Patch(color='green')
virgi = mpatches.Patch(color='blue')
my_pal = {"versicolor": "g", "setosa": "r", "virginica": "b"}
plt_index = 0
# for i, df in enumerate(grouped_dfs_02):
for group_name, df in reshaped_dataset.groupby('measurement'):
axi = plt.subplot(1, len(grouped_dfs_02), plt_index + 1)
sp_name = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
df_melt = df.melt('measurement', var_name='species', value_name='values')
sns.boxplot(data=df_melt, x='species', y='values', ax=axi, orient="v", palette=my_pal)
plt.title(group_name)
plt_index += 1
# Move the legend to an empty part of the plot
plt.legend(title='species', labels=sp_name,
handles=[setosa, versi, virgi], bbox_to_anchor=(1, 1.23),
fancybox=True, shadow=True, ncol=5, loc='upper right')
plt.tight_layout()
plt.show()
- 以下实现将重构代码以生成绘图并根据 how do I make a single legend for many subplots with matplotlib? 添加图例
- Matplotlib: Legend Guide
- matplotlib.pyplot.legend
loc
bbox_to_anchor
- 鸢尾花数据集已经是
seaborn
的一部分,它作为数据框加载。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# load iris data
iris = sns.load_dataset("iris")
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
# create figure
fig = plt.figure(figsize=(20, 5), dpi=80)
# add subplots
for i, col in enumerate(iris.columns[:-1], 1):
plt.subplot(1, 4, i)
ax = sns.boxplot(x='species', y=col, data=iris, hue='species')
ax.get_legend().remove()
plt.title(col)
# add legend
handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc='upper right', ncol=3, bbox_to_anchor=(.75, 0.98))
# add subtitle
fig.suptitle('Distribution of floral traits in the species of iris')
plt.show()