Quita los elefantes: pierdes el 67% de los escarabajos peloteros#

Paper: Importance of elephants for dung beetle biodiversity and ecosystem functionsScience, 2026-05-28

Open In Colab

📺 Pendiente — video corto saldrá en YouTube

El experimento más largo del mundo en escarabajos peloteros#

Mpala Research Centre, en Laikipia (Kenia). Sabana semiárida, 400–700 mm de lluvia al año, megafauna intacta: elefantes, jirafas, búfalos, cebras, kudúes, impalas, dik-diks. Desde 2009 hay 6 hectáreas valladas que separan zonas con todos los herbívoros, zonas sin megaherbívoros (elefante + jirafa), y zonas sin ningún herbívoro silvestre.

En esas parcelas, un equipo internacional capturó 9.114 escarabajos peloteros entre 2021 y 2023, secuenció 4.383 ejemplares (genética COI) y los clasificó en 179 especies probables. Después montaron una pregunta concreta: cuando un escarabajo se sube a una bola de heces, ¿de quién es esa heces? Para responderla pusieron baits de 9 herbívoros distintos y vieron quién aparece en cada bola. Eso reconstruye la red completa de quién come qué.

El resultado se puede resumir en una sola cifra. Veámosla.

# ==============================================================
# Configuración — modifica estos valores para explorar
# ==============================================================
COLOR_ELEFANTE = '#DC2626'      # Rojo alerta — la pieza clave
COLOR_OTROS = '#2563EB'         # Azul CaM
COLOR_MEGA = '#7C3AED'          # Violeta — megaherbívoros
COLOR_TOTAL = '#059669'         # Emerald — total exclusion
COLOR_GANADO = '#D97706'        # Amber — sitios con ganado
FUENTE = 'Fuente: Pringle et al. (2026), Science | Datos transcritos del Supplementary Information (Tablas S6, S13, S16)'

import os, urllib.request
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Cargar estilo CaM (local -> fallback GitHub raw)
BASE = 'https://raw.githubusercontent.com/Ciencia-a-Mordiscos/lab/main'
style_file = '../../cam.mplstyle'
if not os.path.exists(style_file):
    style_file = '/tmp/cam.mplstyle'
    if not os.path.exists(style_file):
        urllib.request.urlretrieve(f'{BASE}/cam.mplstyle', style_file)
plt.style.use(style_file)

# Datos (descarga automatica si no existen)
DATOS = ['herbivoros_dung.csv', 'exclusion_experimento.csv',
         'sitios_comparacion.csv', 'keystone_metrics.csv', 'red_centralidad.csv']
os.makedirs('datos', exist_ok=True)
for f in DATOS:
    path = f'datos/{f}'
    if not os.path.exists(path):
        urllib.request.urlretrieve(
            f'{BASE}/papers/2026-05-28-elefantes-escarabajos-keystone-mpala/datos/{f}',
            path)

herbivoros = pd.read_csv('datos/herbivoros_dung.csv')
exclusion = pd.read_csv('datos/exclusion_experimento.csv')
sitios = pd.read_csv('datos/sitios_comparacion.csv')
keystone = pd.read_csv('datos/keystone_metrics.csv')

os.makedirs('figuras', exist_ok=True)
print(f'{len(herbivoros)} actores en la red (8 herbivoros + humano)')
print(f'{len(exclusion)} tratamientos del experimento de exclusion (15 anos)')
print(f'{len(sitios)} sitios comparados (Mpala vs ganado)')
9 actores en la red (8 herbivoros + humano)
3 tratamientos del experimento de exclusion (15 anos)
3 sitios comparados (Mpala vs ganado)

El elefante cae aparte#

Cada herbívoro de Mpala atrae a un puñado de escarabajos. El elefante atrae al doble que el siguiente más conectado, y eso es solo el número crudo.

# Hero: comparacion elefante vs otros en metricas de la red trofica
# Eliminar humano del comparativo (el paper lo incluye pero no es animal silvestre)
df = herbivoros[herbivoros['herbivoro_es'] != 'Humano'].copy()
df = df.sort_values('beetle_richness', ascending=True)

fig, ax = plt.subplots(figsize=(13, 5.5))

colores = [COLOR_ELEFANTE if h == 'Elefante' else COLOR_OTROS for h in df['herbivoro_es']]
y = np.arange(len(df))
ax.barh(y, df['beetle_richness'], color=colores, alpha=0.85, edgecolor='white', linewidth=1)

for i, (val, name) in enumerate(zip(df['beetle_richness'], df['herbivoro_es'])):
    ax.text(val + 1.5, i, f'{int(val)}', va='center', fontsize=10,
            color=COLOR_ELEFANTE if name == 'Elefante' else '#444444',
            fontweight='bold')

ax.set_yticks(y)
ax.set_yticklabels(df['herbivoro_es'], fontsize=11)
for tick, name in zip(ax.get_yticklabels(), df['herbivoro_es']):
    if name == 'Elefante':
        tick.set_color(COLOR_ELEFANTE)
        tick.set_fontweight('bold')

ax.set_xlabel('Especies de escarabajos peloteros asociadas', fontsize=11)
ax.set_xlim(0, 100)
ax.set_title('A cuantas especies de escarabajos atrae cada herbivoro?',
             fontsize=14, fontweight='bold', pad=28)
ax.text(0.5, 1.03, 'Mpala, Kenia · 4.231 escarabajos identificados en heces de 9 herbivoros distintos (2021-2023)',
        transform=ax.transAxes, fontsize=10, color='#666666', ha='center')

# Anotacion elefante
elef_idx = df.reset_index(drop=True).index[df['herbivoro_es'].values == 'Elefante'][0]
ax.annotate('1,4x mas que la cebra (siguiente)',
            xy=(88, elef_idx), xytext=(60, elef_idx - 1.8),
            fontsize=11, fontweight='bold', color=COLOR_ELEFANTE,
            arrowprops=dict(arrowstyle='->', color=COLOR_ELEFANTE, lw=1.5))

fig.text(0.13, -0.03, FUENTE, fontsize=7.5, color='#999999', style='italic')
plt.savefig('figuras/red_centralidad.png', dpi=200, bbox_inches='tight')
plt.show()
../../_images/2105a79666add7c71a0ad3a76649abca4be2f02db7a54227860591c28a3c0fe5.png

El elefante atrae a 88 especies de escarabajos. La cebra, segunda en el podio, atrae a 63. La jirafa solo a 32, el búfalo a 30. En una métrica más fina (eigenvector centrality, que pondera con qué tan conectados están a su vez los escarabajos que llegan), el elefante saca 1,00 — el máximo posible. El resto promedia 0,61.

Lo que esto significa: si quitas a la cebra, los escarabajos que dependían de ella tienen alternativas razonables. Si quitas al elefante, una capa entera de la red se queda sin su nodo principal. La pregunta natural es: ¿qué pasa cuando eso ocurre de verdad?

El equipo lo probó.

15 años con elefantes, sin elefantes, sin nada#

El experimento UHURU comenzó en 2009. Tres tratamientos en parcelas vecinas:

  • Abierto: vallas que no excluyen a nadie. Funciona como control.

  • Sin megaherbívoros: vallas de 2,4 m con cables electrificados que bloquean a elefantes y jirafas, pero dejan pasar al resto.

  • Sin nada: vallas completas que excluyen a todos los herbívoros silvestres (de elefantes a dik-diks).

Después de 15 años, ¿qué tan distintas son las comunidades de escarabajos en cada parcela?

# Tres paneles: abundancia, riqueza, biomasa por tratamiento
fig, axes = plt.subplots(1, 3, figsize=(14, 4.8))

metricas = [
    ('abundancia', 'Abundancia (escarabajos)'),
    ('riqueza_sp', 'Riqueza (especies)'),
    ('biomasa_g', 'Biomasa (g)'),
]
colores_trat = {'Abierto': COLOR_OTROS, 'Sin megaherbívoros': COLOR_MEGA, 'Sin nada': COLOR_TOTAL}

for ax, (col, label) in zip(axes, metricas):
    vals = exclusion[col].values
    labels = exclusion['tratamiento_es'].values
    colors = [colores_trat[t] for t in labels]
    ax.bar(range(len(vals)), vals, color=colors, alpha=0.85,
           edgecolor='white', linewidth=1.5)
    for i, v in enumerate(vals):
        txt = f'{int(v)}' if v == int(v) else f'{v:.1f}'
        ax.text(i, v + max(vals) * 0.02, txt,
                ha='center', fontsize=10, fontweight='bold')
    ax.set_xticks(range(len(labels)))
    ax.set_xticklabels(labels, fontsize=9.5, rotation=0)
    ax.set_ylabel(label, fontsize=10)
    ax.set_ylim(0, max(vals) * 1.18)

# Caidas relativas anotadas en el panel de abundancia
ax = axes[0]
ax.annotate('', xy=(1, 2117), xytext=(0, 6429),
            arrowprops=dict(arrowstyle='->', color=COLOR_ELEFANTE, lw=1.8))
ax.text(0.5, 4400, '-67%', ha='center', fontsize=12, fontweight='bold', color=COLOR_ELEFANTE)
ax.annotate('', xy=(2, 1949), xytext=(1, 2117),
            arrowprops=dict(arrowstyle='->', color='#999999', lw=1.5))
ax.text(1.5, 2300, '-8% extra', ha='center', fontsize=10, fontweight='bold', color='#666666')

fig.suptitle('Quita los elefantes y se cae la mitad. Quita el resto y casi no cambia.',
             fontsize=14, fontweight='bold', y=1.04)
fig.text(0.5, 0.97, 'Experimento UHURU, 15 anos (2009-2023) · Tabla S6 del paper',
         fontsize=10, color='#666666', ha='center')
fig.text(0.13, -0.06, FUENTE, fontsize=7.5, color='#999999', style='italic')
plt.tight_layout()
plt.savefig('figuras/exclusion_experimento.png', dpi=200, bbox_inches='tight')
plt.show()
../../_images/88a78de73c5e03e42c903ee502bf6af6df15a8d3237351f8258b0a4947ce1491.png

La historia se repite donde el ganado desplazó a los elefantes#

Cerca de Mpala hay otros dos ranchos: Koija y Lekiji. En ambos, el ganado doméstico desplazó a los elefantes hace décadas. Los modelos GLMM del paper predicen, controlando por esfuerzo de muestreo, cuántos escarabajos aparecerían en cada sitio bajo las mismas condiciones.

Esto NO es un experimento — es una comparación observacional. El equipo no quitó elefantes en Koija ni en Lekiji. Lo único que se puede afirmar es que donde no hay elefantes, hay menos escarabajos, y que el patrón coincide con lo que el experimento controlado mostró dentro de Mpala.

# Comparacion sitios — barras con error bars del GLMM (SE en log-scale)
fig, ax = plt.subplots(figsize=(11, 5.5))

orden = ['Mpala', 'Koija', 'Lekiji']
s = sitios.set_index('sitio').loc[orden].reset_index()
vals = s['abundancia_predicha'].values
# Intervalos aproximados: exp(intercept +/- SE) para mostrar incertidumbre
lo = np.exp(s['intercept_glmm'].values - s['se_glmm'].values)
hi = np.exp(s['intercept_glmm'].values + s['se_glmm'].values)
err = np.array([vals - lo, hi - vals])

colores_sitios = [COLOR_OTROS, COLOR_GANADO, COLOR_GANADO]
x = np.arange(len(vals))
ax.bar(x, vals, color=colores_sitios, alpha=0.85, edgecolor='white', linewidth=1.5)
ax.errorbar(x, vals, yerr=err, fmt='_', color='#333333', capsize=8, capthick=1.5, markersize=0)

for i, v in enumerate(vals):
    ax.text(i, v + max(vals) * 0.04, f'{v:.0f}', ha='center', fontsize=11, fontweight='bold')

# Etiquetas tipo uso
tipos = {'Mpala': 'silvestre (con elefantes)',
         'Koija': 'ganado (sin elefantes)',
         'Lekiji': 'ganado (sin elefantes)'}
ax.set_xticks(x)
ax.set_xticklabels([f'{name}\n{tipos[name]}' for name in orden], fontsize=10)
ax.set_ylabel('Abundancia de escarabajos predicha por GLMM', fontsize=11)

ax.set_title('Mpala tiene 11x mas escarabajos que Lekiji',
             fontsize=14, fontweight='bold', pad=28)
ax.text(0.5, 1.03,
        'Predicciones del modelo controlando por esfuerzo de muestreo · Tabla S13',
        transform=ax.transAxes, fontsize=10, color='#666666', ha='center')

# Anotacion de la nota observacional
ax.text(0.98, 0.85, 'Observacional: el ganado no se manipulo experimentalmente',
        transform=ax.transAxes, fontsize=9, color='#666666', ha='right', style='italic')

ax.text(0.98, 0.02, 'barras: media +/- SE', transform=ax.transAxes,
        fontsize=8, color='#999999', ha='right', va='bottom', style='italic')

fig.text(0.13, -0.03, FUENTE, fontsize=7.5, color='#999999', style='italic')
plt.savefig('figuras/sitios_comparacion.png', dpi=200, bbox_inches='tight')
plt.show()
../../_images/28ddf3453b04b36ded9551b7bd7a6340bdfcfccda52d309ba967e4dab2a88d1a.png

¿Qué tan keystone es un elefante?#

En 1969, Robert Paine acuñó el concepto de keystone species: especies cuyo impacto sobre el ecosistema es desproporcionadamente grande respecto a su biomasa. Décadas después aparecieron formas de medirlo con número. Una es la fuerza de interacción por individuo (interaction strength per capita): cuánto efecto tiene UN individuo sobre la comunidad de escarabajos.

El paper la calculó para tres grupos: el elefante solo, los megaherbívoros como grupo (elefante + jirafa) y todos los ungulados de menos de 1.000 kg juntos (cebra, búfalo, kudú, impala, dik-dik). La diferencia es difícil de leer en escala lineal — necesita logaritmo.

# Distribucion de Si/Smax (community importance index) entre los 9 actores de la red
# El elefante es un outlier extremo — visualizar como anomalia
fig, ax = plt.subplots(figsize=(11, 5.2))

valores = herbivoros['si_smax'].values
nombres = herbivoros['herbivoro_es'].values
elef_val = float(herbivoros[herbivoros['herbivoro_es'] == 'Elefante']['si_smax'].iloc[0])
otros = valores[nombres != 'Elefante']
mediana_otros = np.median(otros)

bins = np.arange(0, 0.35, 0.025)
n, bins_used, _ = ax.hist(otros, bins=bins, color=COLOR_OTROS, alpha=0.45,
                          edgecolor=COLOR_OTROS, linewidth=0.8,
                          label='Resto de actores (n=8)')
y_max = max(n.max(), 3) * 1.4
ax.set_ylim(0, y_max)

ax.axvline(x=mediana_otros, color=COLOR_OTROS, linewidth=1.5,
           label=f'Mediana del resto (n=8 incluyendo humano y ganado) = {mediana_otros:.2f}')
ax.axvline(x=elef_val, color=COLOR_ELEFANTE, linewidth=2.8,
           label=f'Elefante = {elef_val:.2f}')

# Flecha bidireccional
ax.annotate('', xy=(elef_val, y_max * 0.55), xytext=(mediana_otros, y_max * 0.55),
            arrowprops=dict(arrowstyle='<->', color='#666666', lw=1.8))
ax.text((elef_val + mediana_otros) / 2, y_max * 0.62, '3,75x la mediana',
        ha='center', fontsize=11, fontweight='bold', color='#444444')

ax.set_xlabel('Si/Smax — importancia del actor en la comunidad de escarabajos',
              fontsize=11)
ax.set_ylabel('Numero de actores', fontsize=11)
ax.legend(fontsize=10, loc='upper right', framealpha=0.9)
ax.set_title('El elefante es el outlier extremo de la red',
             fontsize=14, fontweight='bold', pad=28)
ax.text(0.5, 1.03,
        'Metrica Si/Smax = importancia relativa del actor en la comunidad de escarabajos (cambio agregado escalado al maximo del sistema)',
        transform=ax.transAxes, fontsize=10, color='#666666', ha='center')

fig.text(0.13, -0.03, FUENTE, fontsize=7.5, color='#999999', style='italic')
plt.savefig('figuras/anomalia_keystone.png', dpi=200, bbox_inches='tight')
plt.show()
../../_images/20a9be22ca825d44222adb1189a6278aa1af1a0a5da382008005542a9e469193.png

Lo que los datos soportan#

Afirmación

¿Soportada?

Detalle

El elefante es la especie más conectada de la red

Atrae a 88 especies de escarabajos (degree); siguiente es la cebra con 63. Ratio 1,40×; 2,17× vs el promedio de otras especies (40,6). Eigenvector centrality 1,00 vs 0,61 del resto

Quitar elefantes reduce abundancia y riqueza de escarabajos

Tratamiento Sin megaherbívoros vs Abierto: −67% abundancia (GLMM β=−0,93, Z=−4,65, P<0,001), −22% riqueza, −51% biomasa

Quitar el resto de herbívoros tiene poco efecto adicional

Sin nada vs Sin megaherbívoros: solo −8% abundancia extra (Padj=0,55) y −15% riqueza extra (Padj=0,10) — no significativo

Donde el ganado desplazó elefantes, hay menos escarabajos

⚠️

Mpala 590 escarabajos predichos vs Koija 178 (−70%) vs Lekiji 54 (−91%). El paper lo enmarca como comparación observacional, no como prueba causal

Un elefante equivale a 1.594 ungulados pequeños en aporte de heces

Métrica community importance per capita: elefante 127,5 vs ungulados <1.000 kg 0,08. Ratio 1.594×

Limitaciones:

  • La métrica Si/Smax agrega 9 actores (incluyendo humano y ganado doméstico), lo cual es un n pequeño para hablar de distribuciones.

  • El experimento de exclusión está en Mpala (sabana semiárida de Laikipia). Generalizar a otras sabanas africanas requiere asumir que las redes tróficas son similares — el paper lo discute en §4.

  • Las parcelas UHURU miden 4 ha. Los elefantes recorren cientos de km² al año; ahí está el efecto medible, pero a escalas mayores podrían entrar dinámicas que las parcelas no capturan.

  • La comparación Mpala / Koija / Lekiji es observacional. No se manipuló el ganado; lo que se puede afirmar es la asociación, no el mecanismo causal específico.

Ahora tú#

Cambia un valor de la configuración y vuelve a ejecutar. Tres preguntas para explorar:

  1. ¿Cuánto se mueven los rangos si descartas al humano de la red? El humano aparece en el paper como uno de los 9 baits probados — abre herbivoros_dung.csv y compara los rangos de centralidad incluyendo/excluyendo al humano.

  2. ¿Qué tan correlacionada está la masa corporal con la centralidad? Calcula la correlación de Spearman entre masa_kg y beetle_richness para los 7 herbívoros silvestres. ¿El rango captura toda la historia o el elefante distorsiona el resultado?

  3. ¿Cuál es el efecto marginal de cada especie removida? Para cada herbívoro, mira su Si/Smax en herbivoros_dung.csv. Si lo quitas, pierdes esa proporción de la comunidad de escarabajos. ¿Qué pasa si los sumas todos? ¿La suma da 1 o más? ¿Por qué?

# --- EXPERIMENTA AQUI ---
# Pregunta 2: que tan correlacionada esta la masa corporal con la centralidad de la red?
from scipy import stats

silvestres = herbivoros[~herbivoros['herbivoro_es'].isin(['Humano', 'Ganado'])].copy()

# Spearman (no asume normalidad — apropiado para n=8)
rho, p = stats.spearmanr(silvestres['masa_kg'], silvestres['beetle_richness'])
print(f'Correlacion masa corporal vs riqueza de escarabajos (n={len(silvestres)})')
print(f'  Spearman rho = {rho:.2f}, P = {p:.3f}')

# Repetir excluyendo elefante para ver cuanto pesa el outlier
sin_elef = silvestres[silvestres['herbivoro_es'] != 'Elefante']
rho2, p2 = stats.spearmanr(sin_elef['masa_kg'], sin_elef['beetle_richness'])
print(f'\nLo mismo SIN el elefante (n={len(sin_elef)})')
print(f'  Spearman rho = {rho2:.2f}, P = {p2:.3f}')

print('\nLectura: con n=7 la correlacion masa-centralidad es practicamente nula (rho=0,04, p=0,94).')
print('La masa corporal por si sola NO explica la centralidad: la jirafa (800 kg) y el bufalo (646 kg)')
print('tienen baja centralidad. Lo distintivo del elefante no es solo su masa — es el unico que come')
print('arbustos enteros y procesa volumenes de heces muy superiores.')
Correlacion masa corporal vs riqueza de escarabajos (n=7)
  Spearman rho = 0.04, P = 0.939

Lo mismo SIN el elefante (n=6)
  Spearman rho = -0.54, P = 0.266

Lectura: con n=7 la correlacion masa-centralidad es practicamente nula (rho=0,04, p=0,94).
La masa corporal por si sola NO explica la centralidad: la jirafa (800 kg) y el bufalo (646 kg)
tienen baja centralidad. Lo distintivo del elefante no es solo su masa — es el unico que come
arbustos enteros y procesa volumenes de heces muy superiores.

Fuentes#

Paper: Importance of elephants for dung beetle biodiversity and ecosystem functions
Science, 2026-05-28

Supplementary Material: Supplementary Materials for: Importance of elephants for dung beetle biodiversity and ecosystem functions
Tablas y figuras suplementarias del paper (S1–S16, Figs S1–S12)

Referencias citadas:

11 afirmaciones del notebook verificadas contra estas fuentes


Datos: Transcritos del Supplementary Information del paper (Tablas S6, S13, S16) y de los datos de centralidad de red (§2.4d). El dataset Dryad asociado al paper estaba embargado al momento de generar este notebook.

Licencia: Datos derivados del paper publicado en Science (2026-05-28). Las transcripciones a CSV son nuestras; cualquier discrepancia con el SI original es nuestra responsabilidad. Código bajo MIT.

Repo: github.com/Ciencia-a-Mordiscos/lab