Introduction
To read and plot El Niño / La Niña time series in Python, a simple and reliable approach is to use the Oceanic Niño Index (ONI) provided by NOAA/CPC. The ONI is based on the 3-month running mean of sea surface temperature (SST) anomalies in the Niño 3.4 region (central equatorial Pacific).
What are El Niño and La Niña?
El Niño and La Niña are the two opposite phases of the El Niño–Southern Oscillation (ENSO), a major mode of climate variability:
- El Niño corresponds to warmer-than-average SSTs in the central and eastern tropical Pacific. It typically leads to significant impacts such as increased rainfall in some regions (e.g., South America) and droughts in others (e.g., Australia, Indonesia).
- La Niña corresponds to cooler-than-average SSTs in the same region, often producing roughly opposite climate effects.
These phenomena influence global weather patterns, including precipitation, temperature, tropical cyclones, and even wildfire activity, making ENSO monitoring essential for climate and environmental studies.
NOAA defines El Niño / La Niña events using a threshold of ±0.5 °C sustained over 5 consecutive overlapping seasons. Note that the most recent ONI values may be revised as new data becomes available.
NOAA provides ONI as a plain text dataset, and additional ENSO-related indices (Niño 3.4, MEI, etc.) are also available. Currently, ONI extends from 1950 to 2026.
Downloads ONI from NOAA
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd import matplotlib.pyplot as plt # NOAA CPC ONI text file url = "https://www.cpc.ncep.noaa.gov/data/indices/oni.ascii.txt" # Read data df = pd.read_csv(url, sep=r"\s+") print(df.head()) print(df.columns) |

This first step loads the ONI dataset directly from NOAA servers. The file typically contains:
- YR → year
- SEAS → overlapping 3-month season (e.g., DJF, JFM, etc.)
- ANOM → SST anomaly (°C)
Converts the season labels into dates, classifies El Niño / Neutral / La Niña
Usually this file contains columns like YR, SEAS, ANOM.
If needed, you can inspect df.columns and adapt the code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import pandas as pd import matplotlib.pyplot as plt url = "https://www.cpc.ncep.noaa.gov/data/indices/oni.ascii.txt" df = pd.read_csv(url, sep=r"\s+") # Keep only the columns we need # Common NOAA format: YR, SEAS, ANOM df = df[["YR", "SEAS", "ANOM"]].copy() # Map overlapping 3-month seasons to a representative month season_to_month = { "DJF": 1, "JFM": 2, "FMA": 3, "MAM": 4, "AMJ": 5, "MJJ": 6, "JJA": 7, "JAS": 8, "ASO": 9, "SON": 10, "OND": 11, "NDJ": 12, } df["month"] = df["SEAS"].map(season_to_month) df["date"] = pd.to_datetime(dict(year=df["YR"], month=df["month"], day=15)) # Simple classification by threshold df["phase"] = "Neutral" df.loc[df["ANOM"] >= 0.5, "phase"] = "El Niño" df.loc[df["ANOM"] <= -0.5, "phase"] = "La Niña" print(df.head()) |

Here we:
- Convert seasonal labels into actual timestamps (mid-month approximation)
- Classify each period into El Niño, La Niña, or Neutral based on SST anomaly thresholds
Plots the time series
Plot the ONI time series:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | plt.figure(figsize=(14, 5)) plt.plot(df["date"], df["ANOM"], linewidth=1) # Threshold lines plt.axhline(0.5, linestyle="--", linewidth=1) plt.axhline(-0.5, linestyle="--", linewidth=1) plt.axhline(0.0, linewidth=0.8) # Shade El Niño and La Niña periods elnino = df["ANOM"] >= 0.5 lanina = df["ANOM"] <= -0.5 plt.fill_between(df["date"], df["ANOM"], 0.5, where=elnino, alpha=0.3) plt.fill_between(df["date"], df["ANOM"], -0.5, where=lanina, alpha=0.3) plt.title("NOAA Oceanic Niño Index (ONI)") plt.xlabel("Time") plt.ylabel("ONI anomaly (°C)") plt.tight_layout() plt.show() |

This visualization highlights:
- Warm phases (El Niño) above +0.5 °C
- Cold phases (La Niña) below −0.5 °C
- Neutral conditions in between
If you want to extract only El Niño / La Niña periods:
1 2 | df_events = df[df["phase"] != "Neutral"].copy() print(df_events[["date", "SEAS", "ANOM", "phase"]].tail(20)) |

Detecting official ENSO events (NOAA definition)
If you want the official NOAA-style episodes, not just months above/below ±0.5, use the 5-season persistence rule:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import numpy as np df["warm"] = df["ANOM"] >= 0.5 df["cold"] = df["ANOM"] <= -0.5 # Rolling 5-season condition df["warm5"] = df["warm"].rolling(5, min_periods=5).sum() >= 5 df["cold5"] = df["cold"].rolling(5, min_periods=5).sum() >= 5 # Expand to mark the whole 5-season windows warm_idx = set() cold_idx = set() for i in df.index[df["warm5"]]: warm_idx.update(range(i - 4, i + 1)) for i in df.index[df["cold5"]]: cold_idx.update(range(i - 4, i + 1)) df["phase_official_like"] = "Neutral" df.loc[df.index.isin(warm_idx), "phase_official_like"] = "El Niño" df.loc[df.index.isin(cold_idx), "phase_official_like"] = "La Niña" print(df[["date", "SEAS", "ANOM", "phase_official_like"]].tail(30)) |

This step ensures consistency with NOAA’s official ENSO classification methodology.
Monthly Niño 3.4
If you prefer a monthly resolution, NOAA also provides Niño 3.4 SST anomalies based on ERSSTv5.
This is useful when:
- You want higher temporal resolution
- You plan to compute your own rolling averages
- You want smoother visualizations
Python Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | import pandas as pd import matplotlib.pyplot as plt url = "https://www.cpc.ncep.noaa.gov/data/indices/ersst5.nino.mth.91-20.ascii" df = pd.read_csv(url, sep=r"\s+") print(df.columns) # Niño 3.4 anomaly column in your file df = df[["YR", "MON", "ANOM.3"]].copy() df = df.rename(columns={"ANOM.3": "ANOM"}) # Create datetime df["date"] = pd.to_datetime(dict(year=df["YR"], month=df["MON"], day=1)) anom = df["ANOM"] plt.figure(figsize=(16, 6)) # Background zones plt.axhspan(0.5, anom.max() + 0.2, color="red", alpha=0.08) plt.axhspan(-0.5, 0.5, color="gray", alpha=0.08) plt.axhspan(anom.min() - 0.2, -0.5, color="blue", alpha=0.08) # Main line plt.plot(df["date"], anom, color="gray", linewidth=1.2, alpha=0.9) # Colored overlays plt.plot(df["date"], anom.where(anom >= 0.5), color="red", linewidth=2.5, label="El Niño") plt.plot(df["date"], anom.where(anom <= -0.5), color="blue", linewidth=2.5, label="La Niña") plt.plot( df["date"], anom.where((anom > -0.5) & (anom < 0.5)), color="gray", linewidth=2.0, label="Neutral" ) # Filled areas plt.fill_between(df["date"], 0, anom, where=anom >= 0.5, color="red", alpha=0.25) plt.fill_between(df["date"], 0, anom, where=anom <= -0.5, color="blue", alpha=0.25) plt.fill_between( df["date"], 0, anom, where=(anom > -0.5) & (anom < 0.5), color="gray", alpha=0.15 ) # Threshold lines plt.axhline(0.5, color="red", linestyle="--", linewidth=1) plt.axhline(-0.5, color="blue", linestyle="--", linewidth=1) plt.axhline(0, color="black", linewidth=0.8) plt.title("Monthly Niño 3.4 SST Anomalies") plt.xlabel("Time") plt.ylabel("Anomaly (°C)") plt.legend(frameon=False) plt.tight_layout() plt.show() |

Use Cases
The Niño 3.4 index is not only useful for visualization but also plays a key role in many climate and environmental applications.
Precipitation and Drought Monitoring
ENSO strongly influences global rainfall patterns. El Niño events are typically associated with wetter conditions in parts of South America and the southern United States, while La Niña often leads to increased rainfall in Australia and Indonesia. This makes Niño 3.4 a valuable predictor for drought and flood risk.
Wildfire Activity
ENSO affects vegetation dryness and fuel availability, which directly impacts wildfire activity. For example, El Niño conditions can increase fire risk in regions such as the Amazon and Indonesia, while La Niña may enhance fire activity in parts of North America. Combining Niño 3.4 with satellite-derived Fire Radiative Power (FRP) or burned area datasets provides insight into interannual fire variability.
Global Temperature Variability
El Niño and La Niña significantly modulate global temperature anomalies. Strong El Niño events are often associated with temporary spikes in global mean temperature, while La Niña tends to produce cooling effects. This is important for interpreting long-term climate trends.
Tropical Cyclones
ENSO influences hurricane activity worldwide. El Niño tends to suppress Atlantic hurricanes but enhances cyclone activity in the Pacific, while La Niña has the opposite effect.
Vegetation and Agriculture
ENSO impacts crop yields, vegetation growth, and drought conditions. The Niño 3.4 index can be combined with satellite vegetation indices (e.g., NDVI) to monitor ecosystem response and agricultural productivity.
Satellite Observations and Retrievals
ENSO-driven changes in cloud cover, atmospheric moisture, and aerosols can affect satellite retrieval algorithms. Understanding ENSO variability can help interpret biases and uncertainties in remote sensing products.
References
| Links | Site |
|---|---|
| ERSSTv5 Niño Indices | NOAA CPC – Monthly Niño 3.4 data used in this tutorial |
| Oceanic Niño Index (ONI) | NOAA CPC – Official ENSO classification method |
| Climate Indices Portal | NOAA CPC – Access to multiple ENSO-related datasets |
| Niño 3.4 Time Series | NOAA PSL – Alternative Niño 3.4 dataset and documentation |
| ERSSTv5 Dataset | NOAA NCEI – Source SST dataset behind Niño indices |
