import numpy as np
import datetime as dt
import pandas as pd
import xarray as xr
import matplotlib as mpl # Needed to access mpl.colormaps[cmapname]
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
The centroid track information is contained in the NetCDF track files. The tracks are saved as stitched latitude (centroid_lat_stitched) and longitude (centroid_lat_stitched) data. In the stitched data, the individual system tracks are separated by NaN values. The track times (datetime_stitched) and areas (area_stitched) are stitched in the same manner.
lptid_stitched.# Read in tracks for a year of LPT.
fn_lpt_systems = ('data/imerg/g50_72h/thresh12/systems/'
+ 'lpt_systems_imerg_2022060100_2023063023.nc')
lpt_systems = xr.load_dataset(fn_lpt_systems)
lpt_systems
<xarray.Dataset>
Dimensions: (nlpt: 108, nstitch: 51707, nobj: 1615)
Coordinates:
* nlpt (nlpt) int32 0 1 2 3 ... 105 106 107
* nstitch (nstitch) int32 0 1 2 ... 51705 51706
* nobj (nobj) int32 0 1 2 ... 1612 1613 1614
Data variables: (12/38)
lptid (nlpt) float64 0.1 1.1 ... 60.2 61.1
lpt_begin_index (nlpt) int64 1 177 598 ... 51295 51526
lpt_end_index (nlpt) int64 175 596 ... 51524 51705
centroid_lon_start (nlpt) float64 264.9 298.4 ... 204.1
centroid_lat_start (nlpt) float64 13.69 -12.56 ... -23.2
centroid_lon_end (nlpt) float64 290.1 261.9 ... 206.4
... ...
min_filtered_running_field (nstitch) float64 nan 12.0 ... nan
max_inst_field (nstitch) float64 nan 40.38 ... nan
max_running_field (nstitch) float64 nan 196.9 ... nan
max_filtered_running_field (nstitch) float64 nan 18.93 ... nan
num_objects (nlpt) int32 175 420 723 ... 230 180
objid (nlpt, nobj) float64 2.022e+13 ... nan
Attributes:
description: LPT Systems NetCDF file.# Create a simple time-longitude plot covering the Indo-Pacific region
plt.figure()
# Markers with size according to by area
plt.scatter(lpt_systems['centroid_lon_stitched'],
lpt_systems['timestamp_stitched'],
s = 1e-5*lpt_systems['area_stitched'],
c = 'none', edgecolors='k', zorder=200,
linewidths=0.3)
# Draw a line for the centroid track
plt.plot(lpt_systems['centroid_lon_stitched'],
lpt_systems['timestamp_stitched'], linewidth=1.3,
color = 'darkorange', zorder=300)
# Set some plotting range limits
plt.gca().set_xlim([60, 240])
plt.gca().set_ylim([dt.datetime(2022,11,1,0,0,0),
dt.datetime(2023,5,1,0,0,0)])
# Some labeling
plt.gca().set_xlabel('Longitude')
# Add grid lines
plt.gca().grid(True, axis='both', linewidth=0.5,
color='darkgrey', linestyle='--')
plt.title('Time-Longitude of LPT System Centroids')
# Save figure
fn_out = 'demo.time_lon_centroids.png'
print(f'--> {fn_out}')
plt.savefig(fn_out, dpi=100, bbox_inches='tight')
--> demo.time_lon_centroids.png
The list of LPT System IDs is contained in the variable lptid. To link the track coordinates to the LPT IDs, the variable lptid_stitched has the same length as centroid_lon_stitched, and similar variables. Like the others, it has a NaN value inbetween the individual system tracks.
# Plot a map of LPT system tracks, colored by the LPT system ID.
# This can also be done using "scatter" and setting colors to the lptid_stitched
# But here I want to illustrate extracting
# the coordinates for individual LPT systems.
fig = plt.figure()
CMAPNAME='tab10'
cmap = mpl.colormaps[CMAPNAME]
# Set up map background
ax = fig.add_subplot(1,1,1,projection=ccrs.Mercator(central_longitude=180))
ax.coastlines()
ax.set_extent([60, 240, -40, 40], crs=ccrs.PlateCarree())
# Loop over the list of LPT IDs
count = 0
for n, this_lptid in enumerate(lpt_systems['lptid'].data):
# Choose a color for this LPT system.
# The colormap 'tab10' has ten colors
# but we need to feed it a value from 0.0 - 1.0
# Therefore, get the ramainder on integer division by 10
# and divide that by 10.0.
this_color = cmap((n % 10)/10.0)
# Extract the longitude and latitude for this LPT system
# Need to be careful since these IDs are decimal values!!!
#
# For this case, using the == method seems to work
# because lptid and lptid_stitched were saved the same
# way to the NetCDF file.
#
# However, this will NOT work when matching these MJO IDs
# with the values in the MJO list files, because those are
# saved as decimals in text files and read in using Pandas.
#
# USING THE == METHOD WITH LPTID FROM THE MJO LIST FILES
# WILL RESULT IN MISSED MJO CASES!!!
#
# Recommendation: Always use the <0.00001 method for generality.
#
# The == method (not recommended)
# X = lpt_systems['centroid_lon_stitched'].data[
# lpt_systems['lptid_stitched'] == this_lptid]
# Y = lpt_systems['centroid_lat_stitched'].data[
# lpt_systems['lptid_stitched'] == this_lptid]
#
# The <0.00001 method (recommended)
X = lpt_systems['centroid_lon_stitched'].data[
np.abs(lpt_systems['lptid_stitched'] - this_lptid) < 0.00001]
Y = lpt_systems['centroid_lat_stitched'].data[
np.abs(lpt_systems['lptid_stitched'] - this_lptid) < 0.00001]
if len(X) > 0:
count += 1
# Plot the track
ax.plot(X, Y, color=this_color, transform=ccrs.PlateCarree())
print(count, ' systems.')
# Save figure
fn_out = 'demo.map_centroids.png'
print(f'--> {fn_out}')
plt.savefig(fn_out, dpi=100, bbox_inches='tight')
108 systems. --> demo.map_centroids.png
The above plots were for all LPT systems, which are mostly NOT MJO systems.
To determine which ones are MJO LPTs, use the MJO list files. The MJO list files are simple text files that can be read using Pandas. The trick is to use read_fwf not read_csv..
fn_mjo_list = ('data/imerg/g50_72h/thresh12/systems/'
+ 'mjo_lpt_list_imerg_2022060100_2023063023.txt')
mjo_list = pd.read_fwf(fn_mjo_list)
mjo_list
| begin_tracking | end_tracking | lptid | lptgroup | duration | mean_zonal_spd | lpt_begin | lpt_end | eprop_begin_idx | eprop_end_idx | eprop_spd | eprop_dur | eprop_begin | eprop_end | eprop_lon_begin | eprop_lon_end | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2022060100 | 2023063023 | 2.70 | 2 | 425.0 | 7.71 | 2022063017 | 2022071810 | 0 | 415 | 7.66 | 415.0 | 2022063017 | 2022071800 | 63.4 | 169.9 |
| 1 | 2022060100 | 2023063023 | 4.10 | 4 | 777.0 | 0.34 | 2022071714 | 2022081823 | 0 | 520 | 1.35 | 520.0 | 2022071714 | 2022080806 | 66.9 | 103.0 |
| 2 | 2022060100 | 2023063023 | 6.10 | 6 | 202.0 | 3.84 | 2022072110 | 2022072920 | 14 | 200 | 3.98 | 186.0 | 2022072200 | 2022072918 | 270.1 | 291.2 |
| 3 | 2022060100 | 2023063023 | 21.80 | 21 | 1567.0 | -0.45 | 2022092022 | 2022112505 | 972 | 1495 | 1.33 | 523.0 | 2022103110 | 2022112205 | 88.2 | 127.3 |
| 4 | 2022060100 | 2023063023 | 21.40 | 21 | 947.0 | 0.52 | 2022101618 | 2022112505 | 7 | 308 | 3.17 | 301.0 | 2022101701 | 2022102914 | 93.2 | 124.7 |
| 5 | 2022060100 | 2023063023 | 21.80 | 21 | 1567.0 | -0.45 | 2022092022 | 2022112505 | 358 | 614 | 6.58 | 256.0 | 2022100520 | 2022101612 | 95.5 | 139.6 |
| 6 | 2022060100 | 2023063023 | 29.10 | 29 | 955.0 | 2.54 | 2022120201 | 2023011020 | 140 | 955 | 2.93 | 815.0 | 2022120721 | 2023011020 | 89.2 | 168.3 |
| 7 | 2022060100 | 2023063023 | 32.10 | 32 | 884.0 | -0.35 | 2022121616 | 2023012212 | 349 | 758 | -0.07 | 409.0 | 2023010203 | 2023011904 | 290.8 | 301.3 |
| 8 | 2022060100 | 2023063023 | 37.08 | 37 | 720.0 | 4.22 | 2023012019 | 2023021919 | 0 | 610 | 4.25 | 610.0 | 2023012019 | 2023021505 | 91.8 | 186.0 |
| 9 | 2022060100 | 2023063023 | 40.10 | 40 | 416.0 | 0.36 | 2023021322 | 2023030306 | 14 | 243 | 2.36 | 229.0 | 2023021502 | 2023022415 | 292.1 | 314.1 |
| 10 | 2022060100 | 2023063023 | 42.10 | 42 | 725.0 | 0.43 | 2023030502 | 2023040407 | 72 | 290 | 3.67 | 218.0 | 2023030802 | 2023031704 | 285.1 | 311.3 |
| 11 | 2022060100 | 2023063023 | 44.10 | 44 | 841.0 | 5.03 | 2023032106 | 2023042507 | 31 | 841 | 5.06 | 810.0 | 2023032213 | 2023042507 | 77.9 | 229.6 |
| 12 | 2022060100 | 2023063023 | 46.10 | 46 | 341.0 | 0.27 | 2023041500 | 2023042905 | 0 | 341 | 0.27 | 341.0 | 2023041500 | 2023042905 | 294.2 | 306.9 |
| 13 | 2022060100 | 2023063023 | 47.10 | 47 | 246.0 | 1.00 | 2023042009 | 2023043015 | 0 | 170 | 6.24 | 170.0 | 2023042009 | 2023042711 | 3.7 | 34.4 |
| 14 | 2022060100 | 2023063023 | 48.10 | 48 | 588.0 | 0.15 | 2023042510 | 2023051922 | 174 | 454 | 2.11 | 280.0 | 2023050216 | 2023051408 | 71.2 | 90.2 |
| 15 | 2022060100 | 2023063023 | 49.10 | 49 | 465.0 | 0.97 | 2023042812 | 2023051721 | 0 | 443 | 0.97 | 465.0 | 2023042812 | 2023051721 | 154.4 | 179.7 |
| 16 | 2022060100 | 2023063023 | 58.10 | 58 | 418.0 | 2.37 | 2023061313 | 2023063023 | 186 | 374 | 8.77 | 188.0 | 2023062107 | 2023062903 | 127.1 | 172.1 |
# Create a simple time-longitude plot covering the Indo-Pacific region
plt.figure()
# Loop over the list of LPT IDs
count = 0
for n, this_lptid in enumerate(lpt_systems['lptid'].data):
# Extract the longitude and latitude for this LPT system
# Need to be careful since these IDs are decimal values!!!
#
# For this case, using the == method seems to work
# because lptid and lptid_stitched were saved the same
# way to the NetCDF file.
#
# However, this will NOT work when matching these MJO IDs
# with the values in the MJO list files, because those are
# saved as decimals in text files and read in using Pandas.
#
# USING THE == METHOD WITH LPTID FROM THE MJO LIST FILES
# WILL RESULT IN MISSED MJO CASES!!!
#
# Recommendation: Always use the <0.00001 method for generality.
#
# The == method (not recommended)
# X = lpt_systems['centroid_lon_stitched'].data[
# lpt_systems['lptid_stitched'] == this_lptid]
# Y = lpt_systems['timestamp_stitched'].data[
# lpt_systems['lptid_stitched'] == this_lptid]
#
# The <0.00001 method (recommended)
X = lpt_systems['centroid_lon_stitched'].data[
np.abs(lpt_systems['lptid_stitched'] - this_lptid) < 0.00001]
Y = lpt_systems['timestamp_stitched'].data[
np.abs(lpt_systems['lptid_stitched'] - this_lptid) < 0.00001]
# Check whether it is an MJO LPT system.
is_mjo = False
if np.nanmin(np.abs(np.array(mjo_list['lptid'].values) - this_lptid)) < 0.00001:
is_mjo = True
count += 1
print(f'MJO LPT System: {this_lptid}.')
# Choose a color for this LPT system.
# The colormap 'tab10' has ten colors
# but we need to feed it a value from 0.0 - 1.0
# Therefore, get the ramainder on integer division by 10
# and divide that by 10.0.
this_color = cmap((count % 10)/10.0)
# Plot the track
if is_mjo:
plt.gca().plot(X, Y, color=this_color, linewidth=2, zorder=200)
else:
plt.gca().plot(X, Y, color='darkgrey', linewidth=1, zorder=100)
# Set some plotting range limits
plt.gca().set_xlim([60, 240])
plt.gca().set_ylim([dt.datetime(2022,11,1,0,0,0),
dt.datetime(2023,5,1,0,0,0)])
# Some labeling
plt.gca().set_xlabel('Longitude')
# Add grid lines
plt.gca().grid(True, axis='both', linewidth=0.5,
color='darkgrey', linestyle='--')
plt.title('Time-Longitude of LPT System Centroids With MJO Highlighted')
# Save figure
fn_out = 'demo.time_lon_centroids.mjo_lpt.png'
print(f'--> {fn_out}')
plt.savefig(fn_out, dpi=100, bbox_inches='tight')
MJO LPT System: 2.7. MJO LPT System: 4.1. MJO LPT System: 6.1. MJO LPT System: 21.4. MJO LPT System: 21.8. MJO LPT System: 29.1. MJO LPT System: 32.1. MJO LPT System: 37.08. MJO LPT System: 40.1. MJO LPT System: 42.1. MJO LPT System: 44.1. MJO LPT System: 46.1. MJO LPT System: 47.1. MJO LPT System: 48.1. MJO LPT System: 49.1. MJO LPT System: 58.1. --> demo.time_lon_centroids.mjo_lpt.png