Emissions and Emissions per capita

In this tutorial I will use openclimate to create a time series emissions and emissions per capita for countries.

[1]:
from itertools import cycle
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
import numpy as np
import pandas as pd
[2]:
from openclimate import Client
client = Client()
client.jupyter

Let’s start by getting all the country codes

[3]:
df_names = client.parts('EARTH')[['actor_id', 'name']]
actor_ids = tuple(client.parts('EARTH')['actor_id'])

Emissions

Let’s use fossil CO2 emissions from the Global Carbon Budget 2022. You can use client.emissions_datasets() to list all datasets available. Be a little patient, this takes about 20 seconds to retrieve the data for 250 countries.

[4]:
%%time
df_emissions = client.emissions(actor_ids, 'GCB2022:national_fossil_emissions:v1.0')
CPU times: user 5.49 s, sys: 269 ms, total: 5.76 s
Wall time: 20.5 s

This returns a dataframe with total_emissions in tonnes of CO2.

[5]:
df_emissions.sample(5)
[5]:
actor_id year total_emissions datasource_id
202 EE 1968 21716765 GCB2022:national_fossil_emissions:v1.0
170 PH 1996 61255046 GCB2022:national_fossil_emissions:v1.0
52 BN 1930 0 GCB2022:national_fossil_emissions:v1.0
94 MY 1900 58624 GCB2022:national_fossil_emissions:v1.0
207 AR 2010 186733136 GCB2022:national_fossil_emissions:v1.0

Lets’s first rank the countries by the their emissions in the most recent year and display the top 10 emitters.

[6]:
year = df_emissions.year.max()
df_recent = (
    df_emissions
    .loc[df_emissions.year == year]
    .assign(rank = lambda x: x['total_emissions'].rank(ascending=False))
    .assign(percent_of_global = lambda x: (x['total_emissions'] / x['total_emissions'].sum()) * 100)
    .sort_values(by='rank')
    .merge(df_names, on='actor_id')
    .loc[:, ['rank', 'name', 'actor_id', 'year', 'total_emissions', 'percent_of_global']]
)
df_recent.head(10)
[6]:
rank name actor_id year total_emissions percent_of_global
0 1.0 China CN 2021 11472369170 31.777308
1 2.0 United States of America US 2021 5007335888 13.869816
2 3.0 India IN 2021 2709683624 7.505551
3 4.0 Russian Federation RU 2021 1755547389 4.862690
4 5.0 Japan JP 2021 1067398435 2.956586
5 6.0 Iran IR 2021 748878751 2.074319
6 7.0 Germany DE 2021 674753565 1.868999
7 8.0 Saudi Arabia SA 2021 672379870 1.862425
8 9.0 Indonesia ID 2021 619277532 1.715336
9 10.0 Korea, the Republic of KR 2021 616074996 1.706466

China was responbible for the lion’s share of global CO2 emissions in 2021 at nearly 32%. This is as much as the next 6 countries combined! However, this is just a snapshot in time. Let’s plot time series for each of the top 7 emitters.

[7]:
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111)

# top 7 emitters
top_emitters = list(df_recent.head(7).actor_id)

# wong color palette (https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40)
colors = ['#000000', '#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7']

for actor_id, color in zip(top_emitters, cycle(colors)):

    actor_name = df_names.loc[df_names['actor_id'] == actor_id, 'name'].values[0]
    filt = df_emissions['actor_id'] == actor_id
    df_tmp = df_emissions.loc[filt]

    ax.plot(np.array(df_tmp['year']), np.array(df_tmp['total_emissions']) / 10**9,
            linewidth=4,
            label = actor_name,
            color=color)

    ylim = [0, 12]
    ax.set_ylim(ylim)
    ax.set_xlim([1850, 2022])

    # Turn off the display of all ticks.
    ax.tick_params(which='both',     # Options for both major and minor ticks
                   top='off',        # turn off top ticks
                   left='off',       # turn off left ticks
                   right='off',      # turn off right ticks
                   bottom='off')     # turn off bottom ticks

    # Remove x tick marks
    plt.setp(ax.get_xticklabels(), rotation=0)

    # Hide the right and top spines
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.spines['bottom'].set_visible(False)

    # Only show ticks on the left and bottom spines
    ax.yaxis.set_ticks_position('left')
    ax.xaxis.set_ticks_position('bottom')

    # major/minor tick lines
    ax.xaxis.set_minor_locator(AutoMinorLocator(5))
    ax.grid(axis='y',
            which='major',
            color=[0.8, 0.8, 0.8], linestyle='-')

    ax.set_ylabel("Emissions (GCO$_2$e)", fontsize=12)
    ax.legend(loc='upper left', frameon=False)
../_images/notebooks_emissions_and_emissions_per_capita_12_0.png

This tells a richer story. Now we see the US was the main annual contributor up until about the year 2000. After which, Chinese emissions sky rocketed while US emissions started declining.

An interesting feature in this graph is the dramatic drop in Russian emissions. This corresponds to the fall of the Soviet Union, which led to a huge drop in emissions. Key drivers of the emissions reductions were the decreasing beef consumption in the 1990s and carbon sequestration in soils on abandoned cropland Schierhorn et al., (2019).

Emissions per capita

Let’s retrieve population data and calulate emissions per capita for the seven countries with the highest annual emissions.

[8]:
# emissions for top seven countries with highest annual emissions in 2021
df_pop = client.population(tuple(df_recent.head(7)['actor_id']))

# calculate emissions per capita
df_percap = pd.merge(df_emissions, df_pop, on=['actor_id', 'year'])[['actor_id', 'year', 'total_emissions', 'population']]
df_percap = df_percap.assign(total_emissions_per_capita = lambda x: x['total_emissions'] / (x['population']))
[9]:
year = df_percap.year.max()
df_recent_percap = (
    df_percap
    .loc[df_percap.year == year]
    .assign(rank = lambda x: x['total_emissions_per_capita'].rank(ascending=False))
    .assign(percent_of_global = lambda x: (x['total_emissions'] / x['total_emissions'].sum()) * 100)
    .sort_values(by='rank')
    .merge(df_names, on='actor_id')
    .loc[:, ['rank', 'name', 'actor_id', 'year', 'total_emissions_per_capita', 'percent_of_global']]
)
[10]:
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111)

# top 7 emitters
top_emitters = list(df_recent_percap.head(7).actor_id)

# wong color palette (https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40)
colors = ['#000000', '#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7']

for actor_id, color in zip(top_emitters, cycle(colors)):

    actor_name = df_names.loc[df_names['actor_id'] == actor_id, 'name'].values[0]
    filt = df_percap['actor_id'] == actor_id
    df_tmp = df_percap.loc[filt]

    ax.plot(np.array(df_tmp['year']), np.array(df_tmp['total_emissions_per_capita']),
            linewidth=4,
            label = actor_name,
            color=color)

    ylim = [0, 30]
    ax.set_ylim(ylim)
    ax.set_xlim([1950, 2022])

    # Turn off the display of all ticks.
    ax.tick_params(which='both',     # Options for both major and minor ticks
                   top='off',        # turn off top ticks
                   left='off',       # turn off left ticks
                   right='off',      # turn off right ticks
                   bottom='off')     # turn off bottom ticks

    # Remove x tick marks
    plt.setp(ax.get_xticklabels(), rotation=0)

    # Hide the right and top spines
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.spines['bottom'].set_visible(False)

    # Only show ticks on the left and bottom spines
    ax.yaxis.set_ticks_position('left')
    ax.xaxis.set_ticks_position('bottom')

    # major/minor tick lines
    ax.xaxis.set_minor_locator(AutoMinorLocator(5))
    ax.grid(axis='y',
            which='major',
            color=[0.8, 0.8, 0.8], linestyle='-')

    ax.set_ylabel("Emissions per capita (tCO$_2$e)", fontsize=12)
    ax.legend(loc='upper left', frameon=False)
../_images/notebooks_emissions_and_emissions_per_capita_17_0.png

This graph shows that the average person in US emits about double the amount of CO2 annually as the average person in China, despite China having nearly 4 times the US population.