
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "content/user_guide/auto_examples/1single/plot_rotated_eof.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_content_user_guide_auto_examples_1single_plot_rotated_eof.py>`
        to download the full example code

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_content_user_guide_auto_examples_1single_plot_rotated_eof.py:


Rotated EOF analysis
========================

EOF (Empirical Orthogonal Function) analysis is commonly used in climate science, interpreting
the derived eigenvectors (EOFs) as climatic variability patterns. However, due to
the inherent orthogonality constraint in EOF analysis, the interpretation of all
but the first EOF can be problematic. Rotated EOF analysis, using optimization criteria
like Varimax and Promax, offers a solution by releasing this orthogonality constraint,
thus enabling a more accurate interpretation of variability patterns.

Both Varimax (orthogonal) and Promax (oblique) rotations result in "sparse" solutions,
meaning the EOFs become more interpretable by limiting the number of variables that
contribute to each EOF. This rotation effectively serves as a regularization method
for the EOF solution, with the strength of regularization determined by the power parameter;
the higher the value, the sparser the EOFs.

Promax rotation, with a small regularization value (i.e., power=1), reverts to Varimax
rotation. In this context, we compare the first three modes of EOF analysis: (1)
without regularization, (2) with Varimax rotation, and (3) with Promax rotation.

We'll start by loading the necessary packages and data:

.. GENERATED FROM PYTHON SOURCE LINES 24-38

.. code-block:: default


    import matplotlib.pyplot as plt
    import seaborn as sns
    import xarray as xr
    from cartopy.crs import PlateCarree, Robinson
    from matplotlib.gridspec import GridSpec

    import xeofs as xe

    sns.set_context("paper")

    sst = xr.tutorial.open_dataset("ersstv5")["sst"]









.. GENERATED FROM PYTHON SOURCE LINES 39-40

Perform the actual analysis

.. GENERATED FROM PYTHON SOURCE LINES 40-60

.. code-block:: default


    components = []
    scores = []
    # (1) Standard EOF without regularization
    model = xe.single.EOF(n_modes=100, standardize=True, use_coslat=True)
    model.fit(sst, dim="time")
    components.append(model.components())
    scores.append(model.scores())
    # (2) Varimax-rotated EOF analysis
    rot_var = xe.single.EOFRotator(n_modes=50, power=1)
    rot_var.fit(model)
    components.append(rot_var.components())
    scores.append(rot_var.scores())
    # (3) Promax-rotated EOF analysis
    rot_pro = xe.single.EOFRotator(n_modes=50, power=4)
    rot_pro.fit(model)
    components.append(rot_pro.components())
    scores.append(rot_pro.scores())









.. GENERATED FROM PYTHON SOURCE LINES 61-66

Create figure showing the first 6 modes for all 3 cases. While the first mode
is very similar in all three cases the subsequent modes of the standard
solution exhibit dipole and tripole-like patterns. Under Varimax and Promax
rotation, these structures completely disappear suggesting that these patterns
were mere artifacts due to the orthogonality.

.. GENERATED FROM PYTHON SOURCE LINES 66-98

.. code-block:: default


    proj = Robinson(central_longitude=180)
    kwargs = {
        "cmap": "RdBu",
        "transform": PlateCarree(),
        "vmin": -0.03,
        "vmax": +0.03,
        "add_colorbar": False,
    }

    fig = plt.figure(figsize=(10, 5))
    gs = GridSpec(3, 4)
    ax_std = [fig.add_subplot(gs[0, i], projection=proj) for i in range(4)]
    ax_var = [fig.add_subplot(gs[1, i], projection=proj) for i in range(4)]
    ax_pro = [fig.add_subplot(gs[2, i], projection=proj) for i in range(4)]

    for i, (a0, a1, a2) in enumerate(zip(ax_std, ax_var, ax_pro)):
        mode = i + 1
        a0.coastlines(color=".5")
        a1.coastlines(color=".5")
        a2.coastlines(color=".5")
        components[0].sel(mode=mode).plot(ax=a0, **kwargs)
        components[1].sel(mode=mode).plot(ax=a1, **kwargs)
        components[2].sel(mode=mode).plot(ax=a2, **kwargs)

    title_kwargs = dict(rotation=90, va="center", weight="bold")
    ax_std[0].text(-0.1, 0.5, "Standard", transform=ax_std[0].transAxes, **title_kwargs)
    ax_var[0].text(-0.1, 0.5, "Varimax", transform=ax_var[0].transAxes, **title_kwargs)
    ax_pro[0].text(-0.1, 0.5, "Promax", transform=ax_pro[0].transAxes, **title_kwargs)

    plt.tight_layout()
    plt.savefig("rotated_eof.jpg", dpi=200)



.. image-sg:: /content/user_guide/auto_examples/1single/images/sphx_glr_plot_rotated_eof_001.png
   :alt: mode = 1, mode = 2, mode = 3, mode = 4, mode = 1, mode = 2, mode = 3, mode = 4, mode = 1, mode = 2, mode = 3, mode = 4
   :srcset: /content/user_guide/auto_examples/1single/images/sphx_glr_plot_rotated_eof_001.png
   :class: sphx-glr-single-img






.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 13.936 seconds)


.. _sphx_glr_download_content_user_guide_auto_examples_1single_plot_rotated_eof.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example




    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_rotated_eof.py <plot_rotated_eof.py>`

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_rotated_eof.ipynb <plot_rotated_eof.ipynb>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
