Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pandas: Bar-Plot with two bars and two y-axis

I have a DataFrame looking like this:

     amount     price
age
A     40929   4066443
B     93904   9611272
C    188349  19360005
D    248438  24335536
E    205622  18888604
F    140173  12580900
G     76243   6751731
H     36859   3418329
I     29304   2758928
J     39768   3201269
K     30350   2867059

Now I'd like to plot a bar-plot with the age on the x-axis as labels. For each x-tick there should be two bars, one bar for the amount, and one for the price. I can get this working by using simply:

df.plot(kind='bar')

The problem is the scaling. The prices are so much higher that I can not really identify the amount in that graph, see:

enter image description here

Thus I'd like a second y-axis. I tried it using:

df.loc[:,'amount'].plot(kind='bar')
df.loc[:,'price'].plot(kind='bar',secondary_y=True)

but this just overwrites the bars and does NOT place them side-by-side. Is there any way to do this without having to access the lower-level matplotlib (which would be possible obviously by placing the bars side by side manually)?

For now, I'm using two single plots within subplots:

df.plot(kind='bar',grid=True,subplots=True,sharex=True); 

resulting in:

enter image description here

like image 924
tim Avatar asked Jun 12 '14 11:06

tim


People also ask

How do you plot a line graph with two vertical Y-axis in Python?

By using the twinx() method we create two twin y-axes. In the above example, by using the twinx() method we create two y-axes and plot the same data by using the plot() method.

How do you plot multiple Y-axis in Python?

Using subplots() method, create a figure and a set of subplots. Plot [1, 2, 3, 4, 5] data points on the left Y-axis scales. Using twinx() method, create a twin of Axes with a shared X-axis but independent Y-axis, ax2.


4 Answers

Using the new pandas release (0.14.0 or later) the below code will work. To create the two axis I have manually created two matplotlib axes objects (ax and ax2) which will serve for both bar plots.

When plotting a Dataframe you can choose the axes object using ax=.... Also in order to prevent the two plots from overlapping I have modified where they align with the position keyword argument, this defaults to 0.5 but that would mean the two bar plots overlapping.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from io import StringIO

s = StringIO("""     amount     price
A     40929   4066443
B     93904   9611272
C    188349  19360005
D    248438  24335536
E    205622  18888604
F    140173  12580900
G     76243   6751731
H     36859   3418329
I     29304   2758928
J     39768   3201269
K     30350   2867059""")

df = pd.read_csv(s, index_col=0, delimiter=' ', skipinitialspace=True)

fig = plt.figure() # Create matplotlib figure

ax = fig.add_subplot(111) # Create matplotlib axes
ax2 = ax.twinx() # Create another axes that shares the same x-axis as ax.

width = 0.4

df.amount.plot(kind='bar', color='red', ax=ax, width=width, position=1)
df.price.plot(kind='bar', color='blue', ax=ax2, width=width, position=0)

ax.set_ylabel('Amount')
ax2.set_ylabel('Price')

plt.show()

Plot

like image 194
Ffisegydd Avatar answered Sep 30 '22 04:09

Ffisegydd


You just need to write: df.plot( kind= 'bar', secondary_y= 'amount')

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from io import StringIO
s = StringIO("""     amount     price
A     40929   4066443
B     93904   9611272
C    188349  19360005
D    248438  24335536
E    205622  18888604
F    140173  12580900
G     76243   6751731
H     36859   3418329
I     29304   2758928
J     39768   3201269
K     30350   2867059""")
df = pd.read_csv(s, index_col=0, delimiter=' ', skipinitialspace=True)

_ = df.plot( kind= 'bar' , secondary_y= 'amount' , rot= 0 )
plt.show()

Secondary_Y_axis

like image 41
InLaw Avatar answered Sep 30 '22 04:09

InLaw


Here is an other method:

  • create all the bars in left axes
  • move some bars to the right axes by change it's transform attribute

Here is the code:

import pylab as pl
df = pd.DataFrame(np.random.rand(10, 2), columns=["left", "right"])
df["left"] *= 100

ax = df.plot(kind="bar")
ax2 = ax.twinx()
for r in ax.patches[len(df):]:
    r.set_transform(ax2.transData)
ax2.set_ylim(0, 2);

here is the output:

enter image description here

like image 38
HYRY Avatar answered Sep 30 '22 06:09

HYRY


As mentioned by InLaw you should use secondary_y = 'amount'

To add to his answer here is how to set the ylabels for the two axis:

df.plot.bar(figsize=(15,5), secondary_y= 'amount')

ax1, ax2 = plt.gcf().get_axes() # gets the current figure and then the axes

ax1.set_ylabel('price')

ax2.set_ylabel('amount')
like image 25
Tomas G. Avatar answered Sep 30 '22 05:09

Tomas G.