0

I have a barplot with this values in a dict for the C/C):

{'Country Name': {0: 'United States',
  1: 'United States',
  2: 'United States',
  3: 'United States',
  4: 'Russian Federation',
  5: 'Russian Federation',
  6: 'Russian Federation',
  7: 'Russian Federation',
  8: 'Japan',
  9: 'Japan',
  10: 'Japan',
  11: 'Japan',
  12: 'Germany',
  13: 'Germany',
  14: 'Germany',
  15: 'Germany',
  16: 'France',
  17: 'France',
  18: 'France',
  19: 'France'},
 'Indicator Name': {0: 'Population, total',
  1: 'Population, ages 0-14, total',
  2: 'Population, ages 15-64, total',
  3: 'Population, ages 65+, total',
  4: 'Population, total',
  5: 'Population, ages 0-14, total',
  6: 'Population, ages 15-64, total',
  7: 'Population, ages 65+, total',
  8: 'Population, total',
  9: 'Population, ages 0-14, total',
  10: 'Population, ages 15-64, total',
  11: 'Population, ages 65+, total',
  12: 'Population, total',
  13: 'Population, ages 0-14, total',
  14: 'Population, ages 15-64, total',
  15: 'Population, ages 65+, total',
  16: 'Population, total',
  17: 'Population, ages 0-14, total',
  18: 'Population, ages 15-64, total',
  19: 'Population, ages 65+, total'},
 'Valeur': {0: 320896618.0,
  1: 61653419.0,
  2: 212262832.0,
  3: 46980367.0,
  4: 144096870.0,
  5: 24255306.0,
  6: 100404879.0,
  7: 19436685.0,
  8: 127141000.0,
  9: 16517168.0,
  10: 77547638.0,
  11: 33076194.0,
  12: 81686611.0,
  13: 10716271.0,
  14: 53720119.0,
  15: 17250221.0,
  16: 66624068.0,
  17: 12168975.0,
  18: 41837530.0,
  19: 12617563.0}}

Code for the barplot (with the ax because I tried containers):

ax = plt.figure(figsize=(10,5))
ax = sns.barplot(data = Graph1values, x = 'Country Name', y = 'Valeur', hue = 'Indicator Name',palette="dark")
ax = plt.xlabel('')
ax = plt.ylabel('Nombre de personnes', size = 15)
ax = plt.title('Etude de la répartition de la population', size = 20)
    
ax = plt.show()

enter image description here

I want to add these values on top of the bars

x = ['100%', '19%', '66%', '15%', '100%', '17%', '70%', '13%', '100%', '13%', '61%', '26%', '100%',
 '13%', '66%', '21%', '100%', '18%', '63%', '19%']

I tried with containers, but it does not work.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Rocheteau
  • 43
  • 7
  • 3
    Please only use `ax=` with `sns.barplot`, not for the other commands. The other commands don't return an `ax`. – JohanC Mar 15 '23 at 11:09

1 Answers1

1
  • It seems the dict must be the output of a DataFrame, which isn't shown in the OP.
  • Use .bar_label to add custom labels to the top of each bar. How to add value labels on a bar chart has a thorough explanation of the method.
    • Use the bar height (h), country, and container label, with Boolean indexing on df, to get the correct 'percents' to annotate the bars.
    • The answers to this question do not demonstrate how to get the custom values for the bars.
  • Do not assign all lines to ax, as they do not return a matplotlib.axes. This overwrites ax, so ax.bar_label won't work.
    • plt.xlabel, plt.ylabel, and plt.title return matplotlib.text.Text.
    • With ax = plt.show(), type(ax) → NoneType because plt.show doesn't return anything.
  • Tested in python 3.11, pandas 1.5.3, matplotlib 3.7.1, seaborn 0.12.2
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# create the dataframe
data = {'Country Name': {0: 'United States', 1: 'United States', 2: 'United States', 3: 'United States', 4: 'Russian Federation', 5: 'Russian Federation', 6: 'Russian Federation', 7: 'Russian Federation', 8: 'Japan', 9: 'Japan', 10: 'Japan', 11: 'Japan', 12: 'Germany', 13: 'Germany', 14: 'Germany', 15: 'Germany', 16: 'France', 17: 'France', 18: 'France', 19: 'France'},
        'Indicator Name': {0: 'Population, total', 1: 'Population, ages 0-14, total', 2: 'Population, ages 15-64, total', 3: 'Population, ages 65+, total', 4: 'Population, total', 5: 'Population, ages 0-14, total', 6: 'Population, ages 15-64, total', 7: 'Population, ages 65+, total', 8: 'Population, total', 9: 'Population, ages 0-14, total', 10: 'Population, ages 15-64, total', 11: 'Population, ages 65+, total', 12: 'Population, total', 13: 'Population, ages 0-14, total', 14: 'Population, ages 15-64, total', 15: 'Population, ages 65+, total', 16: 'Population, total', 17: 'Population, ages 0-14, total', 18: 'Population, ages 15-64, total', 19: 'Population, ages 65+, total'},
        'Valeur': {0: 320896618.0, 1: 61653419.0, 2: 212262832.0, 3: 46980367.0, 4: 144096870.0, 5: 24255306.0, 6: 100404879.0, 7: 19436685.0, 8: 127141000.0, 9: 16517168.0, 10: 77547638.0, 11: 33076194.0, 12: 81686611.0, 13: 10716271.0, 14: 53720119.0, 15: 17250221.0, 16: 66624068.0, 17: 12168975.0, 18: 41837530.0, 19: 12617563.0}}
df = pd.DataFrame(data)

# add the list of percent values to the dataframe, which assumes they're in the correct order (as they appear to be)
df['percents'] = ['100%', '19%', '66%', '15%', '100%', '17%', '70%', '13%', '100%', '13%', '61%', '26%', '100%', '13%', '66%', '21%', '100%', '18%', '63%', '19%']

# create the plot
fig, ax = plt.subplots(figsize=(10, 5))
sns.barplot(data=df, x='Country Name', y='Valeur', hue='Indicator Name', palette="dark", ax=ax)

# customize the plot labels and title
plt.xlabel('')
plt.ylabel('Nombre de personnes', size=15)
plt.title('Etude de la répartition de la population', size=20)

# list of countries for selecting data from df
countries = [v.get_text() for v in ax.get_xticklabels()]  # countries = df['Country Name'].unique() also works

# iterate through the axes bar containers
for c in ax.containers:
    
    # get the label of the current containers
    label = c.get_label()

    # use the height of the bar, country, and label name to get the corresponding percent for the container
    labels = [df.loc[df['Indicator Name'].eq(label) &
                     df['Country Name'].eq(country) &
                     df['Valeur'].eq(h) , 'percents'].iloc[0] if (h := v.get_height()) else '' for (v, country) in zip(c, countries)]
    
    # add the bar label with the custom labels
    ax.bar_label(c, labels=labels)

enter image description here

df

          Country Name                 Indicator Name       Valeur percents
0        United States              Population, total  320896618.0     100%
1        United States   Population, ages 0-14, total   61653419.0      19%
2        United States  Population, ages 15-64, total  212262832.0      66%
3        United States    Population, ages 65+, total   46980367.0      15%
4   Russian Federation              Population, total  144096870.0     100%
5   Russian Federation   Population, ages 0-14, total   24255306.0      17%
6   Russian Federation  Population, ages 15-64, total  100404879.0      70%
7   Russian Federation    Population, ages 65+, total   19436685.0      13%
8                Japan              Population, total  127141000.0     100%
9                Japan   Population, ages 0-14, total   16517168.0      13%
10               Japan  Population, ages 15-64, total   77547638.0      61%
11               Japan    Population, ages 65+, total   33076194.0      26%
12             Germany              Population, total   81686611.0     100%
13             Germany   Population, ages 0-14, total   10716271.0      13%
14             Germany  Population, ages 15-64, total   53720119.0      66%
15             Germany    Population, ages 65+, total   17250221.0      21%
16              France              Population, total   66624068.0     100%
17              France   Population, ages 0-14, total   12168975.0      18%
18              France  Population, ages 15-64, total   41837530.0      63%
19              France    Population, ages 65+, total   12617563.0      19%
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158