Electricity generation in illustrative pathways and by category (Figure 2.16)

Notebook sr15_2.4.2.2_electricity_generation_marker-scenarios

This notebook is based on the Release 1.1 of the IAMC 1.5C Scenario Explorer and Data and refers to the published version of the IPCC Special Report on Global Warming of 1.5C (SR15).

The notebook is run with pyam release 0.5.0.

The source code of this notebook is available on GitHub (release 2.0.2).

sr15_2.4.2.2_electricity_generation_marker-scenarios

IPCC SR15 scenario assessment

Analysis of the electricity generation development
in illustrative pathways

This notebook computes indicators and diagnostics of the electricity sector and fuel mix timeseries for Figure 2.16, focusing on the illustrative pathways and the IEA's 'Faster Transition Scenario' using the 'World Energy Model' in the IPCC's "Special Report on Global Warming of 1.5°C".

The scenario data used in this analysis can be accessed and downloaded at https://data.ene.iiasa.ac.at/iamc-1.5c-explorer.

Load pyam package and other dependencies

In [1]:
import pandas as pd
import numpy as np
import io
import itertools
import yaml
import math
import matplotlib.pyplot as plt
plt.style.use('style_sr15.mplstyle')
%matplotlib inline
import pyam
pyam - INFO: Running in a notebook, setting `pyam` logging level to `logging.INFO` and adding stderr handler

Import scenario data, categorization and specifications files

The metadata file with scenario categorisation and quantitative indicators can be downloaded at https://data.ene.iiasa.ac.at/iamc-1.5c-explorer.
Alternatively, it can be re-created using the notebook sr15_2.0_categories_indicators.

The last cell of this section loads and assigns a number of auxiliary lists as defined in the categorization notebook.

In [2]:
sr1p5 = pyam.IamDataFrame(data='../data/iamc15_scenario_data_world_r2.0.xlsx')
pyam.utils - INFO: Reading `../data/iamc15_scenario_data_world_r2.0.xlsx`
In [3]:
sr1p5.load_meta('sr15_metadata_indicators.xlsx')
pyam.core - INFO: Importing metadata for 416 scenarios (for total of 416)
In [4]:
with open("sr15_specs.yaml", 'r') as stream:
    specs = yaml.load(stream, Loader=yaml.FullLoader)

rc = pyam.run_control()
for item in specs.pop('run_control').items():
    rc.update({item[0]: item[1]})
cats = specs.pop('cats')
cats_15_no_lo = specs.pop('cats_15_no_lo')
marker = specs.pop('marker')

Downselect scenario ensemble to categories of interest for this assessment

In [5]:
cats.remove('Above 2C')
In [6]:
years = [2030, 2050, 2100]
In [7]:
df = sr1p5.filter(category=cats, year=years)

Set specifications for filter and plotting

In [8]:
save_name = 'output/fig2.16{}.png'
In [9]:
filter_args = dict(df=sr1p5, category=cats, marker=None, join_meta=True)

Retrieve historical data from IEA Energy Statistics

In [10]:
hist = sr1p5.filter(model='Reference', scenario='IEA Energy Statistics (r2017)')
In [11]:
fossil_vars = [
    'Secondary Energy|Electricity|Coal',
    'Secondary Energy|Electricity|Oil',
    'Secondary Energy|Electricityy|Gas'
]

ren_vars = [
    'Secondary Energy|Electricity|Geothermal',
    'Secondary Energy|Electricity|Hydro',
    'Secondary Energy|Electricity|Ocean',
]

hist_mapping = {}

for f in fossil_vars:
    hist_mapping.update({f: 'Fossil without CCS'})
for r in ren_vars:
    hist_mapping.update({r: 'Other renewables'})

hist_mapping.update({
    'Secondary Energy|Electricity|Biomass': 'Biomass without CCS'})

hist.rename({'variable': hist_mapping}, inplace=True)
In [12]:
hist_args = dict(color='black', linestyle='dashed', linewidth=1)

Add IEA's 'Faster Transition Scenario' to the set of marker scenarios for comparison

In [13]:
m = 'IEA WEM'
col = 'marker'
df.set_meta(m, col,
            df.filter(model='IEA World Energy Model 2017',
                      scenario='Faster Transition Scenario'))
rc.update({'marker': {col: {m: 'o'}},
           'c': {col: {m: 'red'}},
           'edgecolors': {col: {m: 'black'}}}
         )
marker += [m]

Rename variables for plots

In [14]:
variable_mapping = [
    ('Fossil without CCS', 
         ['Secondary Energy|Electricity|Coal|w/o CCS',
          'Secondary Energy|Electricity|Gas|w/o CCS',
          'Secondary Energy|Electricity|Oil|w/o CCS'], 'black'),
    ('Fossil with CCS',
         ['Secondary Energy|Electricity|Coal|w/ CCS',
          'Secondary Energy|Electricity|Gas|w/ CCS',
          'Secondary Energy|Electricity|Oil|w/ CCS'], 'grey'),
    ('Biomass without CCS', 'Secondary Energy|Electricity|Biomass|w/o CCS',
        'forestgreen'),
    ('Biomass with CCS', 'Secondary Energy|Electricity|Biomass|w/ CCS',
        'limegreen'),
    ('Nuclear', 'Secondary Energy|Electricity|Nuclear', 'firebrick'),
    ('Wind', 'Secondary Energy|Electricity|Wind', 'lightskyblue'),
    ('Solar', 'Secondary Energy|Electricity|Solar', 'gold'),
    ('Other renewables',
         ['Secondary Energy|Electricity|Ocean',
          'Secondary Energy|Electricity|Geothermal',
          'Secondary Energy|Electricity|Hydro'], 'darkorange')
]
In [15]:
variables = []
mapping = {}

for (name, variable, color) in variable_mapping:
    variables.append(name)
    if isinstance(variable, list):
        for v in variable:
            mapping.update({v: name})
    else:
        mapping.update({variable: name})
    rc.update({'color': {'marker': {name: color}}})

df.rename({'variable': mapping}, inplace=True)
hist.rename({'variable': mapping}, inplace=True)
In [16]:
df.filter(variable=variables, inplace=True)
hist.filter(variable=variables + ['Secondary Energy|Electricity'],
            inplace=True)

Plot by marker scenario

In [17]:
w, h = plt.figaspect(0.3)
fig = plt.figure(figsize=(w, h))
ymax = 680
hist_yr = 2015

_years = len(years) - 1
label_list = []

w = 0.5 / len(years)

for i, m in enumerate(marker):
    _df = df.filter(marker=m).timeseries()
    meta = _df.iloc[0].name[0:2]
    _label = '{}\n{}\n({})'.format(meta[0], meta[1], m)
    _df.index = _df.index.droplevel([0, 1, 2, 4])
    
    # use _df.columns because not all scenarios extend until 2100
    pos = [0.5 / _years * (j - (len(_df.columns) - 1) / 2) + i
           for j in range(len(_df.columns))]
    b = [0] * len(_df.columns)

    for v in variables:
        if v in _df.index:
            lst = _df.loc[v]
            plt.bar(x=pos, height=lst, bottom=b, width=w,
                    color=rc['color']['marker'][v],
                    edgecolor='black', label=None)
            b += _df.loc[v]

    label_list.append(_label)

    val = (
        hist.filter(variable='Secondary Energy|Electricity')
        .timeseries()[hist_yr]
    )
    plt.hlines(y=val, xmin=(-.4 + i),
               xmax=(.4 + i), **hist_args,
               label=None)

    # add years at the top
    for j, yr in enumerate(_df.columns):
        plt.text(pos[j] - 0.1, ymax * 1.05, yr)    
    
# add legend entries
plt.hlines(y=[], xmin=[], xmax=[], **hist_args,
           label='{} Electricity Generation (IEA Energy Statistics 2017)'.format(hist_yr))
for v in variables:
    plt.scatter(x=[], y=[], color=rc['color']['marker'][v], label=v)

plt.legend()
plt.grid(False)
plt.xlim(-0.5, (i + 0.6))
plt.xticks(range(0, i + 1), label_list)
plt.vlines(x=[_i + 0.5 for _i in range(i)], ymin=0, ymax=ymax, colors='white')
plt.ylim(0, ymax)
plt.ylabel('Electricity generation by illustrative pathway (EJ/y)')

fig.savefig(save_name.format('a_electricity_generation_by_marker'))

Plot energy system development by fuel for all 1.5°C pathways with limited overshoot

In [18]:
w, h = plt.figaspect(0.3)
fig = plt.figure(figsize=(w, h))
ymax = 220
hist_yr = 2015

_years = len(years) - 1
label_list = []

def marker_args(m):
    return dict(zorder=4,
                edgecolors=rc['edgecolors']['marker'][m],
                c=rc['c']['marker'][m],
                marker=rc['marker']['marker'][m],
                linewidths=1)

for i, v in enumerate(variables):
    _df = df.filter(variable=v).timeseries()
    _df = pyam.filter_by_meta(_df, df, category=None, marker=None, join_meta=True)
    
    for j, y in enumerate(years):
        _df_15 = _df[_df.category.isin(cats_15_no_lo)]
        lst = _df_15[y][~np.isnan(_df[y])]
        pos = 0.5 / _years * (j - _years / 2) + i
        
        outliers = len(lst[lst > ymax])
        if outliers > 0:
            plt.text(pos - 0.01 * len(years), ymax * 1.01, outliers)

        p = plt.boxplot(lst, positions=[pos],
                        whis='range',
                        patch_artist=True)
        plt.setp(p['boxes'], color=rc['color']['marker'][v])
        plt.setp(p['medians'], color='black')
        
        for m in marker:
            val = _df.loc[_df.marker == m, y]
            if not val.empty:
                plt.scatter(x=pos, y=val, **marker_args(m),
                            s=40, label=None)

    if v in list(hist.variables()):
        val = hist.filter(variable=v).timeseries()[hist_yr]
        plt.hlines(y=val, xmin=(-.4 + i), xmax=(.4 + i), **hist_args,
                   label=None)
                
    label_list.append(v)

# add legend entries
plt.hlines(y=[], xmin=[], xmax=[], **hist_args,
           label='{} Electricity Generation (IEA Energy Statistics 2017)'.format(hist_yr))
for m in marker:
    meta = df.filter(marker=m).timeseries().iloc[0].name[0:2]
    _label = '{}|{} ({})'.format(meta[0], meta[1], m)
    plt.scatter(x=[], y=[], **marker_args(m), s=60, label=_label)

# add years at the top
for _i in range(0, i + 1):
    for j, yr in enumerate(years):
        plt.text(0.5 / _years * (j - _years / 2) + _i - 0.1,
                 ymax * 1.05, yr)

# plt.legend()
plt.grid(False)
plt.xlim(-0.6, (i + 0.6))
plt.xticks(range(0, i + 1), label_list)
plt.vlines(x=[_i + 0.5 for _i in range(i)], ymin=0, ymax=ymax, colors='white')
plt.ylim(0, ymax)
plt.ylabel('Electricity generation by fuel type (EJ/y)')

fig.savefig(save_name.format('b_electricity_generation_by_fuel'))

Export timeseries data to xlsx

In [19]:
writer = pd.ExcelWriter('output/fig2.16_data_table.xlsx')
pyam.utils.write_sheet(writer, name, 
                       pyam.filter_by_meta(df.timeseries(), df, category=None, marker=None, join_meta=True),
                       index=True)
writer.save()
In [ ]: