In two previous posts (here and here) I showed how to download and plot World Ocean Atlas Data. This post is an update where we will be using the latest oceans library and the lasted Atlas database (WOA13).
First let's define a mapping function using cartopy.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
from cartopy.mpl.gridliner import (LONGITUDE_FORMATTER,
LATITUDE_FORMATTER)
LAND = cfeature.NaturalEarthFeature('physical', 'land', '50m',
edgecolor='face',
facecolor=cfeature.COLORS['land'])
def make_map(bbox, projection=ccrs.PlateCarree()):
fig, ax = plt.subplots(figsize=(8, 6),
subplot_kw=dict(projection=projection))
ax.set_extent(bbox)
ax.add_feature(LAND, facecolor='0.75')
ax.coastlines(resolution='50m')
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = gl.ylabels_right = False
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
return fig, ax
Now we can import the new woa_subset
from oceans. This version returns
an iris cube instance instead of a Pandas Panel.
The call below requests annual temperature climatology at 0.25 degrees
resolution for the whole globe. The latest keyword argument requests the
whole dataset and not only the objectively analyzed temperature
(default is False
).
import matplotlib.pyplot as plt
from oceans.colormaps import cm
from oceans.ff_tools import wrap_lon180
from oceans.datasets import woa_subset
bbox = [2.5, 357.5, -87.5, 87.5]
kw = dict(bbox=bbox, variable='temperature', clim_type='00',
resolution='0.25', full=True)
cubes = woa_subset(**kw)
print(cubes)
The standard_name
is confusing. All the variables are
sea_water_temperature
. To understand the dataset we need to inspect the
long_name
or the attribute description.
[(k, c.var_name, c.long_name) for k, c in enumerate(cubes)]
We want the "Objectively analyzed mean fields for sea_water_temperature at
standard depth levels" or var_name==t_an
.
(Note that this is the only variable returned when calling with full=False
.)
Let's plot the surface data.
import matplotlib.pyplot as plt
import iris.plot as iplt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
from palettable import colorbrewer
def make_map(cube, projection=ccrs.PlateCarree(), figsize=(12, 10),
cmap=cm.avhrr):
fig, ax = plt.subplots(figsize=figsize,
subplot_kw=dict(projection=projection))
ax.add_feature(cfeature.LAND, facecolor='0.75')
cs = iplt.pcolormesh(cube, cmap=cmap)
ax.coastlines()
if isinstance(projection, ccrs.PlateCarree) or isinstance(projection, ccrs.Mercator):
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=1.5,
color='gray', alpha=0.5, linestyle='--')
gl.xlabels_top = gl.ylabels_right = False
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
cbar = dict(extend='both', shrink=0.5, pad=0.02,
orientation='horizontal', fraction=0.1)
cb = fig.colorbar(cs, **cbar)
cb.ax.set_xlabel(r"$^{\circ}$ C")
return fig, ax
Different from the previous woa_subset
version, this one returns all
depth levels and not the requested ones. The iris cube is "lazy", so
there is no reason to slice it earlier because no data is downloaded until you
actually need to.
cube = cubes[4]
c = cube[0, 0, ...] # Slice singleton time and first level.
fig, ax = make_map(c, projection=ccrs.Robinson())
I also added a woa_profile
version to quickly extract vertical
profiles at a given position. Here is how to use it:
from oceans import woa_profile
kw = dict(variable='temperature', clim_type='00', resolution='1.00', full=False)
polar = woa_profile(-25.5, -70.5, **kw)
tempe = woa_profile(-25.5, -45.0, **kw)
equat = woa_profile(-25.5, 0, **kw)
from matplotlib import style
import matplotlib.pyplot as plt
style.use('ggplot')
def plot_profile(cube, label):
z = cube.coord(axis='Z').points
l = ax.plot(cube[0, :].data, z, label=label, linewidth=2)
fig, ax = plt.subplots(figsize=(2.25, 6))
plot_profile(polar, label='Polar')
plot_profile(tempe, label='Temperate')
plot_profile(equat, label='Equatorial')
ax.legend(bbox_to_anchor=(1.5, .95))
ax.invert_yaxis()
_ = ax.set_ylim(4000, 0)
Happy May the fourth!
from IPython.display import YouTubeVideo
YouTubeVideo("ngElkyQ6Rhs")
HTML(html)