WOA13 cross sections

In [1]:
import warnings
warnings.filterwarnings('ignore')
In [2]:
import iris
iris.FUTURE.netcdf_promote = True


def woa_subset(url, bbox=[-179.875, -89.875, 179.875, 89.875], level=None):
    cubes = iris.load_raw(url)
    # TODO: Getting only the OA field for now.
    for idx, cube in enumerate(cubes):
        if 'Objectively analyzed mean fields for' in cube.long_name:
            cube = cubes.pop(idx)
            break

    # Select data subset.
    lon = iris.Constraint(longitude=lambda lon: bbox[0] <= lon <= bbox[2])
    lat = iris.Constraint(latitude=lambda lat: bbox[1] <= lat <= bbox[3])
    if level:
        dep = iris.Constraint(depth=lambda z: z == level)
        cube = cube.extract(lon & lat & dep)
    else:
        cube = cube.extract(lon & lat)

    if cube.ndim >= 3 and cube.shape[0] == 1:  # Squeeze time dimension.
        cube = cube[0, ...]
    return cube
In [3]:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER


def make_map(projection=ccrs.PlateCarree(), resolution='110m'):
    fig, ax = plt.subplots(figsize=(11, 7),
                           subplot_kw=dict(projection=projection))
    ax.set_global()
    ax.coastlines(resolution=resolution, color='k')
    gl = ax.gridlines(draw_labels=True)
    gl.xlabels_top = gl.ylabels_right = False
    gl.xformatter = LONGITUDE_FORMATTER
    gl.yformatter = LATITUDE_FORMATTER
    ax.add_feature(cfeature.LAND, facecolor='0.75')
    return fig, ax
In [4]:
ocean = dict(
    Indian=dict(
        bbox=[45., -32., 105., -32.]
    )
)

level = None
ocean = ocean['Indian']

base = 'https://data.nodc.noaa.gov/thredds/dodsC/woa/WOA13/DATA/'
var = dict(
    temp='temperature/netcdf/decav/0.25/woa13_decav_t00_04.nc',
    sal='salinity/netcdf/decav/0.25/woa13_decav_s00_04.nc',
    nit='nitrate/netcdf/all/1.00/woa13_all_n00_01.nc',
    aou='AOU/netcdf/all/1.00/woa13_all_A00_01.nc',
    oxy='oxygen/netcdf/all/1.00/woa13_all_o00_01.nc',
    sil='silicate/netcdf/all/1.00/woa13_all_i00_01.nc',
    phos='phosphate/netcdf/all/1.00/woa13_all_p00_01.nc'
)
In [5]:
%matplotlib inline

import numpy as np

from ctd import plot_section
from oceans.colormaps import cm
from matplotlib.ticker import FuncFormatter
from iris.pandas import as_data_frame


for key, value in var.items():
    print(key)
    url = base + value
    fname = value.split('/')[-1]
    cube = woa_subset(url, bbox=ocean['bbox'], level=level)
    if cube.ndim > 2:
        cube = cube.collapsed(['latitude'], iris.analysis.MEAN)

    if key == 'temp':
        title = 'Temperature'
        units = r'$^\circ$C'
        cmap = cm.avhrr
    elif key == 'sal':
        title = 'Salinity'
        units = r'g kg$^{-1}$'
        cmap = cm.odv
    elif key == 'nit':
        title = 'Nitrogen'
        units = r'$\mu$mol L$^{-1}$'
        cmap = cm.odv
    elif key == 'aou' or key == 'oxy':
        title = 'AOU'
        units = r'mL L$^{-1}$'
        cmap = cm.odv
    elif key == 'sil':
        title = 'Silicate'
        units = r'$\mu$mol L$^{-1}$'
        cmap = cm.odv
    elif key == 'phos':
        title = 'Phosphate'
        units = r'$\mu$mol L$^{-1}$'
        cmap = cm.odv

    lon = cube.coord(axis='X').points
    lat = cube.coord(axis='Y').points

    df = as_data_frame(cube)
    if key == 'sal':
        df = df.clip(33, 37)  # 27.5, 37.5
    levels = np.arange(df.min().min(), df.max().max(), 0.02)
    df.lon = lon
    df.lat = np.repeat(lat, len(lon))

    fig, ax, cbar = plot_section(df, cmap=cm.odv, marker=None,
                                 levels=levels)
    cbar.ax.set_title(units)
    ax.set_xlabel('')
    ax.set_ylabel('')

    # Add km to x-axis.
    def km(x, pos):
        if x.is_integer():
            x = int(x)
        return '{} km'.format(x)
    km_formatter = FuncFormatter(km)
    ax.xaxis.set_major_formatter(km_formatter)

    # Add m to y-axis.
    def m(x, pos):
        if x.is_integer():
            x = int(x)
        return '{} m'.format(x)
    m_formatter = FuncFormatter(m)
    ax.yaxis.set_major_formatter(m_formatter)

    # New x-axis.
    def deg(labels):
        new_labels = []
        for x in labels:
            if x < 0:
                text = r'%.2f$^\circ$ W' % abs(x)
            elif x > 0:
                text = r'%.2f$^\circ$ E' % x
            else:
                text = r'%.2f$^\circ$' % x
            new_labels.append(text)
        return new_labels

    ax2 = ax.twiny()
    xmin, xmax = ax.get_xlim()[0], ax.get_xlim()[-1]
    loc = np.array([xmin, xmax*0.25, xmax*0.5, xmax*0.75, xmax])
    labels = [np.percentile(lon, 0), np.percentile(lon, 25),
              np.percentile(lon, 50), np.percentile(lon, 75),
              np.percentile(lon, 100)]
    ax2.set_xticks(loc)
    ax2.set_xticklabels(deg(labels))

    # Global inset map.
    projection = ccrs.Orthographic(central_longitude=lon.mean(),
                                   central_latitude=lat.mean())
    axin = plt.axes([0.625, 0.1, 0.25, 0.25], projection=projection)
    axin.set_global()
    axin.add_feature(cfeature.LAND)
    axin.coastlines()
    axin.plot(df.lon, df.lat, 'r', transform=ccrs.Geodetic())
    temp
    sal
    nit
    aou
    oxy
    sil
    phos

png

png

png

png

png

png

png