Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

CMMTE Comparisons

Authors
Affiliations
University of California Berkeley
British Antarctic Survey
import numpy as np
import pandas as pd
import xarray as xr
from matplotlib import pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns

from artools.loading_utils import *
from artools.attribute_utils import *
from artools.format_utils import *
from artools.display_utils import *

First, let’s load up a csv table of with count and duration information for CMMTEs across the various regions of Antarctica, for each month of each year from 1992-2012. This table was extracted from the CMMT Excel spreadsheets, provided by Jonathan Chambers and Matthew Lazzara.

# loading up the CMMTE data
cmmtes = pd.read_csv('../../input_data/cmmte/cmmte_regional_counts_durations.csv')
cmmtes['count'] = cmmtes.iloc[:,-12:].sum(1)
/tmp/ipykernel_2596/2149630709.py:3: Pandas4Warning: Starting with pandas version 4.0 all arguments of sum will be keyword-only.
  cmmtes['count'] = cmmtes.iloc[:,-12:].sum(1)
# loading up the catalogs and doing some light preprocessing
ais_da = load_ais()

full_cat = load_catalog('epsspace0.5_epstime12_minpts5_nreppts10_seed12345.h5')
landfalling_storms = full_cat[full_cat.is_landfalling]

landfalling_storms['start_date'] = landfalling_storms['data_array'].apply(add_start_date, ais_da=ais_da)
landfalling_storms['end_date'] = landfalling_storms['data_array'].apply(add_end_date, ais_da=ais_da)
landfalling_storms['landfall_duration'] = landfalling_storms['data_array'].apply(compute_duration, ais_da=ais_da)
landfalling_storms['full_duration'] = landfalling_storms['data_array'].apply(compute_duration)

Aggregate Statistics

First, let’s compare aggregate statistics across our catalog and the archive of CMMTEs.

yearly_cmmtes = cmmtes.groupby('Year')['count'].sum()
yearly_cmmtes = yearly_cmmtes.loc[1993:2012]
yearly_ars = landfalling_storms.groupby(landfalling_storms['start_date'].dt.year).size()
yearly_ars = yearly_ars.loc[1993:2012]
plt.figure(figsize=(6, 4))

sns.lineplot(x=yearly_ars.index.astype(int), 
             y=yearly_ars.values, 
             marker='o', 
             label='Landfalling ARs')

sns.lineplot(x=yearly_cmmtes.index.astype(int), 
             y=yearly_cmmtes.values, 
             marker='o', 
             label='CMMTEs')

# Axis Labeling
plt.xlabel('Year')
plt.ylabel('Count')

plt.gca().xaxis.set_major_locator(ticker.MaxNLocator(integer=True))


plt.legend()
plt.savefig('../../output/count_comparisons.png', dpi=300)
<Figure size 600x400 with 1 Axes>
yearly_cmmtes.corr(yearly_ars)
np.float64(0.2978032646838606)
cmmte_differenced = yearly_cmmtes.diff(periods=1)
ars_differenced = yearly_ars.diff(periods=1)
ars_differenced.corr(cmmte_differenced)
np.float64(0.24846147152027)
fig, ax = plt.subplots(ncols=2, figsize=(10,3))

ax[0].set_title('Raw')
ax[0].set_ylabel('CMMTE')
ax[0].set_xlabel('Our Catalog')
sns.scatterplot(x=yearly_ars, y=yearly_cmmtes, ax=ax[0])
ax[1].set_title('First-Order Differenced')
ax[1].set_ylabel('CMMTE')
ax[1].set_xlabel('Our Catalog')
sns.scatterplot(x=ars_differenced, y=cmmte_differenced, ax=ax[1]);
<Figure size 1000x300 with 2 Axes>

Some similar structure, but correlations are not exactly as we may hope for. I’m imagining this has something to do with how a CMMTE is defined: there is a time condition where the event must be making landfall for a certain amount of time (from the website: ‘An event in which a cloud mass travels from an oceanic region perpendicularly onto the continent, lasting at least 48 consecutive hours.’). I’m not sure yet if this means 48 consecutive hours of landfall, or that the storm was tracked for 48 consecutive hours and the landfalling duration was less time. I’m going to assume the latter for now.

landfalling_storms_longer = landfalling_storms[landfalling_storms.full_duration >= 48]
yearly_cmmtes = cmmtes.groupby('Year')['count'].sum()
yearly_cmmtes = yearly_cmmtes.loc[1993:2012] 
yearly_ars_longer = landfalling_storms_longer.groupby(landfalling_storms_longer['start_date'].dt.year).size()
yearly_ars_longer = yearly_ars_longer.loc[1993:2012]
plt.figure(figsize=(6, 4))

sns.lineplot(x=yearly_ars_longer.index.astype(int), 
             y=yearly_ars_longer.values, 
             marker='o', 
             label='Landfalling ARs')
sns.lineplot(x=yearly_cmmtes.index.astype(int), 
             y=yearly_cmmtes.values, 
             marker='o', 
             label='CMMTEs')
# Axis Labeling
plt.xlabel('Year')
plt.ylabel('Count')

plt.gca().xaxis.set_major_locator(ticker.MaxNLocator(integer=True))
plt.legend();
<Figure size 600x400 with 1 Axes>
yearly_cmmtes.corr(yearly_ars_longer)
np.float64(0.6296624748757214)
cmmte_differenced = yearly_cmmtes.diff(periods=1)
ars_differenced_longer = yearly_ars_longer.diff(periods=1)
ars_differenced_longer.corr(cmmte_differenced)
np.float64(0.4686151222662772)
fig, ax = plt.subplots(ncols=2, figsize=(10,3))

ax[0].set_title('Raw')
ax[0].set_ylabel('CMMTE')
ax[0].set_xlabel('Our Catalog')
sns.scatterplot(x=yearly_ars_longer, y=yearly_cmmtes, ax=ax[0])
ax[1].set_title('First-Order Differenced')
ax[1].set_ylabel('CMMTE')
ax[1].set_xlabel('Our Catalog')
sns.scatterplot(x=ars_differenced_longer, y=cmmte_differenced, ax=ax[1]);
<Figure size 1000x300 with 2 Axes>

Correlation in actual counts and differences from year to year are much higher if we subset based on the length of the storms. We do have much less storms overall when subsetting in this way, however.

fig, ax = plt.subplots(ncols=1, figsize=(8,5))
sns.lineplot(x=yearly_ars.index.astype(int), 
             y=yearly_ars.values, 
             marker='o', 
             label='All ARs',
             ax=ax)
sns.lineplot(x=yearly_ars_longer.index.astype(int), 
             y=yearly_ars_longer.values, 
             marker='o', 
             label='ARs >= 48hr',
             ax=ax)
sns.lineplot(x=yearly_cmmtes.index.astype(int), 
             y=yearly_cmmtes.values, 
             marker='D', 
             label='CMMTEs',
             ax=ax)

ax.xaxis.set_major_locator(ticker.MaxNLocator(integer=True))
ax.grid()
ax.set_ylabel('Count', fontsize=12)
ax.set_xlabel('Year', fontsize=12)
ax.set_title('Landfalling AR Counts and CMMTEs', fontsize=14)
fig.savefig('../../output/plots/cmmte_yearly_comparison.png', dpi=300)
<Figure size 800x500 with 1 Axes>

Individual Event Comparisons

We also compare our products on an event-by-event basis for a particular year of events, verifying if events reported in the CMMT archive are also present in our catalog, and vice versa.

storms2009 = landfalling_storms[landfalling_storms.end_date.dt.year == 2009]
stormtime = to_stormtime_format(storms2009)
animation = make_movie(stormtime, '2009 Storms', '../../output/2009_storms.mp4')
Saving animation to ../../output/2009_storms.mp4...
Loading...
from IPython.display import Video
Video("../../output/2009_storms.mp4", embed=True, html_attributes="controls")
Loading...

Out of the 54 CMMTEs recorded in the period from January 2009 to November 2009, we are able to link 29 of them to ARs in the above animation.