如何使用子图制作单个图例? _get_legend_handles_labels 不工作
How do I make a SINGLE legend using subplots? _get_legend_handles_labels is not working
我想制作一个单一图例,并为整个子图中各个图中的模型提供相应的颜色。
我目前的代码如下:
from matplotlib.legend import _get_legend_handles_labels
colors = ['red', 'blue','darkblue', 'purple', 'orange', 'brown', 'pink', 'darkgreen', 'gray']
models = ['Logistic Regression', 'SVM', 'Decision Tree', 'Random Forest', 'XGBoost', 'ADABoost', 'Gaussian NB', 'KNN', 'MLP']
# English
fig, axs = plt.subplots(4,2, figsize=(25,15))
fig.suptitle('Performance measures for English and Arabic data', fontsize = 25)
axs[0,0].bar(models, en_f1_scores, color=colors)
axs[0,0].set_title("English F1 score", fontsize = 20)
axs[1,0].bar(models, en_acc_scores, color=colors)
axs[1,0].set_title("English accuracy score", fontsize = 20)
axs[2,0].bar(models, en_recall_scores, color=colors)
axs[2,0].set_title("English recall score", fontsize = 20)
axs[3,0].bar(models, en_precision_scores, color=colors)
axs[3,0].set_title("English precision score", fontsize = 20)
# Arabic
axs[0,1].bar(models, ar_f1_scores, color=colors)
axs[0, 1].set_title("Arabic F1 score", fontsize = 20)
axs[1,1].bar(models, ar_accuracy_scores, color=colors)
axs[1,1].set_title("Arabic accuracy score", fontsize = 20)
axs[2,1].bar(models, ar_recall_scores, color=colors)
axs[2,1].set_title("Arabic recall score", fontsize = 20)
axs[3,1].bar(models, ar_precision_scores, color=colors)
axs[3,1].set_title("Arabic precision score", fontsize = 20)
fig.tight_layout(pad=3.0)
当前输出如下所示:
添加此代码:
lines, labels = fig.axes[-1].get_legend_handles_labels()
fig.legend(lines, labels, loc = 'upper center')
什么都不做,它只显示:
<matplotlib.legend.Legend at 0x266574402b0>
此外,行和标签都是空数组; []
如何在次要图的顶部添加图例? (如果是横向图例就更好了!)
谢谢!
首先,我建议将所有信息保存到列表中,这样情节可以通过一个大循环来制作。这样,如果一些细节发生变化,只需更改一处即可。
要创建图例,系统会自动添加带有“标签”的图形元素。通常,一个完整的条形图只有一个标签。通过深入研究生成的条,可以分配单独的标签。
代码首先创建了一个虚拟图例,因此fig.tight_layout()
可以调整所有间距并为图例留出一些位置。调用fig.tight_layout()
后,真正的图例就创建好了。 (对于真正的图例,fig.tight_layout()
会尝试将其完全分配给一个子图,并在两列子图之间创建一个很大的间隙)。
import matplotlib.pyplot as plt
import numpy as np
colors = ['red', 'blue', 'darkblue', 'purple', 'orange', 'brown', 'pink', 'darkgreen', 'gray']
models = ['Logistic Regression', 'SVM', 'Decision Tree', 'Random Forest', 'XGBoost', 'ADABoost', 'Gaussian NB', 'KNN', 'MLP']
titles = ["F1 score", "accuracy score", "recall score", "precision score"]
N = len(models)
en_f1_scores = np.random.rand(N)
en_acc_scores = np.random.rand(N)
en_recall_scores = np.random.rand(N)
en_precision_scores = np.random.rand(N)
en_scores = [en_f1_scores, en_acc_scores, en_recall_scores, en_precision_scores]
ar_f1_scores = np.random.rand(N)
ar_acc_scores = np.random.rand(N)
ar_recall_scores = np.random.rand(N)
ar_precision_scores = np.random.rand(N)
ar_scores = [ar_f1_scores, ar_acc_scores, ar_recall_scores, ar_precision_scores]
fig, axs = plt.subplots(4, 2, figsize=(25, 15), sharex=True, sharey='row')
fig.suptitle('Performance measures for English and Arabic data', fontsize=25)
for axs_row, en_score, ar_score, title in zip(axs, en_scores, ar_scores, titles):
for language, score, ax in zip(['English', 'Arabic'], [en_score, ar_score], axs_row):
ax.bar(models, score, color=colors)
ax.set_title(language + ' ' + title, fontsize=20)
ax.set_xticks([]) # remove the x tick and their labels
ax.grid(axis='y', ls=':', color='black') # add some gridlines
ax.set_axisbelow(True) # gridlines behind the bars
for spine in ['top', 'right', 'left']: # remove part of the surrounding box, as it gets busy with the grid lines
ax.spines[spine].set_visible(False)
ax.margins(x=0.01) # less white space left and right
# the legend is created for each graphical element that has a "label"
for bar, model in zip(axs[0, 0].containers[0], models):
bar.set_label(model)
# first create a dummy legend, so fig.tight_layout() makes enough space
axs[0, 0].legend(handles=axs[0, 0].containers[0][:1],
bbox_to_anchor=(0, 1.12), loc='lower left')
fig.tight_layout(pad=3.0)
# now create the real legend; if fig.tight_layout() were called on this,
# it would create a large empty space between the columns of subplots
# as it wants the legend to belong to only one of the subplots
axs[0, 0].legend(handles=axs[0, 0].containers[0], ncol=len(models),
bbox_to_anchor=(1.03, 1.12), loc='lower center', fontsize=18)
plt.show()
我想制作一个单一图例,并为整个子图中各个图中的模型提供相应的颜色。
我目前的代码如下:
from matplotlib.legend import _get_legend_handles_labels
colors = ['red', 'blue','darkblue', 'purple', 'orange', 'brown', 'pink', 'darkgreen', 'gray']
models = ['Logistic Regression', 'SVM', 'Decision Tree', 'Random Forest', 'XGBoost', 'ADABoost', 'Gaussian NB', 'KNN', 'MLP']
# English
fig, axs = plt.subplots(4,2, figsize=(25,15))
fig.suptitle('Performance measures for English and Arabic data', fontsize = 25)
axs[0,0].bar(models, en_f1_scores, color=colors)
axs[0,0].set_title("English F1 score", fontsize = 20)
axs[1,0].bar(models, en_acc_scores, color=colors)
axs[1,0].set_title("English accuracy score", fontsize = 20)
axs[2,0].bar(models, en_recall_scores, color=colors)
axs[2,0].set_title("English recall score", fontsize = 20)
axs[3,0].bar(models, en_precision_scores, color=colors)
axs[3,0].set_title("English precision score", fontsize = 20)
# Arabic
axs[0,1].bar(models, ar_f1_scores, color=colors)
axs[0, 1].set_title("Arabic F1 score", fontsize = 20)
axs[1,1].bar(models, ar_accuracy_scores, color=colors)
axs[1,1].set_title("Arabic accuracy score", fontsize = 20)
axs[2,1].bar(models, ar_recall_scores, color=colors)
axs[2,1].set_title("Arabic recall score", fontsize = 20)
axs[3,1].bar(models, ar_precision_scores, color=colors)
axs[3,1].set_title("Arabic precision score", fontsize = 20)
fig.tight_layout(pad=3.0)
当前输出如下所示:
添加此代码:
lines, labels = fig.axes[-1].get_legend_handles_labels()
fig.legend(lines, labels, loc = 'upper center')
什么都不做,它只显示:
<matplotlib.legend.Legend at 0x266574402b0>
此外,行和标签都是空数组; []
如何在次要图的顶部添加图例? (如果是横向图例就更好了!)
谢谢!
首先,我建议将所有信息保存到列表中,这样情节可以通过一个大循环来制作。这样,如果一些细节发生变化,只需更改一处即可。
要创建图例,系统会自动添加带有“标签”的图形元素。通常,一个完整的条形图只有一个标签。通过深入研究生成的条,可以分配单独的标签。
代码首先创建了一个虚拟图例,因此fig.tight_layout()
可以调整所有间距并为图例留出一些位置。调用fig.tight_layout()
后,真正的图例就创建好了。 (对于真正的图例,fig.tight_layout()
会尝试将其完全分配给一个子图,并在两列子图之间创建一个很大的间隙)。
import matplotlib.pyplot as plt
import numpy as np
colors = ['red', 'blue', 'darkblue', 'purple', 'orange', 'brown', 'pink', 'darkgreen', 'gray']
models = ['Logistic Regression', 'SVM', 'Decision Tree', 'Random Forest', 'XGBoost', 'ADABoost', 'Gaussian NB', 'KNN', 'MLP']
titles = ["F1 score", "accuracy score", "recall score", "precision score"]
N = len(models)
en_f1_scores = np.random.rand(N)
en_acc_scores = np.random.rand(N)
en_recall_scores = np.random.rand(N)
en_precision_scores = np.random.rand(N)
en_scores = [en_f1_scores, en_acc_scores, en_recall_scores, en_precision_scores]
ar_f1_scores = np.random.rand(N)
ar_acc_scores = np.random.rand(N)
ar_recall_scores = np.random.rand(N)
ar_precision_scores = np.random.rand(N)
ar_scores = [ar_f1_scores, ar_acc_scores, ar_recall_scores, ar_precision_scores]
fig, axs = plt.subplots(4, 2, figsize=(25, 15), sharex=True, sharey='row')
fig.suptitle('Performance measures for English and Arabic data', fontsize=25)
for axs_row, en_score, ar_score, title in zip(axs, en_scores, ar_scores, titles):
for language, score, ax in zip(['English', 'Arabic'], [en_score, ar_score], axs_row):
ax.bar(models, score, color=colors)
ax.set_title(language + ' ' + title, fontsize=20)
ax.set_xticks([]) # remove the x tick and their labels
ax.grid(axis='y', ls=':', color='black') # add some gridlines
ax.set_axisbelow(True) # gridlines behind the bars
for spine in ['top', 'right', 'left']: # remove part of the surrounding box, as it gets busy with the grid lines
ax.spines[spine].set_visible(False)
ax.margins(x=0.01) # less white space left and right
# the legend is created for each graphical element that has a "label"
for bar, model in zip(axs[0, 0].containers[0], models):
bar.set_label(model)
# first create a dummy legend, so fig.tight_layout() makes enough space
axs[0, 0].legend(handles=axs[0, 0].containers[0][:1],
bbox_to_anchor=(0, 1.12), loc='lower left')
fig.tight_layout(pad=3.0)
# now create the real legend; if fig.tight_layout() were called on this,
# it would create a large empty space between the columns of subplots
# as it wants the legend to belong to only one of the subplots
axs[0, 0].legend(handles=axs[0, 0].containers[0], ncol=len(models),
bbox_to_anchor=(1.03, 1.12), loc='lower center', fontsize=18)
plt.show()