0

""" I'm trying to reproduce a plot showing the world population growth from 1950 to 2100.

  1. ideally, I'd like to show two different colors under the lineplot, darkgreen from 1950 to 2019 because these are actual data, and lightgreen for the projected data (2019 to 2100)
  2. I'd like to annotate specific points corresponding to 1950, 1987, 2019 and 2050. I tried using markers=True but but failed.

I'm looking for something like the following plot (without the annual growth rate in red) enter image description here

Thank you in advance for helping me out.

"""

data = {'Year': {0: 1950,
  1: 1951,
  2: 1952,
  3: 1953,
  4: 1954,
  5: 1955,
  6: 1956,
  7: 1957,
  8: 1958,
  9: 1959,
  10: 1960,
  11: 1961,
  12: 1962,
  13: 1963,
  14: 1964,
  15: 1965,
  16: 1966,
  17: 1967,
  18: 1968,
  19: 1969,
  20: 1970,
  21: 1971,
  22: 1972,
  23: 1973,
  24: 1974,
  25: 1975,
  26: 1976,
  27: 1977,
  28: 1978,
  29: 1979,
  30: 1980,
  31: 1981,
  32: 1982,
  33: 1983,
  34: 1984,
  35: 1985,
  36: 1986,
  37: 1987,
  38: 1988,
  39: 1989,
  40: 1990,
  41: 1991,
  42: 1992,
  43: 1993,
  44: 1994,
  45: 1995,
  46: 1996,
  47: 1997,
  48: 1998,
  49: 1999,
  50: 2000,
  51: 2001,
  52: 2002,
  53: 2003,
  54: 2004,
  55: 2005,
  56: 2006,
  57: 2007,
  58: 2008,
  59: 2009,
  60: 2010,
  61: 2011,
  62: 2012,
  63: 2013,
  64: 2014,
  65: 2015,
  66: 2016,
  67: 2017,
  68: 2018,
  69: 2019,
  70: 2020,
  71: 2091,
  72: 2092,
  73: 2093,
  74: 2094,
  75: 2095,
  76: 2096,
  77: 2097,
  78: 2098,
  79: 2099,
  80: 2100},
 'billion': {0: 2.5,
  1: 2.6,
  2: 2.6,
  3: 2.7,
  4: 2.7,
  5: 2.8,
  6: 2.8,
  7: 2.9,
  8: 2.9,
  9: 3.0,
  10: 3.0,
  11: 3.1,
  12: 3.2,
  13: 3.2,
  14: 3.3,
  15: 3.3,
  16: 3.4,
  17: 3.5,
  18: 3.6,
  19: 3.6,
  20: 3.7,
  21: 3.8,
  22: 3.9,
  23: 3.9,
  24: 4.0,
  25: 4.1,
  26: 4.2,
  27: 4.2,
  28: 4.3,
  29: 4.4,
  30: 4.5,
  31: 4.5,
  32: 4.6,
  33: 4.7,
  34: 4.8,
  35: 4.9,
  36: 5.0,
  37: 5.1,
  38: 5.1,
  39: 5.2,
  40: 5.3,
  41: 5.4,
  42: 5.5,
  43: 5.6,
  44: 5.7,
  45: 5.7,
  46: 5.8,
  47: 5.9,
  48: 6.0,
  49: 6.1,
  50: 6.1,
  51: 6.2,
  52: 6.3,
  53: 6.4,
  54: 6.5,
  55: 6.5,
  56: 6.6,
  57: 6.7,
  58: 6.8,
  59: 6.9,
  60: 7.0,
  61: 7.0,
  62: 7.1,
  63: 7.2,
  64: 7.3,
  65: 7.4,
  66: 7.5,
  67: 7.5,
  68: 7.6,
  69: 7.7,
  70: 7.8,
  71: 10.8,
  72: 10.8,
  73: 10.8,
  74: 10.8,
  75: 10.9,
  76: 10.9,
  77: 10.9,
  78: 10.9,
  79: 10.9,
  80: 10.9}}
df = pd.DataFrame(data)
print(df)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns

fig,ax = plt.subplots(figsize=(10,8))
sns.lineplot(x='Year',y='billion',data=df,ax=ax,color='b')
ax.set_ylim([2,11])
plt.fill_between(df['Year'].values, df['billion'].values,color='lightgreen')

plt.text(1950,2.5,'2.5 Billion\nin 1950',horizontalalignment='left')
plt.text(1987,5,'5 Billion\nin 1987',horizontalalignment='right')
plt.text(2019,7.7,'7.7 Billion\nin 2019',horizontalalignment='right')
plt.text(2050,9.7,'9.7 Billion\nin 2050',horizontalalignment='right')

ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)#hiding y spine
plt.gca().axes.get_yaxis().set_visible(False) #hiding y axis
ax.spines['right'].set_visible(False)
plt.show()
plt.close()

""" This is what I got so far enter image description here """

Amilovsky
  • 397
  • 6
  • 15

1 Answers1

2

You can fill between years using where=:

ax.fill_between(df['Year'], df['billion'], color='darkgreen', where=df['Year'] <= 2019)
ax.fill_between(df['Year'], df['billion'], color='lightgreen', where=df['Year'] >= 2019)

You can interpolate values for the years with np.interp():

marked_years = [1950, 1987, 2019, 2050]
ax.scatter(marked_years, np.interp(marked_years, df['Year'], df['billion']), marker='o', color='black', s=50)

In a similar way the texts could be placed:

for year, value in zip(marked_years, np.interp(marked_years, df['Year'], df['billion'])):
    ax.text(year, value, f'{value:.1f} Billion\nin {year}\n', ha='left' if year < 1970 else 'right', va='bottom')

Optionally you set tick marks for the x-axis every 10 years, and leave out the padding:

ax.xaxis.set_major_locator(ticker.MultipleLocator(10))
ax.margins(x=0, tight=True) # zero padding for the x-axis```

resulting plot

JohanC
  • 71,591
  • 8
  • 33
  • 66