.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "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 ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_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-39 .. code-block:: Python import xarray as xr import matplotlib.pyplot as plt import seaborn as sns from matplotlib.gridspec import GridSpec from cartopy.crs import Robinson, PlateCarree from xeofs.models import EOF, EOFRotator sns.set_context("paper") sst = xr.tutorial.open_dataset("ersstv5")["sst"] .. GENERATED FROM PYTHON SOURCE LINES 40-41 Perform the actual analysis .. GENERATED FROM PYTHON SOURCE LINES 41-61 .. code-block:: Python components = [] scores = [] # (1) Standard EOF without regularization model = 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 = 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 = EOFRotator(n_modes=50, power=4) rot_pro.fit(model) components.append(rot_pro.components()) scores.append(rot_pro.scores()) .. rst-class:: sphx-glr-script-out .. code-block:: none /home/slevang/miniconda3/envs/xeofs-docs/lib/python3.11/site-packages/numpy/lib/nanfunctions.py:1879: RuntimeWarning: Degrees of freedom <= 0 for slice. var = nanvar(a, axis=axis, dtype=dtype, out=out, ddof=ddof, .. GENERATED FROM PYTHON SOURCE LINES 62-67 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 67-99 .. code-block:: Python 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:: /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: /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 6.472 seconds) .. _sphx_glr_download_auto_examples_1single_plot_rotated_eof.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_rotated_eof.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_rotated_eof.py ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_