Abrir en Colab

Estadísticas de mosquitos y cobertura terrestre#

Esta lección muestra cómo investigar los datos de GLOBE, calcular estadísticas y crear gráficos y mapas.

import pandas as pd
pd.set_option("display.max_columns", None)

import geopandas as gpd
import matplotlib.pyplot as plt
import seaborn as sns
import folium

Mosquitos#

Carguemos los datos directamente desde el enlace. No es necesario descargar ningún archivo en tu computadora.

mosquito = gpd.read_file(
    "https://github.com/geo-di-lab/emerge-lessons/raw/"
    "refs/heads/main/docs/data/globe_mosquito.zip"
)

mosquito.head()

Consulta la lista de columnas:

mosquito.info()

¿Cuántas filas contiene el conjunto de datos?

len(mosquito)

Entre 2018 y 2024 se registraron 43,012 contribuciones de ciencia participativa. Ahora veamos en cuántos países se enviaron datos.

len(mosquito['CountryCode'].unique())

Veamos los tipos de hábitats, o fuentes de agua, que registraron las personas participantes.

# Categorías generales de fuentes de agua
mosquito["WaterSourceType"].value_counts()

Estas son las categorías generales de fuentes de agua reportadas a NASA mediante GLOBE. La mayoría de los datos parece corresponder a recipientes artificiales. Veamos ahora algunas categorías más específicas de la otra columna:

# Categorías más específicas de fuentes de agua
mosquito["WaterSource"].value_counts()

Creemos un gráfico circular con la columna de categorías generales, WaterSourceType.

# Algunas opciones de paletas de colores
display(sns.color_palette(palette="Set2"))
display(sns.color_palette(palette="twilight_shifted"))
display(sns.color_palette(palette="tab20"))
# Gráfico circular de los tipos de fuentes de agua
types = (
    mosquito[["SiteId", "WaterSourceType"]]
    .groupby("WaterSourceType", as_index=False)
    .count()
)

plt.figure(figsize=(5, 5))
patches, texts = plt.pie(
    x=types["SiteId"],
    colors=sns.color_palette("Set2")
)

plt.title(
    "Observaciones de mosquitos de GLOBE: "
    "tipos generales de fuentes de agua"
)
plt.legend(
    patches,
    types["WaterSourceType"],
    loc="center left",
    bbox_to_anchor=(1, 0.5),
    frameon=False
)
plt.show()

¿Cuál es el promedio de larvas registradas en cada país?

mosquito_avg = (
    mosquito.groupby("CountryCode")["LarvaeCountProcessed"]
    .mean()
)

mosquito_avg

Creemos un mapa que muestre el promedio de larvas por país. Los límites generalizados de los países proceden de Esri, Garmin y la Agencia Central de Inteligencia de Estados Unidos (The World Factbook). Estos límites se han simplificado para que el procesamiento de datos y las visualizaciones se carguen más rápido.

Los códigos ISO alfa-3 proceden de la capa World Countries, elaborada por Esri, Garmin, la Agencia Central de Inteligencia de Estados Unidos (The World Factbook) y la Organización Internacional de Normalización (ISO).

countries = gpd.read_file(
    "https://github.com/geo-di-lab/emerge-lessons/raw/"
    "refs/heads/main/docs/data/world_countries_general.geojson"
).to_crs(epsg=4326)

mosquito_avg = countries.merge(
    mosquito_avg,
    left_on="iso3",
    right_on="CountryCode",
    how="left"
)
fig, ax = plt.subplots(figsize=(10, 4))

mosquito_avg.plot(
    column="LarvaeCountProcessed",
    cmap="viridis",
    legend=True,
    vmin=0,
    vmax=50,
    ax=ax,
    missing_kwds={
        "color": "lightgrey",
        "label": "Sin datos"
    }
)

plt.title(
    "Observaciones de mosquitos de GLOBE: "
    "promedio de larvas"
)
ax.axis("off")
plt.show()

Ahora crearemos un mapa interactivo que muestre el número total de observaciones de GLOBE por país.

mosquito_obs = (
    mosquito.groupby("CountryCode")
    .size()
    .reset_index(name="GLOBE_Observations")
)

mosquito_obs = countries.merge(
    mosquito_obs,
    left_on="iso3",
    right_on="CountryCode",
    how="left"
)
map = folium.Map(
    location=[0, 0],
    zoom_start=3,
    tiles="CartoDB positron"
)

# Crear un mapa con una escala de colores según el número
# de observaciones enviadas a GLOBE
folium.Choropleth(
    geo_data=mosquito_obs.to_json(),
    name="Observaciones de GLOBE",
    data=mosquito_obs,
    columns=["name", "GLOBE_Observations"],
    key_on="feature.properties.name",
    fill_color="YlGnBu",
    fill_opacity=0.7,
    bins=[1, 50, 100, 500, 1000, 5000, 10000, 20000],
    legend_name=(
        "Número de observaciones de GLOBE (2018–2024)"
    )
).add_to(map)

# Agregar información emergente al pasar el cursor
folium.GeoJson(
    geo_data=mosquito_obs.to_json(),
    data=mosquito_obs,
    key_on="feature.properties.name",
    tooltip=folium.features.GeoJsonTooltip(
        fields=["name", "GLOBE_Observations"],
        aliases=["País:", "Observaciones:"]
    ),
    style_function=lambda feature: {
        "color": "white",
        "weight": 1
    }
).add_to(map)

display(map)

Cobertura terrestre#

Carga los datos de cobertura terrestre directamente desde el enlace.

land_cover = gpd.read_file(
    "https://github.com/geo-di-lab/emerge-lessons/raw/"
    "refs/heads/main/docs/data/globe_land_cover.zip"
)

land_cover.head()
land_cover.info()
len(land_cover)

Se enviaron ligeramente más observaciones a GLOBE Land Cover, 50,766, que a Mosquito Habitat Mapper.

len(land_cover['CountryCode'].unique())

Una parte útil del conjunto de datos de cobertura terrestre son las clasificaciones MUC. MUC significa Modified UNESCO Classification y es un sistema que reúne distintos tipos de uso y cobertura del suelo.

# Consultar cuántos códigos MUC diferentes aparecen
len(land_cover["MucCode"].unique())
# Identificar el código MUC más común de cada país
muc = (
    land_cover.groupby("CountryCode")["MucDescription"]
    .apply(
        lambda x: (
            x.value_counts().idxmax()
            if not x.value_counts().empty
            else None
        )
    )
    .reset_index(name="MucDescription")
)

# Agregar la cantidad de observaciones del código MUC más común
muc["Count"] = (
    land_cover.groupby("CountryCode")["MucDescription"]
    .apply(lambda x: x.value_counts().max())
    .values
)

# Agregar el número total de observaciones de GLOBE
muc["GLOBE_Observations"] = (
    land_cover.groupby("CountryCode")
    .size()
    .values
)

muc
# Comprobar el cálculo mediante uno de los países
print(
    "Cantidad de observaciones del MUC más común:",
    len(
        land_cover[
            (land_cover["CountryCode"] == "USA")
            & (
                land_cover["MucDescription"]
                == "Herbaceous/Grassland, Short Grass"
            )
        ]
    )
)

print(
    "Total de observaciones de GLOBE:",
    len(
        land_cover[
            land_cover["CountryCode"] == "USA"
        ]
    )
)

La cantidad de filas coincide con la cifra del conjunto de datos anterior, por lo que sabemos que el cálculo se realizó correctamente.

muc = countries.merge(
    muc,
    left_on="iso3",
    right_on="CountryCode",
    how="left"
)

Algunas descripciones MUC son similares. Por ello, las agruparemos en categorías generales como Barren, Closed Forest, Cultivated y las demás categorías indicadas a continuación.

Estos valores permanecen en inglés porque deben coincidir exactamente con las descripciones del conjunto de datos.

muc_list = [
    "Barren",
    "Closed Forest",
    "Cultivated",
    "Herbaceous",
    "Open Water",
    "Trees",
    "Urban",
    "Wetlands",
    "Woodland"
]

for muc_code in muc_list:
    muc.loc[
        muc["MucDescription"].str.contains(
            muc_code,
            na=False
        ),
        "MucDescriptionShort"
    ] = muc_code
fig, ax = plt.subplots(figsize=(11, 5))

muc.plot(
    column="MucDescriptionShort",
    cmap="viridis",
    legend=True,
    ax=ax,
    missing_kwds={
        "color": "lightgrey",
        "label": "Sin datos"
    },
    legend_kwds={
        "loc": "lower left",
        "frameon": False
    }
)

plt.title(
    "Cobertura terrestre de GLOBE: "
    "códigos MUC más comunes"
)
plt.show()

Crearemos un mapa interactivo que muestre el número de observaciones de cobertura terrestre y los códigos MUC más comunes.

map = folium.Map(
    location=[0, 0],
    zoom_start=3,
    tiles="CartoDB positron"
)

# Crear un mapa con una escala de colores según el número
# de observaciones enviadas a GLOBE
folium.Choropleth(
    geo_data=muc.to_json(),
    name="Observaciones de GLOBE",
    data=muc,
    columns=["name", "GLOBE_Observations"],
    key_on="feature.properties.name",
    fill_color="YlGnBu",
    fill_opacity=0.7,
    bins=[
        1, 50, 100, 500, 1000,
        5000, 10000, 20000, 30200
    ],
    legend_name=(
        "Número de observaciones de GLOBE (2018–2024)"
    )
).add_to(map)

# Agregar información emergente al pasar el cursor
folium.GeoJson(
    geo_data=muc.to_json(),
    data=muc,
    key_on="feature.properties.name",
    tooltip=folium.features.GeoJsonTooltip(
        fields=[
            "name",
            "MucDescriptionShort",
            "GLOBE_Observations"
        ],
        aliases=[
            "País:",
            "MUC más común:",
            "Observaciones:"
        ]
    ),
    style_function=lambda feature: {
        "color": "white",
        "weight": 1
    }
).add_to(map)

display(map)