Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plot dataframe then add vertical lines; how get custom legend text for all?

I can plot a dataframe (2 "Y" values) and add vertical lines (2) to the plot, and I can specify custom legend text for either the Y values OR the vertical lines, but not both at the same time.

import pandas as pd
import matplotlib.pyplot as plt

d = {'x' : [1., 2., 3., 4.], 'y1' : [8., 6., 4., 2.], 'y2' : [-4., 13., 2.2, -1.1]}
df = pd.DataFrame(d)
ax = df.plot(x='x', y=['y1'], linestyle='-', color='b')
df.plot(x='x', y=['y2'], linestyle='--', color='y', ax=ax)
ax.legend(labels=['y1custom', 'y2custom'])
plt.axvline(x=1.5, color='r', linestyle='--', label='vline1.5custom')
plt.axvline(x=3.5, color='k', linestyle='--', label='vline3.5custom')
plt.legend()        # <---- comment out....or not....for different effects
plt.show()

A key line in the code is "plt.legend()". With it in the code, I get this (note legend has dataframe column labels "y1" and "y2" instead of my desired custom labels):

with plt.legend() call

With "plt.legend()" removed, I get this (legend has my custom labels for the dataframe values only, legend for vertical lines does not even appear!):

without plt.legend() call

How can I get the best of both worlds, specifically the following (in whatever order) for my legend?:

y1custom
y2custom
vline1.5custom
vline3.5custom

Sure I could rename the columns of the dataframe first, but...ugh! There must be a better way.

like image 285
sasumner Avatar asked Mar 15 '18 14:03

sasumner


People also ask

How do you plot multiple vertical lines in Python?

By using axvline() In matplotlib, by using the axvline() method we can create multiple vertical lines in the plot.

How do you plot a vertical line in Jupyter?

To plot a vertical line with pyplot, you can use the axvline() function. In this syntax: x is the coordinate for the x-axis. This point is from where the line would be generated vertically. ymin is the bottom of the plot; ymax is the top of the plot.


Video Answer


2 Answers

Each call to legend() overwrites the initially created legend. So you need to create one single legend with all the desired labels in.

This means you can get the current labels via ax.get_legend_handles_labels() and replace those you do not like with something else. Then specify the new list of labels when calling legend().

import pandas as pd
import matplotlib.pyplot as plt

d = {'x' : [1., 2., 3., 4.], 'y1' : [8., 6., 4., 2.], 'y2' : [-4., 13., 2.2, -1.1]}
df = pd.DataFrame(d)
ax = df.plot(x='x', y=['y1'], linestyle='-', color='b')
df.plot(x='x', y=['y2'], linestyle='--', color='y', ax=ax)

ax.axvline(x=1.5, color='r', linestyle='--', label='vline1.5custom')
ax.axvline(x=3.5, color='k', linestyle='--', label='vline3.5custom')

h,labels = ax.get_legend_handles_labels()
labels[:2] = ['y1custom','y2custom']
ax.legend(labels=labels)

plt.show()

enter image description here

like image 83
ImportanceOfBeingErnest Avatar answered Sep 19 '22 09:09

ImportanceOfBeingErnest


label can be passed to plot() as long as you specify the column being plotted:

import pandas as pd
import matplotlib.pyplot as plt

d = {'x' : [1., 2., 3., 4.], 'y1' : [8., 6., 4., 2.], 'y2' : [-4., 13., 2.2, -1.1]}
df = pd.DataFrame(d)

ax = df['y1'].plot(x='x', linestyle='-', color='b', label='y1custom')
df['y2'].plot(x='x', linestyle='--', color='y', ax=ax, label='y2custom')
plt.axvline(x=1.5, color='r', linestyle='--', label='vline1.5custom')
plt.axvline(x=3.5, color='k', linestyle='--', label='vline3.5custom')
plt.legend()
plt.show()

This approach avoids having to mess around with the legend afterwards:

matplotlib figure+custom legend

like image 33
Martin Evans Avatar answered Sep 23 '22 09:09

Martin Evans