GLODAP: Global Ocean Data Analysis Project

Jupyter Book and GitHub repo.

GLODAP: Global Ocean Data Analysis Project#

This notebook is a viewer for global ocean chemistry. It depends upon downloading local copies of five data files. The data are organized as depth-sorted layers of the global ocean (where the depths are predetermined). The data files are not part of this Jupyter Book due to size limits.

The GLODAP global ocean dataset compiles several decades of observation. It is a ‘geological instant’ snapshot of the state of the entire ocean.

Moving the sliders for each chart selects for depth, as shown at the bottom left.

  • GLODAP data used here is the 2016 version; 2021 v2 available

  • Color map cmocean

  • Make a subset intrinsic, show by default e.g. Atlantic / Caribbean / Amazon

This sequence of download commands gets five global ocean state datasets.

!mkdir glodap
!wget -q https://kilroybackup.s3.us-west-2.amazonaws.com/glodap/NO3.nc         -O glodap/NO3.nc
!wget -q https://kilroybackup.s3.us-west-2.amazonaws.com/glodap/TCO2.nc        -O glodap/TCO2.nc
!wget -q https://kilroybackup.s3.us-west-2.amazonaws.com/glodap/oxygen.nc      -O glodap/oxygen.nc
!wget -q https://kilroybackup.s3.us-west-2.amazonaws.com/glodap/salinity.nc    -O glodap/salinity.nc
!wget -q https://kilroybackup.s3.us-west-2.amazonaws.com/glodap/temperature.nc -O glodap/temperature.nc

Artifact: configuration#

import os, sys, time, glob, warnings, cmocean
from IPython.display import clear_output
warnings.filterwarnings('ignore')
this_dir = os.getcwd()  

from matplotlib import animation, rc
from numpy import datetime64 as dt64, timedelta64 as td64
from matplotlib import pyplot as plt, colors as mplcolors
import numpy as np, pandas as pd, xarray as xr
from ipywidgets import *
from traitlets import dlink
glodapdir = '../../../data/oceanography/glodap/'         # this is a location outside of the repository

temperatureFnm = glodapdir + 'temperature.nc'
salinityFnm    = glodapdir + 'salinity.nc'
oxygenFnm      = glodapdir + 'oxygen.nc'
NO3Fnm         = glodapdir + 'NO3.nc'
TCO2Fnm        = glodapdir + 'TCO2.nc'

glodap = {}
glodap['S'] = xr.open_dataset(salinityFnm)
glodap['T'] = xr.open_dataset(temperatureFnm)
glodap['O'] = xr.open_dataset(oxygenFnm)
glodap['N'] = xr.open_dataset(NO3Fnm)
glodap['R'] = xr.open_dataset(TCO2Fnm)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/file_manager.py:211, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
    210 try:
--> 211     file = self._cache[self._key]
    212 except KeyError:

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/lru_cache.py:56, in LRUCache.__getitem__(self, key)
     55 with self._lock:
---> 56     value = self._cache[key]
     57     self._cache.move_to_end(key)

KeyError: [<class 'netCDF4._netCDF4.Dataset'>, ('/home/runner/work/oceanography/data/oceanography/glodap/salinity.nc',), 'r', (('clobber', True), ('diskless', False), ('format', 'NETCDF4'), ('persist', False)), '5382f5bd-415f-4b42-bd38-96fde57fed2f']

During handling of the above exception, another exception occurred:

FileNotFoundError                         Traceback (most recent call last)
Cell In[2], line 10
      7 TCO2Fnm        = glodapdir + 'TCO2.nc'
      9 glodap = {}
---> 10 glodap['S'] = xr.open_dataset(salinityFnm)
     11 glodap['T'] = xr.open_dataset(temperatureFnm)
     12 glodap['O'] = xr.open_dataset(oxygenFnm)

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/api.py:686, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
    674 decoders = _resolve_decoders_kwargs(
    675     decode_cf,
    676     open_backend_dataset_parameters=backend.open_dataset_parameters,
   (...)
    682     decode_coords=decode_coords,
    683 )
    685 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 686 backend_ds = backend.open_dataset(
    687     filename_or_obj,
    688     drop_variables=drop_variables,
    689     **decoders,
    690     **kwargs,
    691 )
    692 ds = _dataset_from_backend_dataset(
    693     backend_ds,
    694     filename_or_obj,
   (...)
    704     **kwargs,
    705 )
    706 return ds

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/netCDF4_.py:666, in NetCDF4BackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, mode, format, clobber, diskless, persist, auto_complex, lock, autoclose)
    644 def open_dataset(
    645     self,
    646     filename_or_obj: str | os.PathLike[Any] | ReadBuffer | AbstractDataStore,
   (...)
    663     autoclose=False,
    664 ) -> Dataset:
    665     filename_or_obj = _normalize_path(filename_or_obj)
--> 666     store = NetCDF4DataStore.open(
    667         filename_or_obj,
    668         mode=mode,
    669         format=format,
    670         group=group,
    671         clobber=clobber,
    672         diskless=diskless,
    673         persist=persist,
    674         auto_complex=auto_complex,
    675         lock=lock,
    676         autoclose=autoclose,
    677     )
    679     store_entrypoint = StoreBackendEntrypoint()
    680     with close_on_error(store):

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/netCDF4_.py:452, in NetCDF4DataStore.open(cls, filename, mode, format, group, clobber, diskless, persist, auto_complex, lock, lock_maker, autoclose)
    448     kwargs["auto_complex"] = auto_complex
    449 manager = CachingFileManager(
    450     netCDF4.Dataset, filename, mode=mode, kwargs=kwargs
    451 )
--> 452 return cls(manager, group=group, mode=mode, lock=lock, autoclose=autoclose)

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/netCDF4_.py:393, in NetCDF4DataStore.__init__(self, manager, group, mode, lock, autoclose)
    391 self._group = group
    392 self._mode = mode
--> 393 self.format = self.ds.data_model
    394 self._filename = self.ds.filepath()
    395 self.is_remote = is_remote_uri(self._filename)

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/netCDF4_.py:461, in NetCDF4DataStore.ds(self)
    459 @property
    460 def ds(self):
--> 461     return self._acquire()

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/netCDF4_.py:455, in NetCDF4DataStore._acquire(self, needs_lock)
    454 def _acquire(self, needs_lock=True):
--> 455     with self._manager.acquire_context(needs_lock) as root:
    456         ds = _nc4_require_group(root, self._group, self._mode)
    457     return ds

File ~/micromamba/envs/geosmart-template/lib/python3.12/contextlib.py:137, in _GeneratorContextManager.__enter__(self)
    135 del self.args, self.kwds, self.func
    136 try:
--> 137     return next(self.gen)
    138 except StopIteration:
    139     raise RuntimeError("generator didn't yield") from None

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/file_manager.py:199, in CachingFileManager.acquire_context(self, needs_lock)
    196 @contextlib.contextmanager
    197 def acquire_context(self, needs_lock=True):
    198     """Context manager for acquiring a file."""
--> 199     file, cached = self._acquire_with_cache_info(needs_lock)
    200     try:
    201         yield file

File ~/micromamba/envs/geosmart-template/lib/python3.12/site-packages/xarray/backends/file_manager.py:217, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
    215     kwargs = kwargs.copy()
    216     kwargs["mode"] = self._mode
--> 217 file = self._opener(*self._args, **kwargs)
    218 if self._mode == "w":
    219     # ensure file doesn't get overridden when opened again
    220     self._mode = "a"

File src/netCDF4/_netCDF4.pyx:2521, in netCDF4._netCDF4.Dataset.__init__()

File src/netCDF4/_netCDF4.pyx:2158, in netCDF4._netCDF4._ensure_nc_success()

FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/oceanography/data/oceanography/glodap/salinity.nc'
for ds in glodap: print(ds)

# should print S T O N R respectively Salinity, Temperature, Oxygen, Nitrate, CO2
S
T
O
N
R
def oxygen(depth_index):
    glodap['O']['oxygen'].sel(depth_surface = depth_index).plot(figsize=(11, 7),cmap='viridis',vmin=150, vmax=350)         # original: cmocean.cm.oxy
    plt.ylabel(None); plt.xlabel(None)
    if depth_index == 0: msg = 'This is for surface water'
    else:                msg = 'This is for water at ' + str(int(glodap['O']['Depth'].values[depth_index])) + ' meters depth'
    plt.text(25, -87, msg); plt.text(28, 50, 'oxygen dissolved in'); plt.text(28, 42, '     ocean water   ')

interact(oxygen, depth_index=widgets.IntSlider(min=0, max=32, step=1, value=0, continuous_update=False, description='O depth'))
<function __main__.oxygen(depth_index)>
plt.rcParams.update({'font.size': 16})

# return to cmocean.cm.oxy, haline, thermal, algae, delta

def oxygen(depth_index):
    glodap['O']['oxygen'].sel(depth_surface = depth_index).plot(figsize=(11, 7),cmap='viridis', vmin=150, vmax=350)
    plt.ylabel(None); plt.xlabel(None)
    if depth_index == 0: msg = 'This is for surface water'
    else:                msg = 'This is for water at ' + str(int(glodap['O']['Depth'].values[depth_index])) + ' meters depth'
    plt.text(25, -87, msg); plt.text(28, 50, 'oxygen dissolved in'); plt.text(28, 42, '     ocean water   ')

def salinity(depth_index):
    glodap['S']['salinity'].sel(depth_surface = depth_index).plot(figsize=(11, 7),cmap='plasma',vmin=33, vmax=36)
    plt.ylabel(None); plt.xlabel(None)
    if depth_index == 0: msg = 'This is for surface water'
    else:                msg = 'This is for water at ' + str(int(glodap['S']['Depth'].values[depth_index])) + ' meters depth'
    plt.text(25, -87, msg); plt.text(47, 50, 'salinity of'); plt.text(47, 42, 'ocean water')

def temperature(depth_index):
    glodap['T']['temperature'].sel(depth_surface = depth_index).plot(figsize=(11, 7),cmap='inferno',vmin=2., vmax=12.)
    plt.ylabel(None); plt.xlabel(None)
    if depth_index == 0: msg = 'This is for surface water'
    else:                msg = 'This is for water at ' + str(int(glodap['T']['Depth'].values[depth_index])) + ' meters depth'
    plt.text(25, -87, msg); plt.text(47, 50, 'temperature of'); plt.text(47, 42, 'ocean water')
    
def nitrate(depth_index):
    glodap['N']['NO3'].sel(depth_surface = depth_index).plot(figsize=(11, 7),cmap='magma', vmin=2., vmax=40.)
    plt.ylabel(None); plt.xlabel(None)
    if depth_index == 0: msg = 'This is for surface water'
    else:                msg = 'This is for water at ' + str(int(glodap['N']['Depth'].values[depth_index])) + ' meters depth'
    plt.text(25, -87, msg); plt.text(47, 50, 'nitrate in'); plt.text(47, 42, 'ocean water')

def carbonate(depth_index):
    glodap['R']['TCO2'].sel(depth_surface = depth_index).plot(figsize=(11, 7), cmap='cividis', vmin=2000., vmax=2500.)
    plt.ylabel(None); plt.xlabel(None)
    if depth_index == 0: msg = 'This is for surface water'
    else:                msg = 'This is for water at ' + str(int(glodap['R']['Depth'].values[depth_index])) + ' meters depth'
    plt.text(25, -87, msg); plt.text(47, 50, 'carbon dioxide in'); plt.text(47, 42, 'ocean water')

interact(oxygen,      depth_index=widgets.IntSlider(min=0, max=32, step=1, value=0, continuous_update=False, description='O depth'))
interact(salinity,    depth_index=widgets.IntSlider(min=0, max=32, step=1, value=0, continuous_update=False, description='S depth'))
interact(temperature, depth_index=widgets.IntSlider(min=0, max=32, step=1, value=0, continuous_update=False, description='T depth'))
interact(nitrate,     depth_index=widgets.IntSlider(min=0, max=32, step=1, value=0, continuous_update=False, description='NO3 depth'))
interact(carbonate,   depth_index=widgets.IntSlider(min=0, max=32, step=1, value=0, continuous_update=False, description='CO2 depth'))
<function __main__.carbonate(depth_index)>

Set the slider above to 28#

Compare with the mid-ocean ridges shown here.


drawing