3.2.b Amenaza por sequía y estiaje
Aguas bajas extremas del Amazonas, sequía meteorológica y relación con El Niño
En Leticia la sequía no se mide solo en lluvia: se mide en metros de río. Entre agosto y noviembre el Amazonas baja a su mínimo y, cuando la vaciante es extrema, los barcos de carga no llegan al puerto, se encarecen los alimentos y el combustible, se secan los lagos y la quebrada de la que se abastece el acueducto, y mueren peces. Las vaciantes de 2023 y 2024 fueron las más severas registradas en la cuenca Espinoza et al., 2024Costa & Marengo, 2023, y el IDEAM reportó en septiembre de 2024 niveles por debajo de los mínimos históricos en la estación de Leticia IDEAM, 2024.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from IPython.display import Markdown, display
from leticia import clima, fuentes, hidro, viz
from leticia.config import parametros
ph = parametros()["hidrologia"]
nivel = hidro.limpiar_nivel(fuentes.nivel_rio())
minimos = hidro.extremos_anuales(nivel, "min")1. La vaciante de 2024 frente a la historia¶
clim = hidro.climatologia_diaria(nivel[nivel.index.year < 2023], base=(1991, 2020))
fig, ax = plt.subplots(figsize=(10.5, 4))
x = clim.index
ax.fill_between(x, clim["min"] / 100, clim["max"] / 100, color=viz.GRIS, alpha=0.15, label="mín–máx 1988–2022")
ax.fill_between(x, clim["p10"] / 100, clim["p90"] / 100, color=viz.GRIS, alpha=0.3, label="p10–p90")
ax.plot(x, clim["p50"] / 100, color=viz.GRIS, lw=1.2, label="mediana")
for anio, color in ((2010, "#fdae61"), (2023, "#f46d43"), (2024, "#a50026"), (2025, "#4575b4"), (2026, "#313695")):
s = nivel[nivel.index.year == anio]
ax.plot(s.index.dayofyear, s / 100, color=color, lw=1.4, label=str(anio))
for u, et in ((ph["umbral_estiaje_cm"], "aguas muy bajas"), (ph["umbral_estiaje_critico_cm"], "aislamiento del puerto")):
ax.axhline(u / 100, color="k", ls=":", lw=0.8)
ax.text(5, u / 100 + 0.15, f"{u/100:.0f} m: {et} (ilustrativo)", fontsize=7)
ax.set_xticks([1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335])
ax.set_xticklabels(list("EFMAMJJASOND"))
ax.set_ylabel("nivel (m)")
ax.set_title("Nivel del Amazonas en Leticia: años recientes frente a 1988–2022")
ax.legend(ncol=4, fontsize=7.5, loc="lower center")
fig.tight_layout()
2. Mínimos anuales, tendencia y periodos de retorno¶
mk = hidro.mann_kendall(minimos["valor"])
fig, ax = plt.subplots(figsize=(10, 3.6))
col = np.where(minimos["valor"] <= ph["umbral_estiaje_cm"], viz.ROJO, viz.TIERRA)
ax.bar(minimos.index, minimos["valor"] / 100, color=col)
t = np.array(minimos.index, dtype=float)
ax.plot(t, (np.median(minimos["valor"]) + mk["sen"] * (t - np.median(t))) / 100, color="k", lw=1, label="pendiente de Sen")
ax.axhline(ph["umbral_estiaje_cm"] / 100, color=viz.GRIS, ls="--", lw=1, label="6 m (ilustrativo)")
ax.set_ylabel("mínimo anual (m)")
ax.set_title("Nivel mínimo de aguas bajas por año (agosto–noviembre)")
ax.legend()
fig.tight_layout()
display(Markdown(f"Años con dato: **{mk['n']}**. Mann-Kendall: z = {mk['z']:.2f}, p = {mk['p']:.2f}; pendiente de Sen "
f"**{mk['sen']:.1f} cm/año** ({mk['sen']*10/100:.2f} m por década). Los cinco mínimos más bajos: "
+ ", ".join(f"{a} ({v/100:.2f} m)" for a, v in minimos['valor'].nsmallest(5).items()) + "."))
T = parametros()["periodos_retorno"]
sin24 = minimos.loc[minimos.index < 2023, "valor"].values
tab = pd.concat({"con 2023–2026": hidro.niveles_retorno_ic(minimos["valor"].values, T, minimos=True)["nivel"] / 100,
"solo hasta 2022": hidro.niveles_retorno_ic(sin24, T, minimos=True)["nivel"] / 100}, axis=1)
display(Markdown("**Nivel mínimo (m) que se alcanza en promedio una vez cada T años** (GEV ajustada a −mínimos):"))
display(tab.round(2))
p_sin = hidro.ajustar_gev(sin24, minimos=True)
from scipy import stats
p24 = stats.genextreme.sf(-m24, *p_sin)
cota = -(p_sin[1] + p_sin[2] / p_sin[0]) if p_sin[0] > 0 else -np.inf
texto = (f"retorno de **{1/p24:,.0f} años**".replace(",", ".") if p24 > 0 else
f"probabilidad **nula**: la distribución ajustada con los datos hasta 2022 tiene un mínimo posible de ≈ {cota/100:.2f} m")
display(Markdown(f"Con la estadística disponible hasta 2022, una vaciante como la de 2024 ({m24/100:.2f} m) tenía {texto}. "
"Al incluir 2023–2026 la curva se desplaza y lo que parecía imposible pasa a tener un periodo de retorno de pocas "
"décadas. Es la firma de un **régimen que cambia**, no de un evento aislado."))3. Días de aguas muy bajas por año¶
dias6 = hidro.dias_bajo_umbral(nivel, ph["umbral_estiaje_cm"])
dias4 = hidro.dias_bajo_umbral(nivel, ph["umbral_estiaje_critico_cm"])
fig, ax = plt.subplots(figsize=(10, 3.3))
ax.bar(dias6.index, dias6, color=viz.TIERRA, label="< 6 m")
ax.bar(dias4.index, dias4, color=viz.ROJO, label="< 4 m")
ax.set_ylabel("días por año")
ax.set_title("Días con el río por debajo de los umbrales de navegación (ilustrativos)")
ax.legend()
fig.tight_layout()
display(pd.DataFrame({"días < 6 m": dias6, "días < 4 m": dias4}).tail(8).T)
Los umbrales de 6 m y 4 m en la regla de Leticia son ilustrativos: la Capitanía de Puerto y las empresas de transporte usan calados y niveles propios. El indicador relevante es la tendencia: en 2023 y 2024 el río pasó muchas más semanas en aguas muy bajas que en cualquier año anterior del registro.
4. Duración de las aguas bajas (método de Santos de Lima et al.)¶
Santos de Lima et al. analizaron 90 estaciones de la Amazonía brasileña y midieron la sequía hidrológica por su duración: los días de cada año hidrológico (de diciembre a noviembre) en que el río está por debajo del P80 de la curva de duración, es decir, del nivel que el río iguala o supera el 80 % del tiempo. En las sequías de 2005, 2010 y 2016 ese periodo pasó de 100 días en la mediana de las estaciones, más de un mes por encima de lo habitual, y las noticias reportaron comunidades aisladas y transporte fluvial interrumpido Santos de Lima et al., 2024. El método no necesita umbrales de navegación, que para Leticia no son públicos, y hace comparable esta estación con las de Brasil.
dur, p80 = hidro.dias_bajo_referencia(nivel, ph["excedencia_aguas_bajas"], ph["mes_inicio_anio_hidrologico"])
completos = dur[dur["completo"]]
incompletos = dur[~dur["completo"] & (dur["cobertura"] >= 0.3)]
fig, ax = plt.subplots(figsize=(10, 3.4))
ax.bar(completos.index, completos["dias_bajo"], color=viz.ROJO, label="temporada de aguas bajas completa")
ax.bar(incompletos.index, incompletos["dias_bajo"], color="none", edgecolor=viz.TIERRA, hatch="///",
label="mínimo: temporada con días sin dato")
ax.axhline(73, color=viz.GRIS, ls="--", lw=1, label="73 días (20 % del año)")
ax.set_ylabel("días bajo el P80")
ax.set_title(f"Días por año hidrológico con el río por debajo del P80 ({p80 / 100:.2f} m en la regla de Leticia)")
ax.legend(fontsize=7.5, ncol=3, loc="upper left")
fig.tight_layout()
display(Markdown(f"P80 de la estación de Leticia: **{p80 / 100:.2f} m**. Años con la temporada de aguas bajas completa: "
f"**{len(completos)}** de {len(dur)}; en ellos la mediana es de {completos['dias_bajo'].median():.0f} días bajo el P80 y el "
f"periodo más largo es el de **{completos['dias_bajo'].idxmax()}**, con {completos['dias_bajo'].max():.0f} días."))
reciente = dur.loc[2019:].copy()
reciente["cobertura"] = (100 * reciente["cobertura"]).round(0)
display(reciente.rename(columns={"dias_bajo": "días bajo el P80", "cobertura": "cobertura de la temporada (%)",
"completo": "temporada completa"}).T)
Lectura. Con el umbral P80 la vaciante de 2024 fue la más larga de los años con registro completo: más de cuatro meses con el río por debajo de su nivel de referencia, del orden de las peores sequías que Santos de Lima et al. documentaron en Brasil. Para 2023 el conteo es solo un mínimo porque falta la mitad de los días de la temporada. Ese es el principal límite del indicador: la serie pública del IDEAM tiene vacíos justo en aguas bajas y solo unos pocos años tienen la temporada completa. Para calcular el P80 cada dato se pondera según cuántos años tienen dato ese día del calendario, de modo que la falta de datos en vaciante no suba el umbral. Completar y publicar la serie diaria es una condición para usar este indicador en una alerta de aislamiento.
5. Sequía meteorológica en Leticia (ERA5)¶
era = fuentes.clima_diario().loc["1979":] # era satelital: ERA5 es más confiable desde 1979
precip = era["precipitation_sum"]
spi3 = clima.spi(precip, 3, base=(1991, 2020))
spei3 = clima.balance_hidrico_spei(precip, era["et0_fao_evapotranspiration"], 3, base=(1991, 2020))
fig, ax = plt.subplots(figsize=(11, 3.4))
s = spei3["1980":]
ax.fill_between(s.index, 0, s, where=s < 0, color=viz.ROJO, alpha=0.7, label="déficit")
ax.fill_between(s.index, 0, s, where=s >= 0, color=viz.AZUL_RIO, alpha=0.6, label="exceso")
ax.axhline(-1.5, color="k", ls=":", lw=0.8)
ax.set_ylabel("SPEI-3")
ax.set_title("Balance hídrico estandarizado de 3 meses (lluvia − evapotranspiración) en Leticia")
ax.legend(loc="lower left")
fig.tight_layout()
peores = spei3.nsmallest(6)
display(Markdown("Meses con el SPEI-3 más bajo: " + ", ".join(f"{i:%m/%Y} ({v:.1f})" for i, v in peores.items()) + "."))
import spei as si
from scipy import stats
spi3_ref = si.spi(clima.suma_mensual(precip), dist=stats.gamma, timescale=3, fit_freq="MS")
comp = pd.concat({"leticia": spi3, "SPEI": spi3_ref}, axis=1).dropna()
dif = (comp["leticia"] - comp["SPEI"]).abs()
display(Markdown(f"**Control de calidad.** El SPI-3 calculado por el paquete de este libro coincide con el del paquete `SPEI` de Python: "
f"correlación {comp.corr().iloc[0, 1]:.2f} y diferencia absoluta mediana {dif.median():.2f} en {len(comp)} meses. "
"La diferencia se debe sobre todo a que aquí la distribución se ajusta con 1991–2020 y el paquete usa toda la serie."))El SPEI resta a la lluvia la evapotranspiración de referencia, de modo que también captura el efecto del calor: en 2023–2024 no solo llovió menos, sino que hizo mucho más calor y el agua se evaporó más rápido. Según el análisis de atribución de World Weather Attribution, el cambio climático hizo unas 30 veces más probable la sequía agrícola de 2023 en la cuenca, sobre todo por el aumento de temperatura Clarke et al., 2024. La lluvia sobre Leticia explica solo una parte de la vaciante: el nivel del río depende de la lluvia en toda la cuenca alta.
6. El Niño y las vaciantes¶
oni = fuentes.oni()
oni_jas = oni[oni.index.month == 8] # trimestre julio–agosto–septiembre
oni_jas.index = oni_jas.index.year
df = pd.concat({"minimo_m": minimos["valor"] / 100, "oni_jas": oni_jas}, axis=1).dropna()
r = df.corr().iloc[0, 1]
fig, ax = plt.subplots(figsize=(6.5, 4))
ax.scatter(df["oni_jas"], df["minimo_m"], c=df.index, cmap="viridis", s=30)
for a in (1998, 2010, 2015, 2023, 2024):
if a in df.index:
ax.annotate(str(a), (df.loc[a, "oni_jas"], df.loc[a, "minimo_m"]), fontsize=7, xytext=(3, 3), textcoords="offset points")
ax.set_xlabel("ONI (julio–septiembre)")
ax.set_ylabel("mínimo anual en Leticia (m)")
ax.set_title(f"El Niño y el mínimo del río (r = {r:.2f})")
fig.tight_layout()
display(Markdown(f"ONI más reciente: **{oni.iloc[-1]:+.2f} °C** ({oni.index[-1]:%m/%Y}, trimestre centrado)."))
Lectura. Los años de El Niño tienden a tener vaciantes más bajas, pero la relación es imperfecta: la sequía de 2005 y la de 2010 respondieron sobre todo al calentamiento del Atlántico Norte tropical, y la de 2023–2024 combinó El Niño, un Atlántico muy cálido y el calentamiento global Marengo et al., 2021Espinoza et al., 2024. Un El Niño fuerte en curso es, por tanto, una señal de alerta para la vaciante siguiente, no una certeza.
- Espinoza, J. C., Jimenez, J. C., Marengo, J. A., Schongart, J., Ronchail, J., Lavado-Casimiro, W., & Ribeiro, J. V. M. (2024). The new record of drought and warmth in the Amazon in 2023 related to regional and global climatic features. Scientific Reports, 14, 8107. 10.1038/s41598-024-58782-5
- Costa, F., & Marengo, J. (2023). Statement on the 2023 Amazon drought and its unforeseen consequences [Techreport]. Science Panel for the Amazon. https://eng-other-pub.sp-amazon.org/231208%20Statement%20on%20the%202023%20Amazon%20Drought%20(English).pdf
- IDEAM. (2024). Comunicado especial No. 100: Niveles bajos del río Amazonas. Instituto de Hidrología, Meteorología y Estudios Ambientales. https://ideam.gov.co/file-download/download/public/4697
- Santos de Lima, L., Silva, F. E. O. e, Dorio Anastácio, P. R., Kolanski, M. M. de P., Pires Pereira, A. C., Menezes, M. S. R., & others. (2024). Severe droughts reduce river navigability and isolate communities in the Brazilian Amazon. Communications Earth & Environment, 5, 370. 10.1038/s43247-024-01530-4
- Clarke, B., Barnes, C., Rodrigues, R., & others. (2024). Climate change, not El Niño, main driver of exceptional drought in highly vulnerable Amazon River Basin. World Weather Attribution. https://www.worldweatherattribution.org/climate-change-not-el-nino-main-driver-of-exceptional-drought-in-highly-vulnerable-amazon-river-basin/
- Marengo, J. A., Espinoza, J. C., Fu, R., Muñoz, J. C. J., Alves, L. M., Rocha, H. R., & Schöngart, J. (2021). Chapter 22: Long-term variability, extremes and changes in temperature and hydro meteorology in the Amazon region [Amazon Assessment Report 2021]. Science Panel for the Amazon. 10.55161/ZGJG8060