如何忽略子图图例中的某些标签?

How to ignore some labels in subplots legend?

我有一个图,其中包含我使用熊猫数据框的数据创建的子图:

    # Definition of the dataframe

df = pd.DataFrame({'Colors': {0: 'Red', 1: 'Blue', 2: 'Green', 3: 'Blue', 4: 'Red'}, 'X_values': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}, 'Y_values': {0: 2, 1: 4, 2: 8, 3: 10, 4: 4}, 'MinY_values': {0: 1.5, 1: 3, 2: 7.5, 3: 8, 4: 2}, 'MaxY_values': {0: 2.5, 1: 5, 2: 9.5, 3: 11, 4: 6}})

我定义了两个列表,其中包含图中每个点的颜色以及我想分配给每个点的标签(然后,如果需要,我可以更改给定点的标签):

color
Out[8]: ['red', 'blue', 'green', 'blue', 'red']

labels
Out[9]: 
['It is a red point',
 'What a wonderful blue point',
 'Sounds to be a green point',
 'What a wonderful blue point',
 'It is a red point']
 

在每个子图中,我需要添加一条水平线。

这是我的问题:当我向图形添加图例时,如果颜色重复,则标签会重复,并且图例中包含水平线,这将“移动”图例。

如何忽略图例中重复的颜色以及不包括其中的黑线?

这是我的代码:

import pandas as pd

from matplotlib.pyplot import show, subplots


# Definition of the dataframe

df = pd.DataFrame({'Colors': {0: 'Red', 1: 'Blue', 2: 'Green', 3: 'Blue', 4: 'Red'}, 'X_values': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}, 'Y_values': {0: 2, 1: 4, 2: 8, 3: 10, 4: 4}, 'MinY_values': {0: 1.5, 1: 3, 2: 7.5, 3: 8, 4: 2}, 'MaxY_values': {0: 2.5, 1: 5, 2: 9.5, 3: 11, 4: 6}})


# Definition of the different colors and labels

color = []

labels = []
 

for i in df['Colors']:
    if i == 'Red':
        color.append('red')
        labels.append('It is a red point')
    if i == 'Blue':
        color.append('blue')
        labels.append('What a wonderful blue point')
    if i == 'Green':
        color.append('green')
        labels.append('Sounds to be a green point')
 
# Figure

fig,axes = subplots(3,1,sharex = True)

fig.subplots_adjust(top=0.975,
bottom=0.07,
left=0.05,
right=0.585,
hspace=0.0,
wspace=0.2) 

for x_val,y_val,min_val,max_val,colors in zip(df['X_values'],df['Y_values'],df['MinY_values'],df['MaxY_values'],color):
    axes[0].errorbar(x_val,y_val,yerr = [[min_val],[max_val]] ,color = colors,barsabove='True',fmt = 'o')

axes[0].axhline(y=5, color='black', linestyle='--')
    
for x_val,y_val,min_val,max_val,colors in zip(df['X_values'],df['Y_values'],df['MinY_values'],df['MaxY_values'],color):
    axes[1].errorbar(x_val,y_val,yerr = [[min_val],[max_val]] ,color = colors,barsabove='True',fmt = 'o')

axes[1].axhline(y=5, color='black', linestyle='--')
    
for x_val,y_val,min_val,max_val,colors in zip(df['X_values'],df['Y_values'],df['MinY_values'],df['MaxY_values'],color):
    axes[2].errorbar(x_val,y_val,yerr = [[min_val],[max_val]] ,color = colors,barsabove='True',fmt = 'o',label = labels)

axes[2].axhline(y=5, color='black', linestyle='--')


# Legend

fig.legend(labels)

fig.legend(bbox_to_anchor=(2,2), loc='center', ncol=1)
  
show()

在这种情况下,最简单的方法是创建自定义图例。

一些注意事项:

  • plt.tight_layout() 可用于将图例和标签很好地放入图中;这比 fig.subplots_adjust() 灵活得多,尤其是在以后对绘图进行更改时
  • fig.legend() 使用“当前斧头”(当前子图),在本例中为 axes[2]
  • 将图例放在图的右侧时,使用 loc='upper left' 作为锚点会有所帮助; 'loc' 不在左侧的值太难控制(bbox_to_anchor 设置锚点的位置,在给定子图的 'axes coordinates' 中测量)

这是一个例子:

from matplotlib import pyplot as plt
from matplotlib.lines import Line2D
import pandas as pd

# Definition of the dataframe
df = pd.DataFrame(
    {'Colors': {0: 'Red', 1: 'Blue', 2: 'Green', 3: 'Blue', 4: 'Red'}, 'X_values': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
     'Y_values': {0: 2, 1: 4, 2: 8, 3: 10, 4: 4}, 'MinY_values': {0: 1.5, 1: 3, 2: 7.5, 3: 8, 4: 2},
     'MaxY_values': {0: 2.5, 1: 5, 2: 9.5, 3: 11, 4: 6}})

fig, axes = plt.subplots(3, 1, sharex=True, gridspec_kw={'hspace': 0.0})

for x_val, y_val, min_val, max_val, color in zip(df['X_values'], df['Y_values'],
                                                 df['MinY_values'], df['MaxY_values'], df['Colors']):
    axes[0].errorbar(x_val, y_val, yerr=[[min_val], [max_val]], color=color, barsabove='True', fmt='o')
axes[0].axhline(y=5, color='black', linestyle='--')

for x_val, y_val, min_val, max_val, color in zip(df['X_values'], df['Y_values'],
                                                 df['MinY_values'], df['MaxY_values'], df['Colors']):
    axes[1].errorbar(x_val, y_val, yerr=[[min_val], [max_val]], color=color, barsabove='True', fmt='o')
axes[1].axhline(y=5, color='black', linestyle='--')

for x_val, y_val, min_val, max_val, color in zip(df['X_values'], df['Y_values'],
                                                 df['MinY_values'], df['MaxY_values'], df['Colors']):
    axes[2].errorbar(x_val, y_val, yerr=[[min_val], [max_val]], color=color, barsabove='True', fmt='o')
axes[2].axhline(y=5, color='black', linestyle='--')

# Legend
legend_handles = [Line2D([], [], color='red', label='It is a red point', marker='o', ls='-'),
                  Line2D([], [], color='blue', label='What a wonderful blue point', marker='o', ls='-'),
                  Line2D([], [], color='green', label='Sounds to be a green point', marker='o', ls='-')]
axes[0].legend(handles=legend_handles, bbox_to_anchor=(1.01, 1), loc='upper left', ncol=1)

plt.tight_layout()
plt.show()