0

I was following this tutorial to add value in my bar chart link

The code that shown in the blog written like this

from matplotlib import pyplot as plt
import numpy as np

years = [1901, 1911, 1921, 1931, 1941, 1951, 1961, 1971, 1981, 1991, 2001, 2011]
population = [237.4, 238.4, 252.09, 251.31, 278.98, 318.66, 361.09, 439.23, 548.16, 683.33, 846.42, 1028.74]

x = np.arange(len(years)) # the label locations
width = 0.35 # the width of the bars

fig, ax = plt.subplots()

ax.set_ylabel('Population(in million)')
ax.set_title('Years')
ax.set_xticks(x)
ax.set_xticklabels(years)

pps = ax.bar(x - width/2, population, width, label='population')
for p in pps:
   height = p.get_height()
   ax.annotate('{}'.format(height),
      xy=(p.get_x() + p.get_width() / 2, height),
      xytext=(0, 3), # 3 points vertical offset
      textcoords="offset points",
      ha='center', va='bottom')

plt.show()

So, the output become like this

enter image description here

But, I just realized that the xticks from the bar chart is not centered

enter image description here

My question - Is anybody know how to center the xticks?

I was trying to find the solution, but not found yet

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
theDreamer911
  • 85
  • 1
  • 9

2 Answers2

3

In matplotlib 3.4.0 or newer bar_label can be used instead of annotate:

import numpy as np
from matplotlib import pyplot as plt

years = [1901, 1911, 1921, 1931, 1941, 1951, 1961, 1971, 1981, 1991, 2001, 2011]
population = [237.4, 238.4, 252.09, 251.31, 278.98, 318.66, 361.09, 439.23,
              548.16, 683.33, 846.42, 1028.74]

# Create Tick Locations
x = np.arange(len(years))
# Plotting
fig, ax = plt.subplots(figsize=(10, 6))
# Do not offset the values of x to center labels (default)
ax.bar(x, population, width=.35, label='population')

# Labels, ticks, etc.
ax.set_ylabel('Population(in million)')
ax.set_title('Years')
ax.set_xticks(x)
ax.set_xticklabels(years)

# Add Bar Labels
for c in ax.containers:
    ax.bar_label(c)

plt.show()

plot

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
  • 1
    Now I gotta go check out the what's new of `matplotlib` thanks for sharing! Seems like you may be able to use `bar_container = ax.bar(...); ax.bar_label(bar_container)` instead of fetching the bar_container from the Axes object. But awesome to know about this nonetheless!! – Cameron Riddell Jul 15 '21 at 22:45
  • 1
    Yes There's only one container in this example. But if you have multiple containers (stacked bar plots for example) you'll need to iterate. I like to do the iterative approach so that it (almost) always works. – Henry Ecker Jul 15 '21 at 22:47
1

imo that tutorial is making plotting more confusing than it needs to be. You seldom need to fetch coordinates from the artists on the plot. Just use your data directly:

from matplotlib import pyplot as plt
import numpy as np

years = [1901, 1911, 1921, 1931, 1941, 1951, 1961, 1971, 1981, 1991, 2001, 2011]
population = [237.4, 238.4, 252.09, 251.31, 278.98, 318.66, 361.09, 439.23, 548.16, 683.33, 846.42, 1028.74]

x_values = np.arange(len(years))
fig, ax = plt.subplots(figsize=(12, 4))

ax.bar(x_values, population, width=.35, label='population')
for x, y in zip(x_values, population):    
    ax.annotate(
        str(y),        # label is our y-value as a string
        xy=(x, y),
        xytext=(0, 3), # 3 points vertical offset
        textcoords="offset points",
        ha='center', 
        va='bottom'
    )
    
    
ax.set_xticks(x_values)
ax.set_xticklabels(years)
ax.set_ylim(0, 1200)

plt.show()

enter image description here

Cameron Riddell
  • 10,942
  • 9
  • 19