SANM2009
SANM2009

Reputation: 1998

Pandas subplots plotting multiple y-axis

I have a dataframe that looks like this. I need a subplot for each unique Item (book, Table and Chair). The plots should be sorted by Year (Year is also the x-axis). I need to make use of twiny to have Price on the left and Quantity plotted on the right of each subplot.

I can do this manually for each Item by creating a individual dataframe. So I created a dataframe for Book, then sorted by Year and set Year as index. then create the plot with secondary_y. But obviously this is long winded. Is there a way to do this from the original dataframe without all the manual processing?

    Item  Year Price  Quantity
0   Book  2000    $2        50
1  Table  2000   $33        44
2  Chair  2000   $21        31
3   Book  2001    $3        77
4  Table  2001   $20       500
5  Chair  2001    $2        50
6   Book  2002   $36         7
7  Table  2002  $200        50
8  Chair  2002   $44         5

Upvotes: 0

Views: 1910

Answers (2)

Simon Bowly
Simon Bowly

Reputation: 1083

You may find seaborn's factorplot very useful for this: https://seaborn.pydata.org/generated/seaborn.factorplot.html

It handles plotting categorised data like yours, saving you the effort of grouping and looping. There are lots of examples at the above link, but hopefully this is close to what you want:

%matplotlib inline
import seaborn as sns
import pandas as pd

data = pd.DataFrame({
    'Item': ['Book', 'Table', 'Chair'] * 3,
    'Year': [2000] * 3 + [2001] * 3 + [2002] * 3,
    'Price': [2, 33, 21, 3, 20, 2, 36, 200, 44],
    'Quantity': [50, 44, 31, 77, 500, 50, 7, 50, 5],
})

g = sns.factorplot(data=data, x='Year', y='Price',
                   col='Item', kind='bar', sharey=False)

Jupyter output

If you want to plot both price and quantity (using a secondary y axis), you can use a custom FacetGrid object with map_dataframe. This doesn't seem to play so well with seaborn though; labels, legend, etc need to be added afterwards. I think the preference for their categorical plotting functions is to create more plots rather than use secondary axes (i.e. a second row of plots for quantity).

def bar_plot(data, **kwargs):
    ''' Called with each subset of data by 'Item' '''
    ax = plt.gca()
    data[['Year', 'Price', 'Quantity']].plot(
        x='Year', kind='bar', ax=ax, secondary_y='Quantity')

g = sns.FacetGrid(data=data, col='Item', sharey=False)
g.map_dataframe(bar_plot)

Combined bars

Upvotes: 2

Felipe
Felipe

Reputation: 11887

Not sure what you mean here, but maybe your can use groupby() and then traverse the groups?

Here's a simple example (using pyplot)

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

%matplotlib inline

dicts = []
dicts.append({'item':'book','year':2000,'price':2, 'quantity':50})
dicts.append({'item':'table','year':2000,'price':33, 'quantity':44})
dicts.append({'item':'chair','year':2000,'price':21, 'quantity':31})

dicts.append({'item':'book','year':2001,'price':3, 'quantity':50})
dicts.append({'item':'table','year':2001,'price':20, 'quantity':44})
dicts.append({'item':'chair','year':2001,'price':2, 'quantity':31})

dicts.append({'item':'book','year':2002,'price':36, 'quantity':7})
dicts.append({'item':'table','year':2002,'price':200, 'quantity':50})
dicts.append({'item':'chair','year':2002,'price':44, 'quantity':5})

df = pd.DataFrame.from_records(dicts)

grouped = df.groupby('item')

fig, axes = plt.subplots(1,3,sharey=True)

fig.set_size_inches(15,4)

for i,group_key in enumerate(list(grouped.groups.keys())):
    grouped.get_group(group_key).set_index('year').plot(kind='bar',ax = axes[i])
    axes[i].set_title(group_key,fontsize=15)

enter image description here

Upvotes: 1

Related Questions