Depth-time Hovmoller plotΒΆ
This recipe shows how to calculate a depth-time Hovmoller plot of 1-year anomaly of globally-averaged of conservative temperature and practical salinity from ACCESS-OM2 between Jan 1989 and Dec 2018.
[1]:
import numpy as np
import xarray as xr
import cf_xarray as cfxr
import intake
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.gridspec import GridSpec
from matplotlib import ticker
import cmocean.cm as cm
from dask.distributed import Client
[2]:
client = Client(threads_per_worker = 1)
client
[2]:
Client
Client-007bc949-8a1c-11ef-bf82-0000008cfe80
| Connection method: Cluster object | Cluster type: distributed.LocalCluster |
| Dashboard: /proxy/8787/status |
Cluster Info
LocalCluster
f8fa9aea
| Dashboard: /proxy/8787/status | Workers: 48 |
| Total threads: 48 | Total memory: 188.56 GiB |
| Status: running | Using processes: True |
Scheduler Info
Scheduler
Scheduler-01f85851-adcc-40b4-a1c7-0ddde083432b
| Comm: tcp://127.0.0.1:46165 | Workers: 48 |
| Dashboard: /proxy/8787/status | Total threads: 48 |
| Started: Just now | Total memory: 188.56 GiB |
Workers
Worker: 0
| Comm: tcp://127.0.0.1:34597 | Total threads: 1 |
| Dashboard: /proxy/41281/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:42705 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-aah3cxuv | |
Worker: 1
| Comm: tcp://127.0.0.1:42711 | Total threads: 1 |
| Dashboard: /proxy/45281/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:37063 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-xtvy0wq2 | |
Worker: 2
| Comm: tcp://127.0.0.1:38195 | Total threads: 1 |
| Dashboard: /proxy/44757/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:44595 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-i55om_hi | |
Worker: 3
| Comm: tcp://127.0.0.1:33047 | Total threads: 1 |
| Dashboard: /proxy/36495/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33947 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-gfb9zek8 | |
Worker: 4
| Comm: tcp://127.0.0.1:40579 | Total threads: 1 |
| Dashboard: /proxy/43293/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:35391 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-58xbdpno | |
Worker: 5
| Comm: tcp://127.0.0.1:37283 | Total threads: 1 |
| Dashboard: /proxy/43651/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:37199 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-q7v48mpm | |
Worker: 6
| Comm: tcp://127.0.0.1:44365 | Total threads: 1 |
| Dashboard: /proxy/44771/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:41615 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-e4pqlldt | |
Worker: 7
| Comm: tcp://127.0.0.1:37899 | Total threads: 1 |
| Dashboard: /proxy/34415/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:38381 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-gqvy3eck | |
Worker: 8
| Comm: tcp://127.0.0.1:33303 | Total threads: 1 |
| Dashboard: /proxy/42115/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:43119 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-9lr61fqu | |
Worker: 9
| Comm: tcp://127.0.0.1:43839 | Total threads: 1 |
| Dashboard: /proxy/37771/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:46599 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-6w_fd03o | |
Worker: 10
| Comm: tcp://127.0.0.1:41051 | Total threads: 1 |
| Dashboard: /proxy/35977/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33615 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-cajmbtz7 | |
Worker: 11
| Comm: tcp://127.0.0.1:41837 | Total threads: 1 |
| Dashboard: /proxy/46321/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:42325 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-4n8l05tg | |
Worker: 12
| Comm: tcp://127.0.0.1:36785 | Total threads: 1 |
| Dashboard: /proxy/36775/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:39811 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-01v8d4n5 | |
Worker: 13
| Comm: tcp://127.0.0.1:37391 | Total threads: 1 |
| Dashboard: /proxy/34955/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:38251 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-1gbj3vno | |
Worker: 14
| Comm: tcp://127.0.0.1:41367 | Total threads: 1 |
| Dashboard: /proxy/37349/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:36321 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-9rsmw0m0 | |
Worker: 15
| Comm: tcp://127.0.0.1:42419 | Total threads: 1 |
| Dashboard: /proxy/43657/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:34671 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-ja0i1sw9 | |
Worker: 16
| Comm: tcp://127.0.0.1:45351 | Total threads: 1 |
| Dashboard: /proxy/33509/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33977 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-seav5bro | |
Worker: 17
| Comm: tcp://127.0.0.1:46201 | Total threads: 1 |
| Dashboard: /proxy/43193/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33355 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-3lf6l6er | |
Worker: 18
| Comm: tcp://127.0.0.1:34967 | Total threads: 1 |
| Dashboard: /proxy/33013/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:43841 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-le58b2mw | |
Worker: 19
| Comm: tcp://127.0.0.1:44157 | Total threads: 1 |
| Dashboard: /proxy/37705/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:40039 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-ixpz66dp | |
Worker: 20
| Comm: tcp://127.0.0.1:46799 | Total threads: 1 |
| Dashboard: /proxy/43959/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:40313 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-7us28f4q | |
Worker: 21
| Comm: tcp://127.0.0.1:32953 | Total threads: 1 |
| Dashboard: /proxy/34787/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:39109 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-yas3qwde | |
Worker: 22
| Comm: tcp://127.0.0.1:45285 | Total threads: 1 |
| Dashboard: /proxy/40777/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:40067 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-9dxff4r6 | |
Worker: 23
| Comm: tcp://127.0.0.1:35255 | Total threads: 1 |
| Dashboard: /proxy/34215/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:35459 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-w03v_vx1 | |
Worker: 24
| Comm: tcp://127.0.0.1:46747 | Total threads: 1 |
| Dashboard: /proxy/35315/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33881 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-axat4v2t | |
Worker: 25
| Comm: tcp://127.0.0.1:46847 | Total threads: 1 |
| Dashboard: /proxy/39655/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:45191 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-4r4ihhmo | |
Worker: 26
| Comm: tcp://127.0.0.1:43393 | Total threads: 1 |
| Dashboard: /proxy/34417/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:46411 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-99hmttez | |
Worker: 27
| Comm: tcp://127.0.0.1:46439 | Total threads: 1 |
| Dashboard: /proxy/42179/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:38387 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-brkkb74w | |
Worker: 28
| Comm: tcp://127.0.0.1:33541 | Total threads: 1 |
| Dashboard: /proxy/43589/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:42669 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-wdbu4xyn | |
Worker: 29
| Comm: tcp://127.0.0.1:46583 | Total threads: 1 |
| Dashboard: /proxy/36057/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:42637 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-a8mewjvz | |
Worker: 30
| Comm: tcp://127.0.0.1:45933 | Total threads: 1 |
| Dashboard: /proxy/36027/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:36951 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-5dxq455m | |
Worker: 31
| Comm: tcp://127.0.0.1:32961 | Total threads: 1 |
| Dashboard: /proxy/40825/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:36935 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-kki4gpe1 | |
Worker: 32
| Comm: tcp://127.0.0.1:42801 | Total threads: 1 |
| Dashboard: /proxy/45229/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33097 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-3vsp41vd | |
Worker: 33
| Comm: tcp://127.0.0.1:34643 | Total threads: 1 |
| Dashboard: /proxy/37155/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:38049 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-xjv2trom | |
Worker: 34
| Comm: tcp://127.0.0.1:45771 | Total threads: 1 |
| Dashboard: /proxy/40975/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:46463 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-iufxt82g | |
Worker: 35
| Comm: tcp://127.0.0.1:36271 | Total threads: 1 |
| Dashboard: /proxy/39415/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:43069 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-z3_uzm5q | |
Worker: 36
| Comm: tcp://127.0.0.1:34419 | Total threads: 1 |
| Dashboard: /proxy/45065/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:37853 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-1uyu5dyy | |
Worker: 37
| Comm: tcp://127.0.0.1:44425 | Total threads: 1 |
| Dashboard: /proxy/41333/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:44841 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-i4ohtevs | |
Worker: 38
| Comm: tcp://127.0.0.1:41425 | Total threads: 1 |
| Dashboard: /proxy/36893/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33129 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-2eob5f3e | |
Worker: 39
| Comm: tcp://127.0.0.1:46873 | Total threads: 1 |
| Dashboard: /proxy/43143/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:40817 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-j2abtk0b | |
Worker: 40
| Comm: tcp://127.0.0.1:45839 | Total threads: 1 |
| Dashboard: /proxy/44701/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:33131 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-n96ujnfi | |
Worker: 41
| Comm: tcp://127.0.0.1:35831 | Total threads: 1 |
| Dashboard: /proxy/34585/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:34669 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-56lwf2tm | |
Worker: 42
| Comm: tcp://127.0.0.1:33219 | Total threads: 1 |
| Dashboard: /proxy/36381/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:43273 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-mcojbqxv | |
Worker: 43
| Comm: tcp://127.0.0.1:34819 | Total threads: 1 |
| Dashboard: /proxy/39943/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:36169 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-01i296fn | |
Worker: 44
| Comm: tcp://127.0.0.1:38619 | Total threads: 1 |
| Dashboard: /proxy/35247/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:34005 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-07agvyrt | |
Worker: 45
| Comm: tcp://127.0.0.1:45525 | Total threads: 1 |
| Dashboard: /proxy/44897/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:39787 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-y8mlm4wd | |
Worker: 46
| Comm: tcp://127.0.0.1:42563 | Total threads: 1 |
| Dashboard: /proxy/41565/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:40221 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-gb3_8e98 | |
Worker: 47
| Comm: tcp://127.0.0.1:33049 | Total threads: 1 |
| Dashboard: /proxy/38535/status | Memory: 3.93 GiB |
| Nanny: tcp://127.0.0.1:34187 | |
| Local directory: /jobfs/126791498.gadi-pbs/dask-scratch-space/worker-en0xvmhs | |
[3]:
catalog = intake.cat.access_nri
experiment = '1deg_jra55_iaf_omip2_cycle1' # 1-deg experiment
[4]:
def load_var(experiment, variable, frequency, start_time=None, end_time=None):
cat_subset = catalog.search(name = experiment)
var = cat_subset[experiment].search(
variable = variable, frequency = frequency, variable_cell_methods='time: mean'
).to_dask(xarray_open_kwargs = dict(use_cftime=True,chunks={}),
xarray_combine_by_coords_kwargs = dict(compat="override", data_vars="minimal", coords="minimal")
)[variable]
var = var.sel(time=slice(start_time, end_time))
return var
Loading the variables
[5]:
temperature = load_var(experiment, 'temp', '1mon')
salinity = load_var(experiment, 'salt', '1mon')
Compute anomalies relative to the first year (assuming monthly output here)
[6]:
temperature_anomaly = temperature - temperature.isel(time=slice(0, 12)).cf.mean('time')
salinity_anomaly = salinity - salinity.isel(time=slice(0, 12)).cf.mean('time')
Next, we load cell area (denoted as \(a(x,y,z)\)) to construct the total ocean area as a function of depth, \(A\), namely
We load dxt and dyt and compute a masked version of cell area; we also use a slight hack to divide temperature by itself and thereby get a 3-dimensional cell area mask that is needed to create \(A(z)\).
[7]:
cat_subset = catalog.search(name = experiment)
dxt = cat_subset[experiment].search(variable = 'dxt', frequency = 'fx', path=".*output000.*").to_dask()['dxt']
dyt = cat_subset[experiment].search(variable = 'dyt', frequency = 'fx', path=".*output000.*").to_dask()['dyt']
cell_area = dxt * dyt
## Make a mask to get vertical variation of area
temp1 = temperature.isel(time=0)
cell_mask = temp1 / temp1
total_area = (cell_area * cell_mask).cf.sum({'longitude', 'latitude'}).load()
Now, the mean temperature at each time level can then be computed as
where \(T\) is the globally average temperature and \(\tilde{\theta}\) is the anomaly of the conservative temperature.
[8]:
### Temperature hovmoller
temperature_hov = (cell_area * temperature_anomaly).cf.sum({'longitude', 'latitude'}) / total_area
temperature_hov = temperature_hov.compute()
### Salinity hovmoller
salinity_hov = (cell_area * salinity_anomaly).cf.sum({'longitude', 'latitude'}) / total_area
salinity_hov = salinity_hov.compute()
[9]:
def plot_hovmoller(fsize = 14, date_format = mdates.DateFormatter('%Y')):
# Set figures properties
plt.rcParams['font.size'] = fsize
plt.rcParams['xtick.labelsize'] = fsize-2
plt.rcParams['ytick.labelsize'] = fsize-2
fig = plt.figure(figsize = (10, 6))
grid = GridSpec(100, 100)
ax = [fig.add_subplot(grid[:30, :30]), fig.add_subplot(grid[:30, 33:63]),
fig.add_subplot(grid[32:, :30]), fig.add_subplot(grid[32:, 33:63])]
for i in range(len(ax)):
ax[i].xaxis.set_major_formatter(date_format)
ax[i].tick_params(axis='x', labelrotation=45)
if i != 0 and i != 2:
ax[i].set_yticklabels([])
return fig, ax
[11]:
fig, ax = plot_hovmoller(fsize = 14)
levels_temperature = np.arange(-0.3, 0.31, 0.01)
cf_temp = temperature_hov.cf.plot(ax = ax[0],
levels = levels_temperature,
x = 'time',
y = 'vertical',
add_colorbar = False,
label = None,
cmap = cm.balance)
temperature_hov.cf.plot(ax = ax[2],
levels = levels_temperature,
x = 'time',
y = 'vertical',
add_colorbar = False,
label = None,
cmap = cm.balance)
levels_salinity = np.arange(-0.03, 0.031, 0.001)
cf_salt = salinity_hov.cf.plot(ax = ax[1],
levels = levels_salinity,
x = 'time',
y = 'vertical',
add_colorbar = False,
label = None,
cmap = cm.curl)
salinity_hov.cf.plot(ax = ax[3],
levels = levels_salinity,
x = 'time',
y = 'vertical',
add_colorbar = False,
label = None,
cmap = cm.curl)
## Beautification details
for i in range(len(ax)):
if i < 2:
ax[i].set_ylim(500, 0)
ax[i].set_xticklabels([])
else:
ax[i].set_xlabel("")
ax[i].set_ylim(5000, 500)
ax[0].set_ylabel("Depth [m]")
ax[1].set_ylabel("")
ax[2].set_ylabel("Depth [m]")
ax[3].set_ylabel("")
# Colorbars
bar = plt.axes([0.11, 0.99, 0.25, 0.02])
cbar_1 = plt.colorbar(cf_temp, cax = bar, orientation = 'horizontal', extend='both', format= '%.2f')
cbar_1.set_label("Temperature [$\degree$C]")
bar = plt.axes([0.37, 0.99, 0.25, 0.02])
cbar_2 = plt.colorbar(cf_salt, cax = bar, orientation = 'horizontal', extend='both', format= '%.2f')
cbar_2.set_label("Salinity [psu]")
for cbar in [cbar_1, cbar_2]:
tick_locator = ticker.MaxNLocator(nbins=3) ## The ticker needs to called within the loop
cbar.locator = tick_locator
cbar.update_ticks()