Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mean line on top of bar plot with pandas and matplotlib

I'm trying to plot a Pandas DataFrame, and add a line to show the mean and median. As you can see below, I'm adding a red line for the mean, but it doesn't show.

If I try to draw a green line at 5, it shows at x=190. So apparently the x values are treated as 0, 1, 2, ... rather than 160, 165, 170, ...

How can I draw lines so that their x values match those of the x axis?

From Jupyter:

DataFrame plot

Full code:

%matplotlib inline

from pandas import Series
import matplotlib.pyplot as plt

heights = Series(
    [165, 170, 195, 190, 170, 
     170, 185, 160, 170, 165, 
     185, 195, 185, 195, 200, 
     195, 185, 180, 185, 195],
    name='Heights'
)
freq = heights.value_counts().sort_index()


freq_frame = freq.to_frame()

mean = heights.mean()
median = heights.median()

freq_frame.plot.bar(legend=False)

plt.xlabel('Height (cm)')
plt.ylabel('Count')

plt.axvline(mean, color='r', linestyle='--')
plt.axvline(5, color='g', linestyle='--')

plt.show()
like image 367
oal Avatar asked Jan 16 '16 15:01

oal


1 Answers

Use plt.bar(freq_frame.index,freq_frame['Heights']) to plot your bar plot. Then the bars will be at freq_frame.index positions. Pandas in-build bar function does not allow for specifying positions of the bars, as far as I can tell.

%matplotlib inline

from pandas import Series
import matplotlib.pyplot as plt

heights = Series(
    [165, 170, 195, 190, 170, 
     170, 185, 160, 170, 165, 
     185, 195, 185, 195, 200, 
     195, 185, 180, 185, 195],
    name='Heights'
)
freq = heights.value_counts().sort_index()

freq_frame = freq.to_frame()

mean = heights.mean()
median = heights.median()

plt.bar(freq_frame.index,freq_frame['Heights'],
        width=3,align='center')

plt.xlabel('Height (cm)')
plt.ylabel('Count')

plt.axvline(mean, color='r', linestyle='--')
plt.axvline(median, color='g', linestyle='--')

plt.show()

bar plot

like image 155
Sergey Antopolskiy Avatar answered Sep 19 '22 12:09

Sergey Antopolskiy