<jupyter_start><jupyter_text>Xarray 7: Calculating ENSO with Xarray ---  Objectives - Load SST data from CESM2- Mask data using `.where()` method- Compute climatologies and anomalies using `.groupby()`- Use `.rolling()` to compute moving average- Compute, normalize, and plot the Niño 3.4 Index   Prerequisites| Concepts | Importance | Notes || --- | --- | --- || [Introduction to Xarray](./xarray.ipynb) | Necessary | || [Computation and Masking](./computation-masking.ipynb) | Necessary | |- **Time to learn**: 20 minutes ---  Imports<jupyter_code>import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import xarray as xr
from pythia_datasets import DATASETS<jupyter_output><empty_output><jupyter_text>Niño 3.4 Index In this notebook, we are going to combine all concepts/topics we've covered so far to compute [Niño 3.4 Index](https://climatedataguide.ucar.edu/climate-data/nino-sst-indices-nino-12-3-34-4-oni-and-tni) for the CESM2 submission for the [CMIP6 project](https://esgf-node.llnl.gov/projects/cmip6/). > Niño 3.4 (5N-5S, 170W-120W): The Niño 3.4 anomalies may be thought of as representing the average equatorial SSTs across the Pacific from about the dateline to the South American coast. The Niño 3.4 index typically uses a 5-month running mean, and El Niño or La Niña events are defined when the Niño 3.4 SSTs exceed +/- 0.4C for a period of six months or more.> Nino X Index computation: (a) Compute area averaged total SST from Niño X region; (b) Compute monthly climatology (e.g., 1950-1979) for area averaged total SST from Niño X region, and subtract climatology from area averaged total SST time series to obtain anomalies; (c) Smooth the anomalies with a 5-month running mean; (d) Normalize the smoothed values by its standard deviation over the climatological period.![](https://www.ncdc.noaa.gov/monitoring-content/teleconnections/nino-regions.gif)At the end of this notebook, you should be able to produce a plot that looks similar to this [Oceanic Niño Index plot](https://climatedataguide.ucar.edu/sites/default/files/styles/node_lightbox_display/public/key_figures/climate_data_set/indices_oni_2_2_lg.png?itok=61jS7Jz7):![](https://climatedataguide.ucar.edu/sites/default/files/styles/node_lightbox_display/public/key_figures/climate_data_set/indices_oni_2_2_lg.png?itok=61jS7Jz7) Open the sea surface temperature and areacello datasets and use Xarray's `merge` method to combine them into a single one.<jupyter_code>filepath = DATASETS.fetch('CESM2_sst_data.nc')
data = xr.open_dataset(filepath)
filepath2 = DATASETS.fetch('CESM2_grid_variables.nc')
areacello = xr.open_dataset(filepath2).areacello
ds = xr.merge([data, areacello])
ds
ds.tos.isel(time=0).min()<jupyter_output><empty_output><jupyter_text>Visualize the first time slice to make sure the data looks okay<jupyter_code>fig = plt.figure(figsize=(12, 6))
ax = plt.axes(projection=ccrs.Robinson(central_longitude=180))
ax.coastlines()
ax.gridlines()
ds.tos.isel(time=0).plot(
    ax=ax, transform=ccrs.PlateCarree(), vmin=-2, vmax=30, cbar_kwargs={'shrink': 0.5}, cmap='coolwarm'
);<jupyter_output><empty_output><jupyter_text>Select the Niño 3.4 region There are a couple ways we could selecting the Niño 3.4 region:1. Use `sel()` or `isel()`2. Use `where()` and select all vlaues within the bounds of interest 1: `sel`:<jupyter_code>tos_nino34 = ds.sel(lat=slice(-5, 5), lon=slice(190, 240))
tos_nino34<jupyter_output><empty_output><jupyter_text>2: `where`:<jupyter_code>tos_nino34 = ds.where((ds.lat<5) & (ds.lat>-5) & (ds.lon>190) & (ds.lon<240), drop=True)
tos_nino34<jupyter_output><empty_output><jupyter_text>Let's plot the selected region to make sure we are doing the right thing.<jupyter_code>fig = plt.figure(figsize=(12, 6))
ax = plt.axes(projection=ccrs.Robinson(central_longitude=180))
ax.coastlines()
ax.gridlines()
tos_nino34.tos.isel(time=0).plot(
    ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'shrink': 0.5}, vmin=-2, vmax=30, cmap='coolwarm'
)
ax.set_extent((120, 300, 10, -10))<jupyter_output><empty_output><jupyter_text>Compute monthly climatology Compute the monthly climo for area averaged total SST from Niño 3.4 region, and subtract climatology from area averaged total SST time series to obtain anomalies<jupyter_code>gb = tos_nino34.tos.groupby('time.month')
tos_nino34_anom = gb - gb.mean(dim='time')
index_nino34 = tos_nino34_anom.weighted(tos_nino34.areacello).mean(dim=['lat', 'lon'])<jupyter_output><empty_output><jupyter_text>Smooth the anomalies with a 5-month running mean<jupyter_code>index_nino34_rolling_mean = index_nino34.rolling(time=5,center=True).mean()
index_nino34.plot(size=8)
index_nino34_rolling_mean.plot()
plt.legend(['anomaly', '5-month running mean anomaly']);<jupyter_output><empty_output><jupyter_text>Normalize the smoothed values We'll normalize the values by dividing the rolling mean by the standard deviation.<jupyter_code>std_dev = tos_nino34.tos.std()
std_dev
normalized_index_nino34_rolling_mean = index_nino34_rolling_mean / std_dev<jupyter_output><empty_output><jupyter_text>Visualize the computed Niño 3.4 index. We'll highlight values in excess of 0.5, roughly corresponding to El Niño (warm) / La Niña (cold) events.<jupyter_code>fig = plt.figure(figsize=(12, 6))

plt.fill_between(
    normalized_index_nino34_rolling_mean.time.data,
    normalized_index_nino34_rolling_mean.where(
        normalized_index_nino34_rolling_mean >= 0.4
    ).data,
    0.4,
    color='red',
    alpha=0.9,
)
plt.fill_between(
    normalized_index_nino34_rolling_mean.time.data,
    normalized_index_nino34_rolling_mean.where(
        normalized_index_nino34_rolling_mean <= -0.4
    ).data,
    -0.4,
    color='blue',
    alpha=0.9,
)

normalized_index_nino34_rolling_mean.plot(color='black')
plt.axhline(0, color='black', lw=0.5)
plt.axhline(0.4, color='black', linewidth=0.5, linestyle='dotted')
plt.axhline(-0.4, color='black', linewidth=0.5, linestyle='dotted')
plt.title('Niño 3.4 Index');<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12131860776439089, 'fraction_numerical': 0.03480589022757698, 'mean_word_length': 5.933874709976799, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 46, 'https://': 5, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '296739', 'license': 'CC0-1.0', 'n_tokens_mistral': 2296, 'n_tokens_neox': 2124, 'n_words': 511, 'path': '07_Xarray_enso.ipynb', 'repo_name': 'ktyle/binder_xarray', 'size': '5976'}