def sst_sss_seasonal (mesh_path, file_path1, file_path2, save=False, fig_name=None):

    # FESOM parameters
    circumpolar=True
    mask_cavities=True
    # Season names for plot titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Build FESOM mesh
    elements, patches = make_patches(mesh_path, circumpolar, mask_cavities)

    # Figure out how many 2D nodes there are
    file = open(mesh_path + 'nod2d.out', 'r')
    file.readline()
    n2d = 0
    for line in file:
        n2d += 1
    file.close()

    # Get seasonal averages of the 3D FESOM output
    temp = seasonal_avg(file_path1, file_path2, 'temp')
    salt = seasonal_avg(file_path1, file_path2, 'salt')
    # Select the surface layer
    sst = temp[:,:n2d]
    sss = salt[:,:n2d]

    # Plot
    fig = figure(figsize=(20,9))
    # Loop over seasons
    for season in range(4):
        # SST
        # Build an array of FESOM data values corresponding to each Element
        values1 = []
        for elm in elements:
            # For each element not in an ice shelf cavity, append the mean
            # value for the 3 component Nodes
            if not elm.cavity:
                values1.append(mean([sst[season,elm.nodes[0].id], sst[season,elm.nodes[1].id], sst[season,elm.nodes[2].id]]))
        ax = fig.add_subplot(2, 4, season+1, aspect='equal')
        img = PatchCollection(patches, cmap='RdBu_r' )#jet)
        img.set_array(array(values1))
        #img.set_clim(vmin=-2, vmax=10)
        img.set_clim(vmin=-4, vmax=4)
        img.set_edgecolor('face')
        ax.add_collection(img)
        xlim([-35, 35])
        ylim([-33, 37])
        axis('off')
        if season == 0:
            text(-39, 0, r'SST ($^{\circ}$C)', fontsize=21, ha='right')
        title(season_names[season], fontsize=24)
        if season == 3:
            cbaxes1 = fig.add_axes([0.92, 0.55, 0.01, 0.3])            
            #cbar1 = colorbar(img, ticks=arange(-2,10+4,4), cax=cbaxes1)
            cbar1 = colorbar(img, ticks=arange(-4,4+2,2), cax=cbaxes1)
            cbar1.ax.tick_params(labelsize=16)
        # SSS
        values2 = []
        for elm in elements:
            # For each element not in an ice shelf cavity, append the mean
            # value for the 3 component Nodes
            if not elm.cavity:
                values2.append(mean([sss[season,elm.nodes[0].id], sss[season,elm.nodes[1].id], sss[season,elm.nodes[2].id]]))
        ax = fig.add_subplot(2, 4, season+5, aspect='equal')
        img = PatchCollection(patches, cmap='RdBu_r') #jet)
        img.set_array(array(values2))
        #img.set_clim(vmin=33, vmax=35)
        img.set_clim(vmin=-0.5, vmax=0.5)
        img.set_edgecolor('face')
        ax.add_collection(img)
        xlim([-35, 35])
        ylim([-33, 37])
        axis('off')
        if season == 0:
            text(-39, 0, 'SSS (psu)', fontsize=21, ha='right')
        if season == 3:
            cbaxes2 = fig.add_axes([0.92, 0.15, 0.01, 0.3])
            #cbar2 = colorbar(img, ticks=arange(33,35+0.5,0.5), cax=cbaxes2)
            cbar2 = colorbar(img, ticks=arange(-0.5,0.5+0.25,0.25), cax=cbaxes2)
            cbar2.ax.tick_params(labelsize=16)
    # Decrease space between plots
    subplots_adjust(wspace=0.025,hspace=0.025)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
def sose_fesom_seasonal(elements,
                        file_path1,
                        file_path2,
                        var_name,
                        lon0,
                        depth_min,
                        save=False,
                        fig_name=None):

    # Path to SOSE seasonal climatology file
    sose_file = '/short/m68/kaa561/SOSE_seasonal_climatology.nc'
    lat_max = -60  #-30
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Bounds on colour scale
    if var_name == 'temp':
        var_min = -2.5
        var_max = 3.5  #7.5
        var_ticks = 1
    elif var_name == 'salt':
        var_min = 33.8
        var_max = 34.8
        var_ticks = 0.2
    else:
        print 'Unknown variable ' + var_name
        return

    # Choose what to write on the title about the variable
    if var_name == 'temp':
        var_string = r'Temperature ($^{\circ}$C)'
    elif var_name == 'salt':
        var_string = 'Salinity (psu)'
    # Choose what to write on the title about longitude
    if lon0 < 0:
        lon_string = ' at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = ' at ' + str(int(round(lon0))) + r'$^{\circ}$E'

    print 'Processing SOSE data'
    # Read grid and 3D data (already seasonally averaged)
    id = Dataset(sose_file, 'r')
    lon_sose = id.variables['longitude'][0, :]
    lat_sose = id.variables['latitude'][:, 0]
    z_sose = id.variables['depth'][:]
    var_3d_sose = id.variables[var_name][:, :, :, :]

    # Calculate zonal slices for each season
    var_sose = ma.empty([4, size(z_sose), size(lat_sose, 0)])
    var_sose[:, :, :] = 0.0
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        var_sose[season, :, :] = interp_lon_sose(var_3d_sose[season, :, :, :],
                                                 lon_sose, lon0)

    # Get seasonal averages of the FESOM output
    fesom_data = seasonal_avg(file_path1, file_path2, var_name)

    # Set colour levels
    lev = linspace(var_min, var_max, num=50)

    # Choose southern boundary based on extent of SOSE grid
    lat_min = amin(lat_sose)

    # Plot
    fig = figure(figsize=(20, 9))
    for season in range(4):
        # FESOM
        print 'Calculating zonal slices for ' + season_names[season]
        patches, values, tmp = side_patches(elements, lat_max, lon0,
                                            fesom_data[season, :])
        ax = fig.add_subplot(2, 4, season + 1)
        img = PatchCollection(patches, cmap=jet)
        img.set_array(array(values))
        img.set_edgecolor('face')
        img.set_clim(vmin=var_min, vmax=var_max)
        ax.add_collection(img)
        xlim([lat_min, lat_max])
        ylim([depth_min, 0])
        title('FESOM (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
        # SOSE
        fig.add_subplot(2, 4, season + 5)
        pcolormesh(lat_sose,
                   z_sose,
                   var_sose[season, :, :],
                   vmin=var_min,
                   vmax=var_max,
                   cmap='jet')
        xlim([lat_min, lat_max])
        ylim([depth_min, 0])
        title('SOSE (' + season_names[season] + ')', fontsize=24)
        xlabel('Latitude', fontsize=18)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
    # Add colorbar
    cbaxes = fig.add_axes([0.93, 0.2, 0.015, 0.6])
    cbar = colorbar(img,
                    cax=cbaxes,
                    ticks=arange(var_min, var_max + var_ticks, var_ticks))
    cbar.ax.tick_params(labelsize=16)
    # Add the main title
    suptitle(var_string + lon_string, fontsize=30)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
def aice_hi_seasonal(mesh_path,
                     file_path1,
                     file_path2,
                     save=False,
                     fig_name=None):

    # FESOM parameters
    circumpolar = True
    mask_cavities = True
    # Season names for plot titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Build FESOM mesh
    elements, patches = make_patches(mesh_path, circumpolar, mask_cavities)

    # Get seasonal averages of the FESOM output
    aice = seasonal_avg(file_path1, file_path2, 'area')
    hi = seasonal_avg(file_path1, file_path2, 'hice')

    # Plot
    fig = figure(figsize=(20, 9))
    # Loop over seasons
    for season in range(4):
        # aice
        # Build an array of FESOM data values corresponding to each Element
        values1 = []
        for elm in elements:
            # For each element not in an ice shelf cavity, append the mean
            # value for the 3 component Nodes
            if not elm.cavity:
                values1.append(
                    mean([
                        aice[season, elm.nodes[0].id],
                        aice[season, elm.nodes[1].id], aice[season,
                                                            elm.nodes[2].id]
                    ]))
        ax = fig.add_subplot(2, 4, season + 1, aspect='equal')
        img = PatchCollection(patches, cmap=jet)
        img.set_array(array(values1))
        #img.set_clim(vmin=-1, vmax=1)
        img.set_clim(vmin=0, vmax=1)
        img.set_edgecolor('face')
        ax.add_collection(img)
        xlim([-35, 35])
        ylim([-33, 37])
        axis('off')
        if season == 0:
            text(-39, 0, 'aice (%)', fontsize=21, ha='right')
        title(season_names[season], fontsize=24)
        if season == 3:
            cbaxes1 = fig.add_axes([0.92, 0.55, 0.01, 0.3])
            #cbar1 = colorbar(img, ticks=arange(-1,1+0.5,0.5), cax=cbaxes1)
            cbar1 = colorbar(img, ticks=arange(0, 1 + 0.25, 0.25), cax=cbaxes1)
            cbar1.ax.tick_params(labelsize=16)
        # hi
        values2 = []
        for elm in elements:
            # For each element not in an ice shelf cavity, append the mean
            # value for the 3 component Nodes
            if not elm.cavity:
                values2.append(
                    mean([
                        hi[season, elm.nodes[0].id],
                        hi[season, elm.nodes[1].id], hi[season,
                                                        elm.nodes[2].id]
                    ]))
        ax = fig.add_subplot(2, 4, season + 5, aspect='equal')
        img = PatchCollection(patches, cmap=jet)
        img.set_array(array(values2))
        #img.set_clim(vmin=-0.5, vmax=0.5)
        img.set_clim(vmin=0, vmax=1.5)
        img.set_edgecolor('face')
        ax.add_collection(img)
        xlim([-35, 35])
        ylim([-33, 37])
        axis('off')
        if season == 0:
            text(-39, 0, 'hi (m)', fontsize=21, ha='right')
        if season == 3:
            cbaxes2 = fig.add_axes([0.92, 0.15, 0.01, 0.3])
            #cbar2 = colorbar(img, ticks=arange(-0.5,0.5+0.25,0.25), cax=cbaxes2)
            cbar2 = colorbar(img, ticks=arange(0, 1.5 + 0.5, 0.5), cax=cbaxes2)
            cbar2.ax.tick_params(labelsize=16)
    # Decrease space between plots
    subplots_adjust(wspace=0.025, hspace=0.025)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
Exemple #4
0
def nsidc_aice_seasonal(mesh_path,
                        file_path1,
                        file_path2,
                        save=False,
                        fig_name=None):

    # FESOM parameters
    circumpolar = True
    mask_cavities = True
    # Season names for plot titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']
    # NSIDC file paths
    nsidc_head = '/short/m68/kaa561/nsidc_aice/seaice_conc_monthly_sh'
    nsidc_head_0 = nsidc_head + '_f11_'
    nsidc_head_1 = nsidc_head + '_f13_'
    nsidc_tail = '_v02r00.nc'
    # Degrees to radians conversion factor
    deg2rad = pi / 180.0
    # Number of days per month (just for NSIDC)
    ndays_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

    # Build FESOM mesh
    elements, patches = make_patches(mesh_path, circumpolar, mask_cavities)

    # Get seasonal averages of the FESOM output
    fesom_data = seasonal_avg(file_path1, file_path2, 'area')

    # Read NSIDC grid from the January file
    id = Dataset(nsidc_head_0 + '199501' + nsidc_tail, 'r')
    nsidc_lon = id.variables['longitude'][:, :]
    nsidc_lat = id.variables['latitude'][:, :]
    id.close()

    # Initialise seasonal averages of NSIDC data
    nsidc_data = ma.empty([4, size(nsidc_lon, 0), size(nsidc_lon, 1)])
    nsidc_data[:, :] = 0.0
    # Process one season at a time
    for season in range(4):
        # Figure out which months we care about
        if season == 0:
            # DJF
            nsidc_months = [12, 1, 2]
        elif season == 1:
            # MAM
            nsidc_months = [3, 4, 5]
        elif season == 2:
            # JJA
            nsidc_months = [6, 7, 8]
        elif season == 3:
            # SON
            nsidc_months = [9, 10, 11]
        season_days = 0  # Number of days in season; this will be incremented

        # Process one month at a time
        for month in nsidc_months:
            # Construct NSIDC file path
            if month < 10:
                nsidc_file = nsidc_head_0 + '19950' + str(month) + nsidc_tail
            else:
                nsidc_file = nsidc_head_1 + '1995' + str(month) + nsidc_tail
            # Read concentration data
            id = Dataset(nsidc_file, 'r')
            nsidc_data_raw = id.variables['seaice_conc_monthly_cdr'][0, :, :]
            # Read std just for the mask
            nsidc_mask = id.variables['stdev_of_seaice_conc_monthly_cdr'][
                0, :, :]
            id.close()
            # Set land mask
            nsidc_data_tmp = ma.empty(shape(nsidc_data_raw))
            nsidc_data_tmp[:, :] = 0.0
            nsidc_data_tmp[~nsidc_mask.mask] = nsidc_data_raw[~nsidc_mask.mask]
            nsidc_data_tmp[nsidc_mask.mask] = ma.masked
            # Accumulate master array, weighted with number of days per month
            nsidc_data[season, :, :] += nsidc_data_tmp * ndays_month[month - 1]
            season_days += ndays_month[month - 1]

        # Convert from sum to average
        nsidc_data[season, :, :] /= season_days

    # Convert to spherical coordinates
    nsidc_x = -(nsidc_lat + 90) * cos(nsidc_lon * deg2rad + pi / 2)
    nsidc_y = (nsidc_lat + 90) * sin(nsidc_lon * deg2rad + pi / 2)

    # Find boundaries for each side of plot based on extent of NSIDC grid
    bdry1 = amax(nsidc_x[:, 0])
    bdry2 = amin(nsidc_x[:, -1])
    bdry3 = amin(nsidc_y[:, 0])
    bdry4 = amax(nsidc_y[:, -1])

    # Set consistent colour levels
    lev = linspace(0, 1, num=50)

    # Plot
    fig = figure(figsize=(20, 9))
    # Loop over seasons
    for season in range(4):
        # NSIDC
        ax = fig.add_subplot(2, 4, season + 1, aspect='equal')
        contourf(nsidc_x, nsidc_y, nsidc_data[season, :, :], lev)
        if season == 0:
            text(-39, 0, 'NSIDC', fontsize=24, ha='right')
        title(season_names[season], fontsize=24)
        xlim([bdry1, bdry2])
        ylim([bdry3, bdry4])
        axis('off')
        # Build an array of FESOM data values corresponding to each Element
        values = []
        for elm in elements:
            # For each element not in an ice shelf cavity, append the mean
            # value for the 3 component Nodes
            if not elm.cavity:
                values.append(
                    mean([
                        fesom_data[season, elm.nodes[0].id],
                        fesom_data[season, elm.nodes[1].id],
                        fesom_data[season, elm.nodes[2].id]
                    ]))
        # Plot FESOM data
        ax = fig.add_subplot(2, 4, season + 5, aspect='equal')
        img = PatchCollection(patches, cmap=jet)
        img.set_array(array(values))
        img.set_clim(vmin=0, vmax=1)
        img.set_edgecolor('face')
        ax.add_collection(img)
        xlim([bdry1, bdry2])
        ylim([bdry3, bdry4])
        axis('off')
        if season == 0:
            text(-39, 0, 'FESOM', fontsize=24, ha='right')
    # Add a horizontal colorbar at the bottom
    cbaxes = fig.add_axes([0.25, 0.04, 0.5, 0.02])
    cbar = colorbar(img,
                    orientation='horizontal',
                    ticks=arange(0, 1 + 0.25, 0.25),
                    cax=cbaxes)
    cbar.ax.tick_params(labelsize=16)
    # Add the main title
    suptitle('Sea ice concentration', fontsize=30)
    # Decrease space between plots
    subplots_adjust(wspace=0.025, hspace=0.025)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
def mld_jja_diff(mesh_path,
                 file_path_beg,
                 file_path_end,
                 save=False,
                 fig_name=None,
                 limit=None):

    # Definition of mixed layer depth: where potential density exceeds
    # surface density by this amount (kg/m^3) as in Sallee et al 2013
    density_anom = 0.03
    # Plotting parameters
    circumpolar = True
    mask_cavities = True
    lat_max = -30 + 90
    font_sizes = [30, 24, 20]

    print 'Building grid'
    elements, patches = make_patches(mesh_path, circumpolar, mask_cavities)

    print 'Reading data'
    # First 10 years
    # Read temperature and salinity at each node, seasonally averaged over JJA
    tmp = seasonal_avg(file_path_beg, file_path_beg, 'temp')
    temp_beg = tmp[2, :]
    tmp = seasonal_avg(file_path_beg, file_path_beg, 'salt')
    salt_beg = tmp[2, :]
    # Last 10 years
    tmp = seasonal_avg(file_path_beg, file_path_end, 'temp')
    temp_end = tmp[2, :]
    tmp = seasonal_avg(file_path_beg, file_path_end, 'salt')
    salt_end = tmp[2, :]
    # Calculate potential density (depth 0)
    print 'Calculating density'
    density_beg = unesco(temp_beg, salt_beg, zeros(shape(temp_beg)))
    density_end = unesco(temp_end, salt_end, zeros(shape(temp_end)))

    # Calculate mixed layer depth at each element
    print 'Calculating mixed layer depth'
    # First 10 years
    mld_beg = []
    for elm in elements:
        if (mask_cavities and not elm.cavity) or (not mask_cavities):
            # Get mixed layer depth at each node
            mld_nodes = []
            # Make sure we exclude ice shelf cavity nodes from element mean
            # (an Element can be a non-cavity element and still have up to 2
            # cavity nodes)
            for i in range(3):
                if (mask_cavities
                        and not elm.cavity_nodes[i]) or (not mask_cavities):
                    node = elm.nodes[i]
                    density_sfc = density_beg[node.id]
                    temp_depth = node.depth
                    curr_node = node.below
                    while True:
                        if curr_node is None:
                            # Reached bottom
                            mld_nodes.append(temp_depth)
                            break
                        if density_beg[
                                curr_node.id] >= density_sfc + density_anom:
                            # Reached critical density anomaly
                            mld_nodes.append(curr_node.depth)
                            break
                        temp_depth = curr_node.depth
                        curr_node = curr_node.below
            # For this element, save the mean mixed layer depth across
            # non-cavity nodes (up to 3)
            mld_beg.append(mean(array(mld_nodes)))
    # Last 10 years
    mld_end = []
    for elm in elements:
        if (mask_cavities and not elm.cavity) or (not mask_cavities):
            # Get mixed layer depth at each node
            mld_nodes = []
            # Make sure we exclude ice shelf cavity nodes from element mean
            # (an Element can be a non-cavity element and still have up to 2
            # cavity nodes)
            for i in range(3):
                if (mask_cavities
                        and not elm.cavity_nodes[i]) or (not mask_cavities):
                    node = elm.nodes[i]
                    density_sfc = density_end[node.id]
                    temp_depth = node.depth
                    curr_node = node.below
                    while True:
                        if curr_node is None:
                            mld_nodes.append(temp_depth)
                            break
                        if density_end[
                                curr_node.id] >= density_sfc + density_anom:
                            mld_nodes.append(curr_node.depth)
                            break
                        temp_depth = curr_node.depth
                        curr_node = curr_node.below
            # For this element, save the mean mixed layer depth across
            # non-cavity nodes (up to 3)
            mld_end.append(mean(array(mld_nodes)))
    # Calculate change in mixed layer depth
    mld_change = array(mld_end) - array(mld_beg)

    if mask_cavities:
        # Get mask array of patches for ice shelf cavity elements
        mask_patches = iceshelf_mask(elements)

    # Choose colour bounds
    if limit is not None:
        bound = limit
    else:
        bound = amax(array(mld_change))

    print 'Plotting'
    # Set up plot
    fig = figure(figsize=(16, 12))
    ax = fig.add_subplot(1, 1, 1, aspect='equal')
    # Set colourmap for patches, and refer it to the values array
    img = PatchCollection(patches, cmap='RdBu_r')
    img.set_array(array(mld_change))
    img.set_edgecolor('face')
    # Add patches to plot
    ax.add_collection(img)
    if mask_cavities:
        # Set colour to light grey for patches in mask
        overlay = PatchCollection(mask_patches, facecolor=(0.6, 0.6, 0.6))
        overlay.set_edgecolor('face')
        # Add mask to plot
        ax.add_collection(overlay)

    # Configure plot
    xlim([-lat_max, lat_max])
    ylim([-lat_max, lat_max])
    ax.get_xaxis().set_ticks([])
    ax.get_yaxis().set_ticks([])
    axis('off')
    title('Change in JJA mixed layer depth (m)\n2091-2100 vs 2006-2015',
          fontsize=font_sizes[0])
    cbar = colorbar(img)
    cbar.ax.tick_params(labelsize=font_sizes[2])
    img.set_clim(vmin=-bound, vmax=bound)

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
def temp_salt_seasonal (elements, file_path1, file_path2, lon0, depth_min, save=False, fig_name=None):

    # Northern boundary for plot
    lat_max = -30
    # Season names for titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Bounds on colour scales for temperature and salinity
    var_min = [-2.5, 33.8]
    var_max = [3.5, 34.8]
    var_ticks = [1, 0.2]

    # Choose what to write on the title about longitude
    if lon0 < 0:
        lon_string = str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = str(int(round(lon0))) + r'$^{\circ}$E'

    # Get seasonal averages of temperature and salinity
    temp_data = seasonal_avg(file_path1, file_path2, 'temp')
    salt_data = seasonal_avg(file_path1, file_path2, 'salt')

    # Set colour levels
    lev1 = linspace(var_min[0], var_max[0], num=50)
    lev2 = linspace(var_min[1], var_max[1], num=50)

    # Plot
    fig = figure(figsize=(20,9))
    # Loop over seasons
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        # Interpolate temperature to lon0 and get plotting patches
        patches, values, lat_min = side_patches(elements, lat_max, lon0, temp_data[season,:])
        ax = fig.add_subplot(2, 4, season+1)
        img = PatchCollection(patches, cmap=jet)
        img.set_array(array(values))
        img.set_edgecolor('face')
        img.set_clim(vmin=var_min[0], vmax=var_max[0])
        ax.add_collection(img)
        xlim([lat_min, lat_max])
        ylim([depth_min, 0])
        title('Temperature (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            # Add depth label on the left
            ylabel('depth (m)', fontsize=18)
        if season == 3:
            # Add a colourbar on the right
            cbaxes = fig.add_axes([0.93, 0.6, 0.015, 0.3])
            cbar1 = colorbar(img, cax=cbaxes, ticks=arange(var_min[0], var_max[0]+var_ticks[0], var_ticks[0]))
            cbar1.ax.tick_params(labelsize=16)
        # Repeat for salinity
        patches, values, lat_min = side_patches(elements, lat_max, lon0, salt_data[season,:])
        ax = fig.add_subplot(2, 4, season+5)
        img = PatchCollection(patches, cmap=jet)
        img.set_array(array(values))
        img.set_edgecolor('face')
        img.set_clim(vmin=var_min[1], vmax=var_max[1])
        ax.add_collection(img)
        xlim([lat_min, lat_max])
        ylim([depth_min, 0])
        title('Salinity (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            ylabel('Depth (m)', fontsize=18)
        xlabel('Latitude', fontsize=18)
        if season == 3:
            cbaxes = fig.add_axes([0.93, 0.1, 0.015, 0.3])
            cbar2 = colorbar(img, cax=cbaxes, ticks=arange(var_min[1], var_max[1]+var_ticks[1], var_ticks[1]))
            cbar2.ax.tick_params(labelsize=16)
    suptitle(lon_string, fontsize=30)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()    
def ismr_seasonal (mesh_path, file_path1, file_path2, save=False, fig_name=None):

    # Plotting parameters
    lat_max = -63 + 90
    circumpolar = True
    mask_cavities = True
    # Seconds per year
    sec_per_year = 365.25*24*3600
    # Season names for plot titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Set colour map
    # Values for change points
    cmap_vals = array([-0.1, 0, 1, 2, 5, 8])
    # Colours for change points
    # (blue, white, yellow-orange, red-orange, dark red, purple)
    cmap_colors = [(0.26, 0.45, 0.86), (1, 1, 1), (1, 0.9, 0.4), (0.99, 0.59, 0.18), (0.5, 0.0, 0.08), (0.96, 0.17, 0.89)]
    # Map to 0-1
    cmap_vals_norm = (cmap_vals + 0.1)/(8 + 0.1)
    # Combine into a list
    cmap_list = []
    for i in range(size(cmap_vals)):
        cmap_list.append((cmap_vals_norm[i], cmap_colors[i]))
    # Make colour map    
    mf_cmap = LinearSegmentedColormap.from_list('melt_freeze', cmap_list)

    # Build FESOM mesh
    # Get separate patches for the open ocean elements so we can mask them out
    elements, mask_patches = make_patches(mesh_path, circumpolar, mask_cavities)
    patches = iceshelf_mask(elements)

    # Get seasonal averages of freshwater flux
    ismr = seasonal_avg(file_path1, file_path2, 'wnet')*sec_per_year
    # Select ice shelf nodes
    values = []

    # Set up a grey square covering the domain, anything that isn't covered
    # up later is land
    x_reg, y_reg = meshgrid(linspace(-lat_max, lat_max, num=100), linspace(-lat_max, lat_max, num=100))
    land_square = zeros(shape(x_reg))

    # Plot
    fig = figure(figsize=(20,6))
    # Loop over seasons
    for season in range(4):
        # Build an array of ismr values corresponding to each ice shelf Element
        values = []
        # Loop over elements
        for elm in elements:
            # For each element in an ice shelf cavity, append the mean value
            # for the 3 component Nodes
            if elm.cavity:
                values.append(mean([ismr[season,elm.nodes[0].id], ismr[season,elm.nodes[1].id], ismr[season,elm.nodes[2].id]]))
        ax = fig.add_subplot(1, 4, season+1, aspect='equal')
        # Start with grey square background for land
        contourf(x_reg, y_reg, land_square, 1, colors=(('0.6', '0.6', '0.6')))
        img = PatchCollection(patches, cmap='RdBu_r') #mf_cmap)
        img.set_array(array(values))
        img.set_edgecolor('face')
        img.set_clim(vmin=-3, vmax=3)
        #img.set_clim(vmin=-0.1, vmax=8)
        ax.add_collection(img)
        # Mask out the open ocean in white
        overlay = PatchCollection(mask_patches, facecolor=(1,1,1))
        overlay.set_edgecolor('face')
        ax.add_collection(overlay)
        # Contour ice shelf fronts
        contour_lines = []
        for elm in elements:
            # Select elements where exactly 2 of the 3 nodes are in a cavity
            if count_nonzero(elm.cavity_nodes) == 2:
                # Save the coastal flags and x- and y- coordinates of these 2
                coast_tmp = []
                x_tmp = []
                y_tmp = []
                for i in range(3):
                    if elm.cavity_nodes[i]:
                        coast_tmp.append(elm.coast_nodes[i])
                        x_tmp.append(elm.x[i])
                        y_tmp.append(elm.y[i])
                # Select elements where at most 1 of these 2 nodes are coastal
                if count_nonzero(coast_tmp) < 2:
                    # Draw a line between the 2 nodes
                    contour_lines.append([(x_tmp[0], y_tmp[0]), (x_tmp[1], y_tmp[1])])
        # Add all the lines to the plot
        contours = LineCollection(contour_lines, edgecolor='black', linewidth=1)
        ax.add_collection(contours)
        # Configure plot
        xlim([-lat_max, lat_max])
        ylim([-lat_max, lat_max])
        axis('off')
        title(season_names[season], fontsize=24)
        if season == 3:
            cbaxes = fig.add_axes([0.92, 0.2, 0.01, 0.6])
            cbar = colorbar(img, cax=cbaxes)
            cbar.ax.tick_params(labelsize=16)
    suptitle('Ice shelf melt rate (m/y)', fontsize=30)
    # Decrease space between plots
    subplots_adjust(wspace=0.025)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()