#13 Percent stacked barplot

 

 

 

 

 

A percent stacked barchart is almost the same as a stacked barchart. Subgroups are displayed on of top of each other, but data are normalised to make in sort that the sum of every subgroups is 100.

 

 

 

 

 

 


# libraries
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
import pandas as pd

# Data
r = [0,1,2,3,4]
raw_data = {'greenBars': [20, 1.5, 7, 10, 5], 'orangeBars': [5, 15, 5, 10, 15],'blueBars': [2, 15, 18, 5, 10]}
df = pd.DataFrame(raw_data)

# From raw value to percentage
totals = [i+j+k for i,j,k in zip(df['greenBars'], df['orangeBars'], df['blueBars'])]
greenBars = [i / j * 100 for i,j in zip(df['greenBars'], totals)]
orangeBars = [i / j * 100 for i,j in zip(df['orangeBars'], totals)]
blueBars = [i / j * 100 for i,j in zip(df['blueBars'], totals)]

# plot
barWidth = 0.85
names = ('A','B','C','D','E')
# Create green Bars
plt.bar(r, greenBars, color='#b5ffb9', edgecolor='white', width=barWidth)
# Create orange Bars
plt.bar(r, orangeBars, bottom=greenBars, color='#f9bc86', edgecolor='white', width=barWidth)
# Create blue Bars
plt.bar(r, blueBars, bottom=[i+j for i,j in zip(greenBars, orangeBars)], color='#a3acff', edgecolor='white', width=barWidth)

# Custom x axis
plt.xticks(r, names)
plt.xlabel("group")

# Show graphic
plt.show()

 

 

Edit: Following the nice comment of Prakash, I propose a little modification to this chart in order to add a legend.


# Create green Bars
plt.bar(r, greenBars, color='#b5ffb9', edgecolor='white', width=barWidth, label="group A")
# Create orange Bars
plt.bar(r, orangeBars, bottom=greenBars, color='#f9bc86', edgecolor='white', width=barWidth, label="group B")
# Create blue Bars
plt.bar(r, blueBars, bottom=[i+j for i,j in zip(greenBars, orangeBars)], color='#a3acff', edgecolor='white', width=barWidth, label="group C")

# Custom x axis
plt.xticks(r, names)
plt.xlabel("group")

# Add a legend
plt.legend(loc='upper left', bbox_to_anchor=(1,1), ncol=1)

# Show graphic
plt.show()

 

  • Sponsors

  • 6 comments

    • Hi, this is my generalization

      # Data
      names = [“A”,”B”,”C”,”D”,”E”]
      raw_data = {‘greenBars’: [20, 1.5, 7, 10, 5], ‘orangeBars’: [5, 15, 5, 10, 15],’blueBars’: [2, 15, 18, 5, 10]}
      df = pd.DataFrame(raw_data,index=names)

      # Get the %
      for i in df.index:
      df.loc[i]=df.loc[i]*100/sum(df.loc[i])

      # Plotting
      r=range(len(names))
      btm=df.iloc[:,0]-df.iloc[:,0] # Looks horrible, I know, enjoy it

      stack_order=[‘greenBars’,’orangeBars’,’blueBars’] # If the original column order is fine, skip it
      colors=[“green”,”orange”,”blue”]

      for i,j in zip(stack_order,colors): # If the original column order is fine, just replace “stack_order” for “df”
      plt.bar(r,df[i],bottom=btm,color=j,label=i)
      btm=btm+df[i]

      plt.legend()
      plt.xticks(r, names)
      plt.xlabel(“Group”)
      plt.ylabel(“Percentage”)
      plt.show()

      Reply
    • it seems more intuitive as well as efficient to manipulate data directly on the basis of DataFrame

      r==[0,1,2,3,4]
      raw_data = {‘greenBars’: [20, 1.5, 7, 10, 5], ‘orangeBars’: [
      5, 15, 5, 10, 15], ‘blueBars’: [2, 15, 18, 5, 10]}
      df = pd.DataFrame(raw_data)
      df[‘totals’]=df.sum(axis=1)
      percents = df.div(df[‘totals’], axis=0)
      percents=percents.drop(‘totals’, axis=1)*100

      # plot
      barWidth = 0.85
      names = (‘A’, ‘B’, ‘C’, ‘D’, ‘E’)
      plt.bar(r, percents[‘greenBars’], color=’#b5ffb9′,edgecolor=’white’,width=barWidth)

      plt.bar(r, percents[‘orangeBars’], bottom=percents[‘greenBars’], color=’#f9bc86′,
      edgecolor=’white’, width=barWidth)

      plt.bar(r, percents[‘blueBars’], bottom=percents[‘greenBars’]+percents[‘orangeBars’], color=’#a3acff’,
      edgecolor=’white’, width=barWidth)

      plt.xticks(r, names)
      plt.xlabel(“group”)
      end = timer()
      print(end – start)

      Reply

    Leave a Reply

    Your email address will not be published.