Function to automate creation of ungrouped bar plots

Viewed 79

This might be a duplicate, however please note I need a solution for ungrouped bar plots.

Here's my reproducible example:

import pandas as pd
import numpy as np

#generate data
np.random.seed(123)
df = pd.DataFrame({ 
    'sex':np.random.choice(['male', 'female'], 500, p=[0.4, 0.6]),
    'country':np.random.choice(['US', 'UK', 'Canada'], 500, p=[0.2, 0.5, 0.3]),
    'age':np.random.normal(40,5,500).round(),
    'grade':np.random.choice(['A', 'B'], 500),
    'religion':np.random.choice(['christian', 'muslim', 'none'], 500),
    'education':np.random.choice(['bachelor', 'master', 'doctorate'], 500, p=[0.7, 0.2, 0.1])
     })

#define function to create percentage bar plot
def catbars (a):
    x = ((a.value_counts(normalize=True, ascending=True))*100).plot.barh()
    print (x)

catbars(df.country)

Output:

enter image description here

Now I want a similar function, but which will generate 6 separate plots, one for each of my variables (sex, country, age, etc.). How can I do this?

1 Answers

How about this?

ncols = 3
nrows = int(np.ceil(df.shape[1] / ncols))
fig, axes = plt.subplots(nrows=nrows, ncols=ncols,
                         figsize=(4*ncols, 3*nrows), sharex=True)
for ax, (name, g) in zip(axes.ravel(), df.items()):
    (g.value_counts(normalize=True, ascending=True) * 100).plot.barh(ax=ax)
    ax.title.set_text(name)
plt.tight_layout()

v1

Note: as a refinement, you may chose to order numerical columns (e.g., age in your example) by value instead of by prevalence. Thus:

ncols = 3
nrows = int(np.ceil(df.shape[1] / ncols))
fig, axes = plt.subplots(nrows=nrows, ncols=ncols,
                         figsize=(4*ncols, 3*nrows), sharex=True)
for ax, (name, g) in zip(axes.ravel(), df.items()):
    z = g.value_counts(normalize=True, ascending=True) * 100
    if isinstance(z.index, (pd.Float64Index, pd.Int64Index)):
        z = z.sort_index(ascending=False)  # might make more sense for numerical categories
    z.plot.barh(ax=ax)
    ax.title.set_text(name)
plt.tight_layout()

v2

Related