.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_gallery/plot_spatial_pcf.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_gallery_plot_spatial_pcf.py: .. _2D_spatial_parabolic_cylinder_function_example: 2D Spatial Parabolic Cylinder Function ================================================================================= Ever wondered how atmospheric waves boogie along the equator? Let's explore how to isolate these fascinating dancers (Kelvin waves, Rossby waves, and friends) using parabolic cylinder functions! Before proceeding with all the steps, first import some necessary libraries and packages .. GENERATED FROM PYTHON SOURCE LINES 12-16 .. code-block:: Python import xarray as xr import cartopy.crs as ccrs import easyclimate as ecl .. GENERATED FROM PYTHON SOURCE LINES 17-24 Loading the Data ------------------------------- First, we need some atmospheric data to work with - think of this as setting up the dance floor for our waves: .. tip:: You can download following datasets here: :download:`Download uwnd_vwnd_hgt_equtorial_2021_2024.nc ` .. GENERATED FROM PYTHON SOURCE LINES 24-28 .. code-block:: Python uvz_data = xr.open_dataset("uwnd_vwnd_hgt_equtorial_2021_2024.nc") uvz_data .. raw:: html
<xarray.Dataset> Size: 43MB
    Dimensions:  (time: 1461, lon: 144, lat: 17)
    Coordinates:
      * time     (time) datetime64[ns] 12kB 2021-01-01 2021-01-02 ... 2024-12-31
      * lon      (lon) float32 576B 0.0 2.5 5.0 7.5 10.0 ... 350.0 352.5 355.0 357.5
      * lat      (lat) float32 68B -20.0 -17.5 -15.0 -12.5 ... 12.5 15.0 17.5 20.0
        level    float32 4B ...
    Data variables:
        hgt      (time, lat, lon) float32 14MB ...
        uwnd     (time, lat, lon) float32 14MB ...
        vwnd     (time, lat, lon) float32 14MB ...


.. GENERATED FROM PYTHON SOURCE LINES 29-33 Isolating Wave Types ------------------------------------------- Now for the star of our show: the 2D spatial parabolic cylinder function filter :py:func:`easyclimate.filter.filter_2D_spatial_parabolic_cylinder_function `! This function works like a talented bouncer, only letting specific wave types into our analysis: .. GENERATED FROM PYTHON SOURCE LINES 33-37 .. code-block:: Python result = ecl.filter.filter_2D_spatial_parabolic_cylinder_function(uvz_data.uwnd, uvz_data.vwnd, uvz_data.hgt) result .. raw:: html
<xarray.Dataset> Size: 343MB
    Dimensions:    (wave_type: 4, lat: 17, lon: 144, time: 1461)
    Coordinates:
      * wave_type  (wave_type) <U6 96B 'kelvin' 'wmrg' 'r1' 'r2'
      * lat        (lat) float32 68B -20.0 -17.5 -15.0 -12.5 ... 12.5 15.0 17.5 20.0
        level      float32 4B 850.0
      * lon        (lon) float32 576B 0.0 2.5 5.0 7.5 ... 350.0 352.5 355.0 357.5
      * time       (time) datetime64[ns] 12kB 2021-01-01 2021-01-02 ... 2024-12-31
    Data variables:
        u          (wave_type, time, lat, lon) float64 114MB -0.001955 ... 0.0107
        v          (wave_type, time, lat, lon) float64 114MB 0.0 0.0 ... 0.01983
        z          (wave_type, time, lat, lon) float64 114MB -0.004085 ... 0.0642


.. GENERATED FROM PYTHON SOURCE LINES 38-46 Visualizing the Waves ------------------------------- Let's meet our wave dancers one by one and see their unique moves! The Graceful Kelvin Wave ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Kelvin waves move eastward with elegant symmetry, like ballet dancers: .. GENERATED FROM PYTHON SOURCE LINES 46-71 .. code-block:: Python fig, ax = ecl.plot.quick_draw_spatial_basemap(figsize=(9, 4), central_longitude=180) ax.set_extent([20, 180, -20, 20], crs = ccrs.PlateCarree()) # Contour plot for height field result.sel(wave_type = "kelvin").z.sel(time = "2023-12-15").plot.contourf( ax = ax, levels=21, transform = ccrs.PlateCarree(), cbar_kwargs={"location": "bottom", "aspect": 50, "shrink": 0.5}, ) # Quiver plot for wind vectors result.sel(wave_type = "kelvin")[["u", "v"]].sel(time = "2023-12-15").thin(lon=1, lat=1).plot.quiver( x = "lon", y = 'lat', u = "u", v = "v", ax = ax, scale = 30, headlength = 5, minlength = 1.5, transform = ccrs.PlateCarree() ) ax.set_title("Kelvin Waves") .. image-sg:: /auto_gallery/images/sphx_glr_plot_spatial_pcf_001.png :alt: Kelvin Waves :srcset: /auto_gallery/images/sphx_glr_plot_spatial_pcf_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 1.0, 'Kelvin Waves') .. GENERATED FROM PYTHON SOURCE LINES 72-76 The WMRG Wave ~~~~~~~~~~~~~~~~~~~~~~~~~~ Westward-moving Mixed Rossby-Gravity waves have more complex moves, like contemporary dancers: .. GENERATED FROM PYTHON SOURCE LINES 76-98 .. code-block:: Python fig, ax = ecl.plot.quick_draw_spatial_basemap(figsize=(9, 4), central_longitude=180) ax.set_extent([20, 180, -20, 20], crs = ccrs.PlateCarree()) result.sel(wave_type = "wmrg").z.sel(time = "2023-12-15").plot.contourf( ax = ax, levels=21, transform = ccrs.PlateCarree(), cbar_kwargs={"location": "bottom", "aspect": 50, "shrink": 0.5}, ) result.sel(wave_type = "wmrg")[["u", "v"]].sel(time = "2023-12-15").thin(lon=1, lat=1).plot.quiver( x = "lon", y = 'lat', u = "u", v = "v", ax = ax, scale = 30, headlength = 5, minlength = 1.5, transform = ccrs.PlateCarree() ) ax.set_title("Westward Mixed Rossby-Gravity Waves") .. image-sg:: /auto_gallery/images/sphx_glr_plot_spatial_pcf_002.png :alt: Westward Mixed Rossby-Gravity Waves :srcset: /auto_gallery/images/sphx_glr_plot_spatial_pcf_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 1.0, 'Westward Mixed Rossby-Gravity Waves') .. GENERATED FROM PYTHON SOURCE LINES 99-106 The Rossby Waves ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rossby waves come in different "generations", let's meet the first two: :math:`[n=1]` Rossby Wave ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. GENERATED FROM PYTHON SOURCE LINES 106-128 .. code-block:: Python fig, ax = ecl.plot.quick_draw_spatial_basemap(figsize=(9, 4), central_longitude=180) ax.set_extent([20, 180, -20, 20], crs = ccrs.PlateCarree()) result.sel(wave_type = "r1").z.sel(time = "2023-12-15").plot.contourf( ax = ax, levels=21, transform = ccrs.PlateCarree(), cbar_kwargs={"location": "bottom", "aspect": 50, "shrink": 0.5}, ) result.sel(wave_type = "r1")[["u", "v"]].sel(time = "2023-12-15").thin(lon=1, lat=1).plot.quiver( x = "lon", y = 'lat', u = "u", v = "v", ax = ax, scale = 70, headlength = 5, minlength = 1.5, transform = ccrs.PlateCarree() ) ax.set_title("$n = 1$ Equatorial Rossby Waves") .. image-sg:: /auto_gallery/images/sphx_glr_plot_spatial_pcf_003.png :alt: $n = 1$ Equatorial Rossby Waves :srcset: /auto_gallery/images/sphx_glr_plot_spatial_pcf_003.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 1.0, '$n = 1$ Equatorial Rossby Waves') .. GENERATED FROM PYTHON SOURCE LINES 129-132 :math:`[n=2]` Rossby Wave ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. GENERATED FROM PYTHON SOURCE LINES 132-154 .. code-block:: Python fig, ax = ecl.plot.quick_draw_spatial_basemap(figsize=(9, 4), central_longitude=180) ax.set_extent([20, 180, -20, 20], crs = ccrs.PlateCarree()) result.sel(wave_type = "r2").z.sel(time = "2023-12-15").plot.contourf( ax = ax, levels=21, transform = ccrs.PlateCarree(), cbar_kwargs={"location": "bottom", "aspect": 50, "shrink": 0.5}, ) result.sel(wave_type = "r2")[["u", "v"]].sel(time = "2023-12-15").thin(lon=1, lat=1).plot.quiver( x = "lon", y = 'lat', u = "u", v = "v", ax = ax, scale = 40, headlength = 5, minlength = 1.5, transform = ccrs.PlateCarree() ) ax.set_title("$n = 2$ Equatorial Rossby Waves") .. image-sg:: /auto_gallery/images/sphx_glr_plot_spatial_pcf_004.png :alt: $n = 2$ Equatorial Rossby Waves :srcset: /auto_gallery/images/sphx_glr_plot_spatial_pcf_004.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 1.0, '$n = 2$ Equatorial Rossby Waves') .. GENERATED FROM PYTHON SOURCE LINES 155-171 Behind the Scenes: How the Magic Works ---------------------------------------------- The :py:func:`easyclimate.filter.filter_2D_spatial_parabolic_cylinder_function ` performs some serious atmospheric wizardry: 1. Detrending and Windowing: Prepares the data by removing trends and applying spectral windows 2. Variable Transformation: Creates new variables that better represent wave structures 3. Fourier Analysis: Identifies frequency and wavenumber components 4. Projection: Maps the data onto parabolic cylinder functions that match equatorial wave structures 5. Filtering: Isolates specific wave types based on their characteristic patterns 6. Reconstruction: Brings everything back to physical space for visualization Each wave type has its own signature moves: - Kelvin Waves: Eastward-moving, symmetric about the equator (:math:`n=0` mode) - WMRG Waves: Westward-moving with mixed characteristics (:math:`n=1` mode) - Rossby Waves: Westward-moving with more complex structures (:math:`n=2`, :math:`n=3` modes) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 9.332 seconds) .. _sphx_glr_download_auto_gallery_plot_spatial_pcf.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_spatial_pcf.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_spatial_pcf.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_spatial_pcf.zip `