I have a figure with subplots I created with data from a panda data frame:
# 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}})
I defined two lists which contain the color for each point on the figure as well as the label I want to assign to each point (Then, I can change a label for a given point if needed):
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']
On each subfigure, I need to add an horizontal line.
Here is my problem: When I add a legend to the figure, the label is repeated if the color is repeated and the horizontal line is included in the legend which will "shift" the legend.
How can I ignore the repeated colors in the legend as well as not include the black line in it ?
Here is my code:
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()
CodePudding user response:
In this case, the easiest is to create a custom legend.
Some notes:
plt.tight_layout()
can be used to fit the legend and the labels nicely into the plot; this is much more flexible thanfig.subplots_adjust()
, especially when later changes are made to the plotsfig.legend()
uses the "current ax" (current subplot), which in this case isaxes[2]
- when putting the legend to the right of the plots, it helps to use
loc='upper left'
for the anchor point; 'loc' values that aren't at the left are too hard to control (bbox_to_anchor
sets the position of the anchor point, measured in