johnbelinsky
johnbelinsky

Reputation: 11

Using matplotlib to create grouped bar chart with xtick labels for bars within a group

I am creating a grouped bar chart in which the groups are presented in descending order based on a percentage. I need to be able to label both bars within a group separately like shown below: What I need

However with the code I have been finding online I can only get this so far: What I have

This is my code so far, anything that will point me in the right direction will help:

products = ['chew', 'e_cigarette', 'cigarette', 'hookah', 'cigar']
def make_a_graph(products, per_totals, per_users):
  per_totals.sort(reverse = True)
  per_users.sort(reverse = True)
  n_groups = len(products)

  fig, ax = plt.subplots()
  index = np.arange(n_groups)
  bar_width = 0.4

  totals = plt.bar(index - bar_width/2, per_totals, bar_width, color = 'b', label = '% of All Students')

  users = plt.bar(index + bar_width/2, per_users, bar_width, color = 'lightblue', label = '% of Product Users')

  plt.xlabel('Tobacco Product')
  plt.ylabel('Percent of Users')
  plt.title('Figure 2. Tobacco Use for 16-18 Year Olds')
  plt.legend()

  plt.tight_layout()
  plt.show()

Upvotes: 1

Views: 1652

Answers (1)

JohanC
JohanC

Reputation: 80534

This code seems to be what you're after. Note that when you sort the per_totals and the per_users, you also need to maintain the correspondence between the number and the product name.

import matplotlib.pyplot as plt
import numpy as np

products = ['chew', 'cigarette', 'hookah', 'cigar', 'e_cigarette']
per_totals = [3.2, 3.5, 0.9, 1.1, 6.7]
per_users = [36.1, 26, 20, 16, 31]

# sort both lists together
per_totals, products_totals = zip(*sorted(zip(per_totals, products), reverse=True))
per_users, products_users = zip(*sorted(zip(per_users, products), reverse=True))

n_groups = len(products)

fig, ax = plt.subplots()
index = np.arange(n_groups)
bar_width = 0.4

totals = plt.bar(index - bar_width/2, per_totals, bar_width, color = '#2c7fb8', label = '% of All Students')
users  = plt.bar(index + bar_width/2, per_users,  bar_width, color = '#7fcdbb', label = '% of Product Users')

# list of ticks: combine the ticks from both groups
# followed by the list of corresponding labels
# note that matplotlib takes care of sorting both lists while maintaining the correspondence
plt.xticks(np.append(index - bar_width/2, index + bar_width/2), # tick positions
           products_totals+products_users, # label corresponding to each tick
           rotation=30)

plt.xlabel('Tobacco Product')
plt.ylabel('Percent of Users')
plt.title('Figure 2. Tobacco Use for 16-18 Year Olds')
plt.legend()
plt.tight_layout()
plt.show()

result

Upvotes: 1

Related Questions