Create animated GIFs based on CCCma data

By David Taylor, www.prooffreader.com

See the CCCma_Basemap IPython notebook in this repo for more explanation of CCCma NetCDF files and how they are manipulated here

Choose global variables

my_path should point to a directory containing only files .nc files that are named something like the following:

snc_NAM-44_CCCma-CanESM2_rcp85_r1i1p1_CCCma-CanRCM4_r2_day_20410101-20451231.nc


In [1]:
my_path = r'F:\Data\snc-climate'
my_month, my_day = (12, 25) # will extract data every year on Christmas Day
my_variable = 'snc'

In [2]:
from __future__ import print_function # to increase compatibility with Python 3.x

import netCDF4 # Not part of standard Python, you may have to download and install it
import numpy as np
import re
import glob
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
%matplotlib inline

Create background map


In [6]:
fig = plt.figure(figsize=(12,12))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
m = Basemap(width=6000000,height=5200000,
            resolution='l',projection='stere',\
            lon_0=-93,lat_0=44, area_thresh=1000)
m.bluemarble()
m.drawstates()
m.drawcountries()

datatxt = 'Data: Canadian Centre for Climate Modeling and Analysis, Model CCGM4/CanESM2/RCP8.5'
plt.text(0.01, 0.02,datatxt, horizontalalignment='left',
         verticalalignment='center',transform=ax.transAxes, fontdict={'family' : 'sans',
        'color'  : 'white',
        'weight' : 'bold',
        'size'   : 10,
        })

plt.text(0.99, 0.02,'www.prooffreader.com', horizontalalignment='right',
         verticalalignment='center',transform=ax.transAxes, fontdict={'family' : 'serif',
        'color'  : 'white',
        'weight' : 'bold',
        'size'   : 10,
        })

plt.text(0.02, 0.98,'Projected White Christmases until the year 2100', horizontalalignment='left',
         verticalalignment='top',transform=ax.transAxes, fontdict={'family' : 'sans',
        'color'  : 'black',
        'weight' : 'bold',
        'size'   : 18,
        }, bbox=dict(boxstyle="square", fc="w"))

plt.savefig('back.png')
plt.show()


Read .nc files and create image masks


In [8]:
#make list of cumulative month lengths for calculations
month_lengths = (0,31,28,31,30,31,30,31,31,30,31,30) # 0 & Jan-Nov
month_cumulative = []
counter = 0
for length in month_lengths:
    counter += length
    month_cumulative.append(counter)

# get list of .nc files in directory
nc_files = glob.glob(my_path+'/*.nc')

for my_filename in nc_files:
    
    ncfile = netCDF4.Dataset(my_filename, 'r')

    to_find = '([12][90][0-9]{2})[01][0-9][0-3][0-9]\-([12][901][0-9]{2})[01][0-9][0-3][0-9]\.nc'
    first_year = int(re.search(to_find, my_filename).group(1))
    last_year = int(re.search(to_find, my_filename).group(2))

    nc_lons = np.array(ncfile.variables['lon'])
    nc_lats = np.array(ncfile.variables['lat'])
    nc_vars = np.array(ncfile.variables[my_variable])

    for my_year in range(first_year, last_year + 1):
        print(my_year, " ", end="")
        days_elapsed = 365 * (my_year - first_year) + month_cumulative[my_month - 1] + my_day
        nc_vars_this_year = nc_vars[days_elapsed]
        fig = plt.figure(figsize=(12,12))
        ax = fig.add_axes([0.1,0.1,0.8,0.8])
        m = Basemap(width=6000000,height=5200000,
            resolution='l',projection='stere',\
            lon_0=-93,lat_0=44, area_thresh=1000)
        x, y = m(nc_lons, nc_lats)

        cdict = {'red':   [(0.0,  0.0, 0.0), # color map from black to white
                           (1.0,  1.0, 1.0)],
                 'green': [(0.0,  0.0, 0.0),
                           (1.0,  1.0, 1.0)],
                 'blue':  [(0.0,  0.0, 0.0),
                           (1.0,  1.0, 1.0)]}

        my_cmap = LinearSegmentedColormap('CustomMap', cdict)

        clevs = range(0,101)

        cs = m.contourf(x,y,nc_vars_this_year,clevs,cmap=my_cmap)
        plt.text(0.91, 0.35,'Dec.25,', horizontalalignment='center',
                 verticalalignment='bottom',transform=ax.transAxes, fontdict={'family' : 'monospace',
                'color'  : 'white',
                'weight' : 'bold',
                'size'   : 23,
                })
        plt.text(0.91, 0.34,str(my_year), horizontalalignment='center',
                 verticalalignment='top',transform=ax.transAxes, fontdict={'family' : 'monospace',
                'color'  : 'white',
                'weight' : 'bold',
                'size'   : 27,
                })
        plt.text(0.02, 0.98,'Projected White Christmases until the year 2099', horizontalalignment='left',
                 verticalalignment='top',transform=ax.transAxes, fontdict={'family' : 'sans',
                'color'  : 'black',
                'weight' : 'bold',
                'size'   : 18,
                }, bbox=dict(boxstyle="square", fc="k"))
        plt.savefig('mask'+str(my_year)+'.png')
        #plt.show()
        plt.close()


2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  2025  2026  2027  2028  2029  2030  2031  2032  2033  2034  2035  2036  2037  2038  2039  2040  2041  2042  2043  2044  2045  2046  2047  2048  2049  2050  2051  2052  2053  2054  2055  2056  2057  2058  2059  2060  2061  2062  2063  2064  2065  2066  2067  2068  2069  2070  2071  2072  2073  2074  2075  2076  2077  2078  2079  2080  2081  2082  2083  2084  2085  2086  2087  2088  2089  2090  2091  2092  2093  2094  2095  2096  2097  2098  2099  2100  

Use masks to make composite images


In [1]:
from PIL import Image

background = 'back.png'

for year in range(2011, 2101):
    maskname = 'mask' + str(year) + '.png'
    back = Image.open(background, 'r')
    mask = Image.open(maskname, 'r')
    mask = mask.convert("L")
    back.paste(mask, mask=mask)
    back.save('snc'+str(year)+'.png')

Use Photoshop to create GIF


In [ ]: