Explore Repeat Hydrography Data from CCHDO#

In this example notebook we will explore data collected on a repeat hydrographic section part of the GO-SHIP repeat hydrographic program.

Binder

All hydrographic data part of this progam are publicly avaiable and are archived at CCHDO. The section analyzed here (P18) is a meridonal transect in the eastern Pacific roughly along the 103\(^o\)W meridian. Section data is available at https://cchdo.ucsd.edu/cruise/33RO20161119. The netCDF file for the CTD data can be downloaded here.

import xarray as xr
import pandas as pd
import numpy as np
import datetime
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import gsw
%matplotlib inline

plt.rcParams["font.size"] = 16
plt.rcParams["figure.facecolor"] = 'white'
import warnings
warnings.filterwarnings('ignore')
# local path to data
datapath = './data/'

# Load netCDF file locally as xarray Dataset

ds = xr.load_dataset(datapath+'p18.nc')
ds
<xarray.Dataset> Size: 105MB
Dimensions:                     (N_PROF: 213, N_LEVELS: 5364)
Coordinates:
    expocode                    (N_PROF) object 2kB '33RO20161119' ... '33RO2...
    station                     (N_PROF) object 2kB '1' '2' '3' ... '211' '212'
    cast                        (N_PROF) int32 852B 3 2 1 1 1 1 ... 1 1 1 1 1 1
    sample                      (N_PROF, N_LEVELS) object 9MB '3.0' '4.0' ... ''
    time                        (N_PROF) datetime64[ns] 2kB 2016-11-24T14:17:...
    latitude                    (N_PROF) float64 2kB 22.69 22.87 ... -68.07
    longitude                   (N_PROF) float64 2kB -110.0 -110.0 ... -95.0
    pressure                    (N_PROF, N_LEVELS) float64 9MB 3.0 4.0 ... nan
Dimensions without coordinates: N_PROF, N_LEVELS
Data variables: (12/16)
    section_id                  (N_PROF) object 2kB 'P18' 'P18' ... 'P18' 'P18'
    btm_depth                   (N_PROF) float64 2kB 2.625e+03 ... 4.435e+03
    pressure_qc                 (N_PROF, N_LEVELS) float32 5MB 2.0 2.0 ... nan
    ctd_temperature             (N_PROF, N_LEVELS) float64 9MB 27.92 ... nan
    ctd_temperature_qc          (N_PROF, N_LEVELS) float32 5MB 3.0 3.0 ... nan
    ctd_salinity                (N_PROF, N_LEVELS) float64 9MB 34.53 ... nan
    ...                          ...
    ctd_beamcp                  (N_PROF, N_LEVELS) float64 9MB nan ... nan
    ctd_beamcp_qc               (N_PROF, N_LEVELS) float32 5MB nan 2.0 ... nan
    ctd_beta700_raw             (N_PROF, N_LEVELS) float64 9MB 0.076 ... nan
    ctd_number_of_observations  (N_PROF, N_LEVELS) float64 9MB 19.0 36.0 ... nan
    profile_type                (N_PROF) object 2kB 'C' 'C' 'C' ... 'C' 'C' 'C'
    geometry_container          float64 8B nan
Attributes:
    Conventions:               CF-1.8 CCHDO-1.0
    cchdo_software_version:    hydro 1.0.2.3
    cchdo_parameters_version:  params 0.1.21
    comments:                  CTD,20200213CCHSIOSEE\n Parameters removed fro...
    featureType:               profile
# list all variables in the dataset
all_vars = [i for i in ds.data_vars] 
all_vars
['section_id',
 'btm_depth',
 'pressure_qc',
 'ctd_temperature',
 'ctd_temperature_qc',
 'ctd_salinity',
 'ctd_salinity_qc',
 'ctd_oxygen',
 'ctd_oxygen_qc',
 'ctd_fluor_raw',
 'ctd_beamcp',
 'ctd_beamcp_qc',
 'ctd_beta700_raw',
 'ctd_number_of_observations',
 'profile_type',
 'geometry_container']
# Plot this hydrogrphic line on a MAP, and show station locations 

projection = ccrs.PlateCarree(central_longitude=180.0)

fig = plt.figure(figsize=(6,5),dpi=150)
ax1 = fig.add_subplot(121, projection=projection)
ax1.set_extent((90,310, -90, 90))
ax1.coastlines()
ax1.gridlines()
ax1.plot(ds.longitude,ds.latitude,transform = ccrs.PlateCarree())

gl1 = ax1.gridlines(
    draw_labels=True, linewidth=1, color='gray', alpha=0.4, linestyle='--',)
# Adjust fontsize for tick labels
gl1.xlabel_style = {'size': 10}
gl1.ylabel_style = {'size': 10}

# add subplot for station locations
ax2 = fig.add_subplot(122, projection=projection)
ax2.set_extent((-115,-90, -75, 30))
ax2.coastlines()
ax2.gridlines()
ax2.scatter(ds.longitude,ds.latitude,transform = ccrs.PlateCarree(),
            marker='.',s=1,
            color='r')

gl2 = ax2.gridlines(
    draw_labels=True, linewidth=1, color='gray', alpha=0.4, linestyle='--',)
# Adjust fontsize for tick labels
gl2.xlabel_style = {'size': 10}
gl2.ylabel_style = {'size': 10}

plt.show()
../../../_images/be0227f081f79e65f1e1b89c8581b245446160d84356e6d3fdeb04d8640e3332.png
# Plot bottom bathymetry 
ds['btm_depth'].plot(figsize=(10,3),
                     yincrease=False,
                     x='latitude',
                     color='gray',
                     linewidth=4,
                     xlim=(-70,23),
                     )
plt.ylabel('meters',fontsize=20)
plt.xlabel('Latitude',fontsize=20)
plt.show()
../../../_images/c973906bc51d84dfeaea807a05d2768b6f4a63e693758fb17d8168b2f69115c8.png
# Using xarray's plot wrapper, simple plot of Pressure Levels vs along-section Profile
ds.ctd_temperature.T.plot(figsize=(20,5),yincrease=False,cmap='RdBu_r',vmax=10,vmin=-2)
plt.show()
../../../_images/977fd93a53def47a63c245b454a55b368410d6bcc1df09b13ed59a23d5f0de8a.png
# Using xarray's plot wrapper, simple plot of Pressure Levels vs along-section Profile
ds.ctd_salinity.T.plot(figsize=(20,5),yincrease=False,cmap='YlGnBu_r',vmax=35.,vmin=34.)
plt.show()
../../../_images/6bc243c718b5e7bb30599de470c9fad1f25404d93045105d037cda938d58e24c.png

Get some variables of interest in the dataset#

exclude_vars = ['bottle_number']  # exclude these variables

# get a list of variables that we might be interested in-
# Filter remove one dimensional variables, QC flags and error variables

vars_of_interest = [i for i in all_vars if '_qc' not in i and '_error' not in i
                    and i not in exclude_vars 
                    and len(ds[i].dims)==2]
print(vars_of_interest)
['ctd_temperature', 'ctd_salinity', 'ctd_oxygen', 'ctd_fluor_raw', 'ctd_beamcp', 'ctd_beta700_raw', 'ctd_number_of_observations']

Next, we can calculate Absolute Salinity (SA) and Conservative Temperature (\(\Theta\)) and Potential Density (\(\sigma_0\))using the GSW Toolbox#

ds['SA'] = gsw.SA_from_SP(ds.ctd_salinity, ds.pressure, ds.longitude, ds.latitude)
ds['CT'] = gsw.CT_from_t(ds.SA,ds.ctd_temperature, ds.pressure)
ds['sigma_0'] = gsw.sigma0(ds.SA,ds.CT)
# Plot CTD Temperature and Conservative Temperature vs Pressure Level for the first profile (index 0)
ds.CT.T[:,0].plot(y='pressure',yincrease=False,label='CT')
ds.ctd_temperature.T[:,0].plot(y='pressure',yincrease=False,label='T')
plt.legend()
plt.show()
../../../_images/83bbaebfef7a4758233520970b0f4c8fe332c34c43f99fb253125b862cef4dac.png

Now we can plot a T-S diagram using this information for all profiles along the section.#

We will also contour potential density, which is useful to identify water masses and water-mass transformation

plt.figure(figsize=(4,3),dpi=200)

# Create a grid of SA and CT values using meshgrid
SA_vals = np.linspace(ds.SA.min().item(), ds.SA.max().item(), 100)
CT_vals = np.linspace(ds.CT.min().item(), ds.CT.max().item(), 100)
SA_grid, CT_grid = np.meshgrid(SA_vals, CT_vals)

# Calculate potential density at each point on the grid
p_density = gsw.sigma0(SA_grid, CT_grid)  # Assuming reference pressure of 0 dbar
# Scatter plot of Absolute Salinity vs. Conservative Temperature
plt.plot(ds.SA, ds.CT, 
         color='slateblue',
         marker='.',
         markersize=.1,
         alpha=0.2,
         linestyle='')

# Add potential density contours
density_levels = np.linspace(min(p_density.flatten()), max(p_density.flatten()), 10)  # Choose density levels
CS = plt.contour(SA_grid, CT_grid, p_density, 
                 levels=density_levels, 
                 colors='gray', 
                 linestyles='dashed')
plt.clabel(CS, inline=True, fontsize=6, fmt='%.1f')

# Label axes
plt.xlabel('Absolute Salinity [g/kg]')
plt.ylabel(r'$\Theta$ [$^\circ$C]')

# Set axis limit
plt.xlim(32,36.6)
plt.show()
../../../_images/3ff4ec42129ce6b0a6584d5df62f5e1e6437eb092ac72f4f031df8b5e771d52d.png