Manuscript maps¶

Created by Ivan Lima on Tue Nov 8 2022 22:13:11 -0500

In [1]:
%matplotlib inline
import pandas as pd
import xarray as xr
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import os, datetime, warnings, cmocean
from cartopy import crs as ccrs
from cartopy import feature as cfeature
print('Last updated on {}'.format(datetime.datetime.now().ctime()))
Last updated on Sun Feb 12 13:51:11 2023
In [2]:
sns.set_theme(context='paper', style='ticks', palette='tab10', rc={'figure.dpi':100, 'figure.figsize':[5, 5], 'axes.grid':True})
pd.options.display.max_columns = 50
warnings.filterwarnings('ignore')

Distribution of bottle data¶

In [3]:
# # read bottle data
# df_bottle = pd.read_csv('data/bottle_satellite_data_clean.csv', parse_dates=['Date'], index_col=0)
# df_bottle.loc[df_bottle.Date.dt.month.isin([1,2,12]),'Season'] = 'Winter' # set seasons
# df_bottle.loc[df_bottle.Date.dt.month.isin([3,4,5]),'Season'] = 'Spring'
# df_bottle.loc[df_bottle.Date.dt.month.isin([6,7,8]),'Season'] = 'Summer'
# df_bottle.loc[df_bottle.Date.dt.month.isin([9,10,11]),'Season'] = 'Fall'

# read bottle data
df_bottle = pd.read_csv('data/bottle_data_DIC_prepared.csv', parse_dates=['Date'], index_col=0, na_values=['<undefined>',-9999.])
df_bottle = df_bottle.loc[df_bottle.Oxygen_flag.isin([2, 6])]
df_bottle = df_bottle.loc[df_bottle.Oxygen.notnull()]

# read bottom topography data
etopo = xr.open_dataset('../Bottom_water_BGC/data/etopo5.nc', chunks='auto')
etopo['bath'] = etopo.bath.where(etopo.bath<0) # ocean points only
etopo = etopo.isel(X=slice(3100,4000), Y=slice(1300,1700)) # subset data to make things faster
In [4]:
minlon, maxlon = 282.5, 296
minlat, maxlat =  34.5, 45.25
lonc, latc = (minlon + maxlon)/2., (minlat + maxlat)/2.
isobaths = [-3000, -2000, -1000, -500, -250, -100, -50]

proj = ccrs.EquidistantConic(central_longitude=lonc, central_latitude=latc)
dpi = 600
fig, axs = plt.subplots(2, 2, subplot_kw={'projection':proj}, figsize=(11,11))
fig.subplots_adjust(hspace=0, wspace=0)

for ax, s, l in zip(axs.ravel(), ['winter','spring','summer','fall'], ['(a) ','(b) ','(c) ','(d) ']):
    ax.set_extent([minlon, maxlon, minlat, maxlat])
    _ = ax.add_feature(cfeature.LAND, zorder=1, facecolor='#b0b0b0')
    _ = ax.coastlines(linewidth=0.5, zorder=1)
    _ = ax.gridlines(xlocs=np.arange(-180,180,5),ylocs=np.arange(0,90,5), draw_labels=False)
    _ = ax.contour(etopo.X, etopo.Y, etopo.bath, isobaths, colors='k', linewidths=0.5, transform=ccrs.PlateCarree())
    df = df_bottle[df_bottle.Season==s]
    _ = ax.scatter(df.Longitude, df.Latitude, c='red', marker='x', transform=ccrs.PlateCarree(), alpha=0.75)
    _ = ax.text(0.025, 0.975, l + s.title(), ha='left', va='top', transform=ax.transAxes, fontsize=12)

for ax in axs[:,-1]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(0,90,5), draw_labels={'right': 'y'})

for ax in axs[-1,:]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(0,90,5), draw_labels={'bottom': 'x'})

fig.savefig('figures/bottle_data_distribution_seasonal.png', dpi=dpi, bbox_inches='tight')

Distribution of CTD data¶

In [5]:
df_ctd = pd.read_csv('data/CombinedCTD_metadata_bathy_600m_sorted.csv', parse_dates=['Date'], index_col=0)
df_ctd = df_ctd[df_ctd.Year>2012]
df_ctd = df_ctd[df_ctd.Longitude<-64.5]  # NELME region
df_ctd = df_ctd[df_ctd.Longitude>-76]    # exclude points in Chesapeake Bay 
df_ctd = df_ctd[df_ctd.Platform_Type!=2] # exclude glider data
df_ctd.loc[df_ctd.Date.dt.month.isin([1,2,12]),'Season'] = 'Winter' # set seasons
df_ctd.loc[df_ctd.Date.dt.month.isin([3,4,5]),'Season'] = 'Spring'
df_ctd.loc[df_ctd.Date.dt.month.isin([6,7,8]),'Season'] = 'Summer'
df_ctd.loc[df_ctd.Date.dt.month.isin([9,10,11]),'Season'] = 'Fall'

fig, axs = plt.subplots(2, 2, subplot_kw={'projection':proj}, figsize=(11,11))
fig.subplots_adjust(hspace=0, wspace=0)

for ax, s, l in zip(axs.ravel(), ['Winter','Spring','Summer','Fall'], ['(a) ','(b) ','(c) ','(d) ']):
    ax.set_extent([minlon, maxlon, minlat, maxlat])
    _ = ax.add_feature(cfeature.LAND, zorder=1, facecolor='#b0b0b0')
    _ = ax.coastlines(linewidth=0.5, zorder=1)
    _ = ax.gridlines(xlocs=np.arange(-180,180,5),ylocs=np.arange(0,90,5), draw_labels=False)
    _ = ax.contour(etopo.X, etopo.Y, etopo.bath, isobaths, colors='k', linewidths=0.5, transform=ccrs.PlateCarree())
    df = df_ctd[df_ctd.Season==s]
    _ = ax.scatter(df.Longitude, df.Latitude, c='red', s=15, marker='x', transform=ccrs.PlateCarree(), alpha=0.5)
    _ = ax.text(0.025, 0.975, l + s, ha='left', va='top', transform=ax.transAxes, fontsize=12)

for ax in axs[:,-1]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(0,90,5), draw_labels={'right': 'y'})

for ax in axs[-1,:]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(0,90,5), draw_labels={'bottom': 'x'})

fig.savefig('figures/ctd_data_distribution_seasonal.png', dpi=dpi, bbox_inches='tight')

Seasonal maps¶

Surface fields¶

In [6]:
ds_surface = xr.open_dataset('data/bgc_surface_seasonal.nc')

minlon, maxlon = 282.5-360, -65.
minlat, maxlat =  34.85, 45.1
lonc, latc = (minlon + maxlon)/2., (minlat + maxlat)/2.
proj = ccrs.EquidistantConic(central_longitude=lonc, central_latitude=latc)
cmap = plt.cm.YlGnBu_r

fig, axs = plt.subplots(6, 4, sharex=True, sharey=True, figsize=(6.5, 10.1), subplot_kw={'projection':proj})
fig.subplots_adjust(hspace=0, wspace=0)
for ax in axs.ravel():
    ax.set_extent([minlon, maxlon, minlat, maxlat])
    _ = ax.add_feature(cfeature.LAND, zorder=1, facecolor='#b0b0b0')
    _ = ax.coastlines(linewidth=0.5, zorder=1)
    _ = ax.gridlines(xlocs=np.arange(-180,180,5),ylocs=np.arange(0,90,5), draw_labels=False)
    _ = ax.contour(etopo.X, etopo.Y, etopo.bath, isobaths, colors='k', linewidths=0.5,
                   transform=ccrs.PlateCarree())

for s in range(4):
    tem = axs[0,s].pcolormesh(ds_surface.lon, ds_surface.lat, ds_surface.Temperature.isel(season=s),
                              vmin=1.75, vmax=28, cmap=cmocean.cm.thermal, transform=ccrs.PlateCarree())
    sal = axs[1,s].pcolormesh(ds_surface.lon, ds_surface.lat, ds_surface.Salinity.isel(season=s),
                              # vmin=29, vmax=36.2, cmap=cmocean.cm.haline, transform=ccrs.PlateCarree())
                              vmin=28.9, vmax=36.3, cmap=cmocean.cm.haline, transform=ccrs.PlateCarree())
    dic = axs[2,s].pcolormesh(ds_surface.lon, ds_surface.lat, ds_surface.DIC.isel(season=s),
                              # vmin=1815, vmax=2126, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=1815, vmax=2227.85, cmap=cmap, transform=ccrs.PlateCarree())
    ta  = axs[3,s].pcolormesh(ds_surface.lon, ds_surface.lat, ds_surface.TA.isel(season=s),
                              # vmin=2099, vmax=2381.2, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=2099, vmax=2392.93, cmap=cmap, transform=ccrs.PlateCarree())
    ph  = axs[4,s].pcolormesh(ds_surface.lon, ds_surface.lat, ds_surface.pH.isel(season=s),
                              # vmin=7.86, vmax=8.17, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=7.79, vmax=8.17, cmap=cmap, transform=ccrs.PlateCarree())
    oa  = axs[5,s].pcolormesh(ds_surface.lon, ds_surface.lat, ds_surface.saturation_aragonite.isel(season=s),
                              vmin=1, vmax=3.85, cmap=cmap, transform=ccrs.PlateCarree())
    # print(oa.get_clim())

# add colorbars
units = [r'$^o$C', 'g/kg', r'$\mu$mol/kg', r'$\mu$mol/kg', '', '']
for ax, pm, u in zip(axs[:,3], [tem, sal, dic, ta, ph, oa], units):
    l, b, w, h = ax.get_position().bounds
    cax = fig.add_axes([l+w+0.075, b+0.05*h, 0.02, h*0.9])
    cb = fig.colorbar(pm, cax=cax)
    cb.set_label(u)

for ax, title in zip(axs[0,:], ['Winter', 'Spring', 'Summer', 'Fall']):
    ax.text(0.5, 1.07, title, ha='center', va='center', transform=ax.transAxes)

for ax, label in zip(axs[:,0], ['Temperature', 'Salinity', 'DIC', 'TA', 'pH', r'$\Omega$ aragonite']):
    ax.text(-0.085, 0.5, label, ha='center', va='center', rotation=90, transform=ax.transAxes)

for ax in axs[:,3]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(40,90,5), draw_labels={'right': 'y'})
    
for ax in axs[5,:]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(40,90,5), draw_labels={'bottom': 'x'})
    
fig.savefig('figures/bgc_surface_seasonal.png', dpi=dpi, bbox_inches='tight')

Bottom fields¶

In [7]:
ds_bottom = xr.open_dataset('data/bgc_bottom_seasonal.nc')

fig, axs = plt.subplots(6, 4, sharex=True, sharey=True, figsize=(6.5, 10.1), subplot_kw={'projection':proj})
fig.subplots_adjust(hspace=0, wspace=0)
for ax in axs.ravel():
    ax.set_extent([minlon, maxlon, minlat, maxlat])
    _ = ax.add_feature(cfeature.LAND, zorder=1, facecolor='#b0b0b0')
    _ = ax.coastlines(linewidth=0.5, zorder=1)
    _ = ax.gridlines(xlocs=np.arange(-180,180,5),ylocs=np.arange(0,90,5), draw_labels=False)
    _ = ax.contour(etopo.X, etopo.Y, etopo.bath, isobaths, colors='k', linewidths=0.5,
                   transform=ccrs.PlateCarree())

for s in range(4):
    tem = axs[0,s].pcolormesh(ds_bottom.lon, ds_bottom.lat, ds_bottom.Temperature.isel(season=s),
                              # vmin=2.1, vmax=26, cmap=cmocean.cm.thermal, transform=ccrs.PlateCarree())
                              vmin=1.75, vmax=28, cmap=cmocean.cm.thermal, transform=ccrs.PlateCarree())
    sal = axs[1,s].pcolormesh(ds_bottom.lon, ds_bottom.lat, ds_bottom.Salinity.isel(season=s),
                              vmin=28.9, vmax=36.3, cmap=cmocean.cm.haline, transform=ccrs.PlateCarree())
    dic = axs[2,s].pcolormesh(ds_bottom.lon, ds_bottom.lat, ds_bottom.DIC.isel(season=s),
                              # vmin=1883.1, vmax=2227.85, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=1815, vmax=2227.85, cmap=cmap, transform=ccrs.PlateCarree())
    ta  = axs[3,s].pcolormesh(ds_bottom.lon, ds_bottom.lat, ds_bottom.TA.isel(season=s),
                              # vmin=2102, vmax=2392.93, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=2099, vmax=2392.93, cmap=cmap, transform=ccrs.PlateCarree())
    ph  = axs[4,s].pcolormesh(ds_bottom.lon, ds_bottom.lat, ds_bottom.pH.isel(season=s),
                              # vmin=7.79, vmax=8.14, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=7.79, vmax=8.17, cmap=cmap, transform=ccrs.PlateCarree())
    oa  = axs[5,s].pcolormesh(ds_bottom.lon, ds_bottom.lat, ds_bottom.saturation_aragonite.isel(season=s),
                              # vmin=1.15, vmax=3.6, cmap=cmap, transform=ccrs.PlateCarree())
                              vmin=1, vmax=3.85, cmap=cmap, transform=ccrs.PlateCarree())
    # print(oa.get_clim())

# add colorbars
units = [r'$^o$C', 'g/kg', r'$\mu$mol/kg', r'$\mu$mol/kg', '', '']
for ax, pm, u in zip(axs[:,3], [tem, sal, dic, ta, ph, oa], units):
    l, b, w, h = ax.get_position().bounds
    cax = fig.add_axes([l+w+0.075, b+0.05*h, 0.02, h*0.9])
    cb = fig.colorbar(pm, cax=cax)
    cb.set_label(u)

for ax, title in zip(axs[0,:], ['Winter', 'Spring', 'Summer', 'Fall']):
    ax.text(0.5, 1.07, title, ha='center', va='center', transform=ax.transAxes)

for ax, label in zip(axs[:,0], ['Temperature', 'Salinity', 'DIC', 'TA', 'pH', r'$\Omega$ aragonite']):
    ax.text(-0.085, 0.5, label, ha='center', va='center', rotation=90, transform=ax.transAxes)

for ax in axs[:,3]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(40,90,5), draw_labels={'right': 'y'})
    
for ax in axs[5,:]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(40,90,5), draw_labels={'bottom': 'x'})
    
fig.savefig('figures/bgc_bottom_seasonal.png', dpi=dpi, bbox_inches='tight')

Surface - Bottom¶

In [8]:
ds_diff = ds_surface - ds_bottom

from matplotlib import colors
from mpl_utils import center_cmap

fig, axs = plt.subplots(6, 4, sharex=True, sharey=True, figsize=(6.5, 10.1), subplot_kw={'projection':proj})
fig.subplots_adjust(hspace=-0.01, wspace=0)
for ax in axs.ravel():
    ax.set_extent([minlon, maxlon, minlat, maxlat])
    _ = ax.add_feature(cfeature.LAND, zorder=1, facecolor='#b0b0b0')
    _ = ax.coastlines(linewidth=0.5, zorder=1)
    _ = ax.gridlines(xlocs=np.arange(-180,180,5),ylocs=np.arange(0,90,5), draw_labels=False)
    _ = ax.contour(etopo.X, etopo.Y, etopo.bath, isobaths, colors='k', linewidths=0.5,
                   transform=ccrs.PlateCarree())

for s in range(4):
    tem = axs[0,s].pcolormesh(ds_diff.lon, ds_diff.lat, ds_diff.Temperature.isel(season=s),
                              vmin=-7, vmax=16, cmap=cmocean.cm.balance, transform=ccrs.PlateCarree())
    sal = axs[1,s].pcolormesh(ds_diff.lon, ds_diff.lat, ds_diff.Salinity.isel(season=s),
                              vmin=-3.8, vmax=1.23, cmap=cmocean.cm.balance, transform=ccrs.PlateCarree())
    dic = axs[2,s].pcolormesh(ds_diff.lon, ds_diff.lat, ds_diff.DIC.isel(season=s),
                              vmin=-299, vmax=11.15, cmap=cmocean.cm.balance, transform=ccrs.PlateCarree())
    ta  = axs[3,s].pcolormesh(ds_diff.lon, ds_diff.lat, ds_diff.TA.isel(season=s),
                              vmin=-185.9, vmax=22.76, cmap=cmocean.cm.balance, transform=ccrs.PlateCarree())
    ph  = axs[4,s].pcolormesh(ds_diff.lon, ds_diff.lat, ds_diff.pH.isel(season=s),
                              vmin=-0.12, vmax=0.22, cmap=cmocean.cm.balance, transform=ccrs.PlateCarree())
    oa  = axs[5,s].pcolormesh(ds_diff.lon, ds_diff.lat, ds_diff.saturation_aragonite.isel(season=s),
                              vmin=-0.96, vmax=1.96, cmap=cmocean.cm.balance, transform=ccrs.PlateCarree())
    # print(oa.get_clim())
    for pm in [tem, sal, dic, ta, ph, oa]:
        center_cmap(pm)

# add colorbars
units = [r'$^o$C', 'g/kg', r'$\mu$mol/kg', r'$\mu$mol/kg', '', '']
for ax, pm, u in zip(axs[:,3], [tem, sal, dic, ta, ph, oa], units):
    l, b, w, h = ax.get_position().bounds
    cax = fig.add_axes([l+w+0.075, b+0.05*h, 0.02, h*0.9])
    cb = fig.colorbar(pm, cax=cax)
    cb.set_label(u)

for ax, title in zip(axs[0,:], ['Winter', 'Spring', 'Summer', 'Fall']):
    ax.text(0.5, 1.07, title, ha='center', va='center', transform=ax.transAxes)

for ax, label in zip(axs[:,0], ['Temperature', 'Salinity', 'DIC', 'TA', 'pH', r'$\Omega$ aragonite']):
    ax.text(-0.085, 0.5, label, ha='center', va='center', rotation=90, transform=ax.transAxes)

for ax in axs[:,3]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(40,90,5), draw_labels={'right': 'y'})
    
for ax in axs[5,:]:
    _ = ax.gridlines(xlocs=np.arange(-180,180,5), ylocs=np.arange(40,90,5), draw_labels={'bottom': 'x'})
    
fig.savefig('figures/bgc_difference_seasonal.png', dpi=dpi, bbox_inches='tight')