GDP per Capita trends

Let’s have a look at trends in GDP per Capita between 1970 - 2022!

Gross domestic product (GDP) is a monetary measure of the total market value of all the final goods and services produced and rendered in a specific time period by a countryor countries.

GDP per capita is the total value of a country’s finished goods and services (Gross domestic product) divided by its total population (per capita).

Data

The data used in this analysis is sourced with thanks from this data set on kaggle. The data consists of a csv file with column of Country names and a column for each year from 1970 to 2022. The GDP per capita values (in US Dollars) are expressed for the respective countries and years.

Data Wrangling

Data wrangling is the process of transforming data from one form into another form that is well suited to the purpose at hand. In our case that means transforming the data into a form that will be easy to create visualisations from. Thankfully the original data set is well tempered so there will be little for us to do before jumping into the visualisations.

I’m using the following tools to work with the data, create visualisations and generate reports:

Code
# import libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns 
import matplotlib.ticker as ticker
import matplotlib.ticker as mtick
from   matplotlib.ticker import ScalarFormatter


# set up for the visuals
%matplotlib inline 
plt.rcParams['figure.figsize'] = [8.0, 4.0]
plt.rcParams['figure.dpi'] = 80
plt.rc('legend',fontsize=9)
plt.rcParams['axes.edgecolor'] = 'grey'

# import data
d = pd.read_csv('data/Per Capita GDP of All Countries 1970 to 2022.csv')
d = d.drop(columns='Sr.No').set_index('Country').T

# make a table of the percentiles for each year
qs = [0.1,0.2,0.25,0.3,0.4,0.5,0.6,0.7,0.75,0.8,0.9]

gdp_percentiles = pd.DataFrame(index = [f"{x*100:.0f}th Percentile" for x in qs ],  
                               data  = [d.quantile(x, axis=1) for x in qs]).T

Data Visualisations

There are many ways we can visualise the data. Different perspectives may offer different insights.

Overall trend over time

Let’s take a look at the overall trend in GDP per Capita over time …

Code
# construct the plot
fig, ax = plt.subplots()
gdp_percentiles.loc[:,['50th Percentile']].plot(color='black',alpha=0.4, ls='-', lw=5.0, ax=ax)

# format axis
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '${:,g}'.format(y)))
ax.spines[['right', 'top']].set_visible(False)

# format legend, title, etc
ax.get_legend().set_title("")
ax.get_legend().get_frame().set_linewidth(0.0)
ax.set_title('GDP Per Capita (1970-2022)', loc='left')

plt.tight_layout()
Figure 1: GDP per Capita (1970 - 2022)

Average (median) GPD per capita has increased from below $500 in 1970 to almost $7000 by 2022. A lot of that increase looks like it took place in the 2000s

Median

We have used the median for our average. The median is the value at or below which 50% of the data points exist. The median is also know as the 50th percentile.

By plotting other percentiles we can get a more detailed picture of the distribution of our data. Let’s add in the 25th percentile and the 75th percentile. We can roughly think of the 25th percentile as being the point below which the GDP per capita of the poorest 25% of countries exists; and the 75th percentile as being the point above which the GDP per capita of the richest 25% of countries exists.

As our data spans a broad range of values, a log scale may help us see some of the patterns more clearly. Below we use a log scale for the y-axis.

Code
# construct the plot
fig, ax = plt.subplots()
gdp_percentiles.loc[:,['25th Percentile']].plot(color='black',alpha=0.4, ls='--', lw=2.5,logy=True, ax=ax)
gdp_percentiles.loc[:,['50th Percentile']].plot(color='black',alpha=0.4, ls='-', lw=5.0, ax=ax)
gdp_percentiles.loc[:,['75th Percentile']].plot(color='black',alpha=0.4, ls='--', lw= 2.5, ax=ax)

# format axis
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '${:,g}'.format(y)))
ax.spines[['right', 'top']].set_visible(False)

# format legend, title, etc
ax.get_legend().set_title("")
ax.get_legend().get_frame().set_linewidth(0.0)
ax.set_title('GDP Per Capita (1970-2022)',loc = 'left')
plt.tight_layout()
Figure 2: GDP per Capita (1970 - 2022) with log y-axis

Comparing two countries

For illustrative purposes we will highlight two countries, so that their respective trends in GDP per capita can be compared over time.

The two charts below show the same data from slightly different perspectives. GDP per capita chart uses the absolute GDP per capita values where as the GDP per capita relative to world median chart expresses the GDP per capita values as a proportion of the world median, with the median indexed to 100 (resulting in a perspective that has more of a focus on the performance of countries relative to each other, rather than the absolute changes).

Code
# construct the plot
ax = d.plot(color='grey',alpha=0.12, legend =False, logy=True)
gdp_percentiles.loc[:,['25th Percentile']].plot(color='black',alpha=0.4, ls='--', lw=2.5, ax=ax, legend=False)
gdp_percentiles.loc[:,['50th Percentile']].plot(color='black',alpha=0.4, ls='-', lw=5.0, ax=ax)
gdp_percentiles.loc[:,['75th Percentile']].plot(color='black',alpha=0.4, ls='--', lw= 2.5, ax=ax, legend =False)
d.loc[:,['Japan']].plot(color='blue',alpha=0.8,lw=3, ax=ax)
d.loc[:,['China']].plot(color='red',alpha=0.8,lw=3, ax=ax)

# format axis
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '${:,g}'.format(y)))
ax.spines[['right', 'top']].set_visible(False)

# format legend, title, etc
ax.get_legend().set_title("")
ax.get_legend().get_frame().set_linewidth(0.0)
plt.rc('legend',fontsize=9)
ax.set_title('GDP Per Capita (1970-2022)', loc='left')
ax.annotate('Dashed lines show 25th and 75th percentile',xy=(0.5,0.05), xycoords='axes fraction', color='0.3')

plt.tight_layout()
Figure 3: GDP per Capita (1970 - 2022) with log y-axis. Japan and China highlighted
Code
# prep data
dm50p = d.div(gdp_percentiles['50th Percentile'],axis=0)
dm75p = d.div(gdp_percentiles['75th Percentile'],axis=0)

_75thRelMedian = (gdp_percentiles['75th Percentile'].div(gdp_percentiles['50th Percentile']))
_25thRelMedian = (gdp_percentiles['25th Percentile'].div(gdp_percentiles['50th Percentile']))

# construct the plot
ax = dm50p.plot(color='grey',alpha=0.12, legend =False, logy=True)
pd.Series(index = d.index, data=1, name="Median").plot(color='black',alpha=0.4, ls='-', lw=5.0, legend=True, ax=ax)
_75thRelMedian.plot(color='black',alpha=0.4, ls='--', lw=2.5, ax=ax)
_25thRelMedian.plot(color='black',alpha=0.4, ls='--', lw=2.5, ax=ax)

dm50p.loc[:,['Japan']].plot(color='blue',alpha=0.8,lw=3, ax=ax)
dm50p.loc[:,['China']].plot(color='red',alpha=0.8,lw=3, ax=ax)

# format axis
ax.spines[['right', 'top']].set_visible(False)
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '{:g}'.format(y*100)))

# format legend, title, etc
ax.set_title('GDP per Capita relative to world median', loc='left')
ax.annotate('(world median indexed to 100)',xy=(0.01,0.97), xycoords='axes fraction', color='0.2')
ax.get_legend().set_title("")
ax.get_legend().get_frame().set_linewidth(0.0)
ax.annotate('Dashed lines show 25th and 75th percentile',xy=(0.5,0.05), xycoords='axes fraction', color='0.3')
plt.tight_layout() 
Figure 4: GDP per Capita relative to world median. With log y-axis. Japan and China highlighted
GDP per capita growth
Code
# prep data
fig, ax = plt.subplots()

# construct the plot
d.pct_change().ewm(alpha=0.2).mean().plot(color='grey',alpha=0.07, legend=False,ax=ax)
pd.Series(index = d.index, data=0, name="Zero").plot(color='black',alpha=0.3, ls='--', lw=5.0, legend=False, ax=ax)
d.pct_change()['China'].ewm(alpha=0.2).mean().plot(color='red',lw=3.0, alpha=0.95,legend=True,ax=ax)
d.pct_change()['Japan'].ewm(alpha=0.2).mean().plot(color='blue', lw=3.0, alpha=0.95,legend=True,ax=ax)


# format axis
ax.spines[['right', 'top']].set_visible(False)
ax.set_ylim([-0.1, 0.3])
ax.yaxis.set_major_formatter(mtick.PercentFormatter(xmax=1))

# format legend, title, etc
ax.set_title('GDP per capita growth (annual %)', loc='left')
ax.annotate('(exponential moving average)',xy=(0.01,0.97), xycoords='axes fraction', color='0.2')
ax.get_legend().set_title("")
ax.get_legend().get_frame().set_linewidth(0.0)
ax.annotate('Lines show smoothed trend',xy=(0.5,0.05), xycoords='axes fraction', color='0.3')
plt.tight_layout() 
Figure 5: GDP per capita growth (annual %). Data smoothed by taking the exponential moving average. Japan and China highlighted