Examples of plotting TrackRun subsets

Import the necessary modules

Note Examples below require cartopy package to be installed

[1]:
import cartopy
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from pathlib import Path
import xarray as xr

from octant.core import TrackRun, OctantTrack

To save time, in this example lcc_map function is used to create a map in Lambert Conformal Conic projection.

[2]:
def lcc_map(fig, subplot_grd=111, clon=None, clat=None, coast=None, extent=None):
    """Create cartopy axes in Lambert Conformal projection."""
    proj = ccrs.LambertConformal(central_longitude=clon, central_latitude=clat)

    # Draw a set of axes with coastlines:
    ax = fig.add_subplot(subplot_grd, projection=proj)
    if isinstance(extent, list):
        ax.set_extent(extent, crs=ccrs.PlateCarree())
    if isinstance(coast, dict):
        feature = cartopy.feature.NaturalEarthFeature(
            name="coastline", category="physical", **coast
        )
        ax.add_feature(feature)
    return ax

Some useful declarations for plotting…

[3]:
plt.rcParams["figure.figsize"] = (15, 10)  # change the default figure size
COAST = dict(scale="50m", alpha=0.5, edgecolor="#333333", facecolor="#AAAAAA")
clon = 10
clat = 75
extent = [-20, 50, 65, 85]
LCC_KW = dict(clon=clon, clat=clat, coast=COAST, extent=extent)

mapkw = dict(transform=ccrs.PlateCarree())

Define the common data directory

[4]:
sample_dir = Path(".") / "sample_data"

Data are usually organised in hierarchical directory structure. Here, the relevant parameters are defined.

[5]:
dataset = "era5"
period = "test"
run_id = 0

Construct the full path

[6]:
track_res_dir = sample_dir / dataset / f"run{run_id:03d}" / period

Load the data

Load land-sea mask array from ERA5 dataset:

[7]:
lsm = xr.open_dataarray(sample_dir / dataset / "lsm.nc")
lsm = lsm.squeeze()  # remove singular time dimension

Now load the cyclone tracks themselves

[8]:
tr = TrackRun(track_res_dir)
[9]:
tr
[9]:
Cyclone tracking results
Number of tracks 671
Data columns lon, lat, vo, time, area, vortex_type
Sources
sample_data/era5/run000/test
[10]:
conditions = [
    ("long_lived", [lambda ot: ot.lifetime_h >= 6]),
    (
        "far_travelled_and_very_long_lived",
        [lambda ot: ot.lifetime_h >= 36, lambda ot: ot.gen_lys_dist_km > 300.0],
    ),
    ("strong", [lambda x: x.max_vort > 1e-3]),
]
[11]:
tr.classify(conditions)

… and classify them

What are the indices of “strong” cyclones?

[12]:
tr["strong"].index.get_level_values("track_idx").unique()
[12]:
Int64Index([93, 182, 252, 569, 631], dtype='int64', name='track_idx')

Simple track plot

Select an OctantTrack by its absolute index

[13]:
import pandas as pd
[14]:
random_track = tr["strong"].loc[182]

Here the variable random_track is a subclass of pandas.DataFrame, and it has the following additional attributes and methods:

[15]:
set(random_track.__dir__()).difference(set(pd.DataFrame().__dir__()))
[15]:
{'area',
 'average_speed',
 'coord_view',
 'from_df',
 'from_mux_df',
 'gb',
 'gen_lys_dist_km',
 'lat',
 'lifetime_h',
 'lon',
 'lonlat',
 'lonlat_c',
 'max_vort',
 'plot_track',
 'time',
 'total_dist_km',
 'tridlonlat',
 'tridlonlat_c',
 'vo',
 'vortex_type',
 'within_rectangle'}

One of them is plot_track() method, which is a small wrapper around matplotlib.pyplot.plot() function.

The important (optional) parameter is ax=, via which a track can be plotted in the given axes. For example, below a figure fig is created along with ax, geo-referenced axes, and then the chosen track is added to the plot. The remaining parameters that can be passed to plot_track are keyword arguments of matplotlib.pyplot.plot(*args, **kwargs) function.

Plot a single track on a map

[16]:
fig = plt.figure()
ax = lcc_map(fig, **LCC_KW)
random_track.plot_track(ax=ax, color=None);
../_images/examples_02_Plotting_34_0.png

Plot a single track without a map

a) In the given Axes

[17]:
fig, ax = plt.subplots()
random_track.plot_track(ax=ax);
../_images/examples_02_Plotting_37_0.png

b) Or automatically create figure and axes in the PlateCarree projection

[18]:
random_track.plot_track();
../_images/examples_02_Plotting_39_0.png

The function returns matplotlib axes object, so it can be used for further plotting.

[19]:
ax1 = random_track.plot_track(color='xkcd:stormy blue',
                              linewidth=3,
                              label=f'track 3317')
ax1.legend(loc=4)
ax1.set_title('My plot');
../_images/examples_02_Plotting_41_0.png

Plot all tracks from TrackRun

[20]:
subsets_and_colors = [("long_lived", "#424242"), ("far_travelled_and_very_long_lived", "C0"), ("strong", "C1")]
[21]:
fig = plt.figure()
ax = lcc_map(fig, **LCC_KW)

handles, labels = [], []
for subset_label, color in subsets_and_colors:
    for (_, track) in tr[subset_label].gb:
        track.plot_track(ax=ax, color=color, label=subset_label)

labels, handles = [
    list(getattr({j: i for i, j in zip(*ax.get_legend_handles_labels())}, m)())
    for m in ["keys", "values"]
]
ax.legend(handles, labels, fontsize="x-large", loc=1);
../_images/examples_02_Plotting_44_0.png