Python multi-timeseries#

Software requirements:

  • Python 3

  • Xarray

  • matplotlib

Example script#

multi_timeseries.py

#!/usr/bin/env python
# coding: utf-8
''''
DKRZ example

Plot multiple ensemble means historical, rcp4.5, and rcp8.5

This example demonstrates how to read and plot the time series data of multiple
model files for Historical and RCP-4.5 and RCP-8.5 ensemble runs.

Content

- create multiple line plots in one figure
- add a legend
- add a title
- add x-label and y-label
- save to PNG

-------------------------------------------------------------------------------
2021 copyright DKRZ licensed under CC BY-NC-SA 4.0 <br>
               (https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)
-------------------------------------------------------------------------------
'''
import numpy as np
import xarray as xr
import matplotlib.pyplot as plt

def main():
    # Input files
    # Data files for model 1
    hist_model1  = 'tas_mod1_hist_rectilin_grid_2D.nc'
    rcp45_model1 = 'tas_mod1_rcp45_rectilin_grid_2D.nc'
    rcp85_model1 = 'tas_mod1_rcp85_rectilin_grid_2D.nc'

    # Data files for model 2
    hist_model2  = 'tas_mod2_hist_rectilin_grid_2D.nc'
    rcp45_model2 = 'tas_mod2_rcp45_rectilin_grid_2D.nc'
    rcp85_model2 = 'tas_mod2_rcp85_rectilin_grid_2D.nc'

    # Data files for model 3
    hist_model3  = 'tas_mod3_hist_rectilin_grid_2D.nc'
    rcp45_model3 = 'tas_mod3_rcp45_rectilin_grid_2D.nc'
    rcp85_model3 = 'tas_mod3_rcp85_rectilin_grid_2D.nc'

    # Data file for model 4
    hist_model4  = 'tas_mod4_hist_rectilin_grid_2D.nc'
    rcp45_model4 = 'tas_mod4_rcp45_rectilin_grid_2D.nc'
    rcp85_model4 = 'tas_mod4_rcp85_rectilin_grid_2D.nc'

    # We use Xarray to open the Historical, RCP-4.5, and RCP-8.5 datasets.
    ds1_hist = xr.open_dataset('../../data/'+hist_model1)
    ds2_hist = xr.open_dataset('../../data/'+hist_model2)
    ds3_hist = xr.open_dataset('../../data/'+hist_model3)
    ds4_hist = xr.open_dataset('../../data/'+hist_model4)

    ds1_rcp45 = xr.open_dataset('../../data/'+rcp45_model1)
    ds2_rcp45 = xr.open_dataset('../../data/'+rcp45_model2)
    ds3_rcp45 = xr.open_dataset('../../data/'+rcp45_model3)
    ds4_rcp45 = xr.open_dataset('../../data/'+rcp45_model4)

    ds1_rcp85 = xr.open_dataset('../../data/'+rcp85_model1)
    ds2_rcp85 = xr.open_dataset('../../data/'+rcp85_model2)
    ds3_rcp85 = xr.open_dataset('../../data/'+rcp85_model3)
    ds4_rcp85 = xr.open_dataset('../../data/'+rcp85_model4)

    # Time
    # Retrieve the years of Historical and RCP runs and create an array containing all.
    nyears_hist = ds1_hist.time.size
    nyears_rcp = ds1_rcp45.time.size
    years = xr.concat([ds1_hist['time.year'], ds1_rcp45['time.year']], dim='time')

    # Define colors and line style
    colors    = {'model1':'blue', 'model2':'red', 'model3':'green', 'model4':'orange'}
    colorhist = {'model1':'black', 'model2':'dimgray', 'model3':'gray', 'model4':'silver',}
    linestyles = {'line':'-', 'dashdot':'-.', 'dotted':':', 'dashdash':'--'}
    linewidth = 1.0

    # Define plot settings
    times = [years[0:ds1_hist.time.size], years[ds1_hist.time.size:len(years)+1], years[ds1_hist.time.size:len(years)+1]]
    styles = [linestyles['line'], linestyles['line'], linestyles['dashdash']]

    model1 = [ds1_hist.tas.squeeze(), ds1_rcp45.tas.squeeze(), ds1_rcp85.tas.squeeze()]
    labels1 = ['model 1 historical', 'model 1 rcp4.5', 'model 1 rcp8.5']
    colors1 = [colorhist['model1'], colors['model1'], colors['model1']]

    model2 = [ds2_hist.tas.squeeze(), ds2_rcp45.tas.squeeze(), ds2_rcp85.tas.squeeze()]
    labels2 = ['model 2 historical', 'model 2 rcp4.5', 'model 2 rcp8.5']
    colors2 = [colorhist['model2'], colors['model2'], colors['model2']]

    model3 = [ds3_hist.tas.squeeze(), ds3_rcp45.tas.squeeze(), ds3_rcp85.tas.squeeze()]
    labels3 = ['model 3 historical', 'model 3 rcp4.5', 'model 3 rcp8.5']
    colors3 = [colorhist['model3'], colors['model3'], colors['model3']]

    model4 = [ds4_hist.tas.squeeze(), ds4_rcp45.tas.squeeze(), ds4_rcp85.tas.squeeze()]
    labels4 = ['model 4 historical', 'model 4 rcp4.5', 'model 4 rcp8.5']
    colors4 = [colorhist['model4'], colors['model4'], colors['model4']]

    # Create the plot
    plt.switch_backend('agg')

    fig, ax = plt.subplots(figsize=(14,7), facecolor='white')
    ax.set_facecolor('white')

    ax.grid()
    ax.set_xlim(years[0],years[-1])
    ax.set_ylim(292,300)
    ax.set_xlabel('years')
    ax.set_ylabel(ds1_hist.tas.long_name+' ['+ds1_hist.tas.units+']')
    ax.yaxis.set_ticks_position('both')
    ax2 = ax.twinx()   # add y-axis annotations to the right
    ax2.set_ylim(ax.get_ylim())

    for i, model in enumerate(model1):
        ax.plot(times[i],
                model,
                label=labels1[i],
                color=colors1[i],
                lw=linewidth,
                linestyle=styles[i])

    for i, model in enumerate(model2):
        ax.plot(times[i],
                model,
                label=labels2[i],
                color=colors2[i],
                lw=linewidth,
                linestyle=styles[i])

    for i, model in enumerate(model3):
        ax.plot(times[i],
                model,
                label=labels3[i],
                color=colors3[i],
                lw=linewidth,
                linestyle=styles[i])

    for i, model in enumerate(model4):
        ax.plot(times[i],
                model,
                label=labels4[i],
                color=colors4[i],
                lw=linewidth,
                linestyle=styles[i])

    # add a legend
    legend = ax.legend(loc='center left',
                       bbox_to_anchor=(1.05,0.8),
                       handlelength=2.9,
                       shadow=True,
                       fontsize='small')
    legend.get_frame().set_facecolor('whitesmoke')

    # add text
    plt.gcf().text(0.5, 0.99, 'DKRZ example: tas ensemble global yearly mean', ha='center', fontsize=20)
    plt.gcf().text(0.5, 0.90, '2m temperature', ha='center', fontfamily='monospace', fontsize=10)

    # text top left side
    plt.gcf().text(0.13, 0.94, 'Project:  project name', fontfamily='monospace', fontsize=10)
    plt.gcf().text(0.13, 0.915, 'Model:    model', fontfamily='monospace', fontsize=10)

    # text top right side
    plt.gcf().text(0.76, 0.94, 'Lat:    -45.76 - 42.24', ha='left', fontfamily='monospace', fontsize=10)
    plt.gcf().text(0.76, 0.92, 'Lon:    -24.64 - 60.28', ha='left', fontfamily='monospace', fontsize=10)
    plt.gcf().text(0.76, 0.90, 'Data:   yearly mean', ha='left', fontfamily='monospace', fontsize=10)

    plt.savefig('plot_multi_timeseries_example.png', bbox_inches='tight', dpi=100)


if __name__ == '__main__':
    main()
    
    

Plot result:

image0