Carretera en la República Democrática Popular Lao. La escuela está a 200 metros. El tráfico ruge, el humo de la basura quemada cruza el camino y los niños caminan por él. ¿Qué respiran hoy? Sin datos locales, nadie lo sabe realmente.
En toda Asia Oriental y el Pacífico, 325 millones de niños[1]respira aire tóxico todos los días, a veces a niveles 10 veces superiores a los límites seguros. El daño suele ser silencioso: pulmones afectados, asma, pero en casos agudos puede provocar la pérdida de días escolares. Los futuros están en juego. A largo plazo, los sistemas de salud están bajo presión y las economías tienen que soportar los costos.
En muchos casos, los datos sobre la calidad del aire ni siquiera están disponibles.
Sin monitores. Sin pruebas. Sin protección.
En esta segunda parte de la serie de blogs.[2], investigamos los repositorios de datos donde se encuentran disponibles datos útiles sobre la calidad del aire, cómo importarlos y cómo ponerlos en funcionamiento en su computadora portátil. También desmitificaremos formatos de datos como GeoJSON, Parquet/GeoParquet, NetCDF/HDF5, COG, GRIB y Zarr para que pueda elegir la herramienta adecuada para el trabajo. Lo estamos preparando para que, en la siguiente parte, podamos explicar paso a paso cómo desarrollamos un modelo de calidad del aire de código abierto.
En los últimos años, ha habido un impulso significativo para generar y utilizar datos sobre la calidad del aire. Estos datos provienen de diferentes fuentes y su calidad varía en consecuencia. Algunos repositorios pueden ayudar a cuantificarlos: estaciones regulatorias para la verdad sobre el terreno, sensores comunitarios para comprender las variaciones hiperlocales, satélites para el contexto regional y reanálisis de modelos para estimaciones (Figura 2). La buena noticia: la mayor parte está abierta. La mejor noticia: el código para comenzar es relativamente corto.
Inicios rápidos del repositorio (con un mínimo de Python)
En esta sección pasamos de los conceptos a la práctica. A continuación, analizamos un conjunto de repositorios de código abierto de uso común y mostramos el código más pequeño posible que necesita para comenzar a extraer datos de cada uno de ellos. Todos los ejemplos asumen Python ≥3.10 con pip install según sea necesario.
Para cada repositorio numerado, encontrará:
una breve descripción de qué es la fuente de datos y cómo se mantiene, casos de uso típicos (cuando esta fuente es adecuada), cómo acceder a ella (claves API, notas de registro o URL directas) y un fragmento mínimo de código Python para extraer datos.
Imagine esto como una guía práctica donde puede hojear las descripciones, elegir la fuente que coincida con su problema y luego adaptar el código para conectarlo directamente a su propio análisis o canalización de modelos.
Consejo: mantenga los secretos fuera del código. Utilice variables de entorno para tokens (por ejemplo, exportar AIRNOW_API_KEY=…).
1) OpenAQ (mediciones terrestres globales; API abierta)
AbiertoAQ[3]es una plataforma de datos de código abierto que aloja datos globales sobre la calidad del aire, como PM2.5, PM10 y O3. Proporcionan datos sobre la calidad del aire al asociarse con varios socios gubernamentales, socios comunitarios y empresas de sensores de calidad del aire como Air Gradient, IQAir, entre otras.
Excelente para: desplazamientos rápidos a través del país, unidades/metadatos armonizados, canalizaciones reproducibles.
Regístrese para obtener una clave API de OpenAQ en https://explore.openaq.org. Después de registrarse, busque su clave API en su configuración. Utilice esta clave para autenticar solicitudes.
!pip instalar openaq pandas importar pandas como pd de pandas importar json_normalize de openaq importar OpenAQ importar fecha y hora desde fecha y hora importar timedelta importar geopandas como gpd solicitudes de importación importar hora importar json # siga el inicio rápido para obtener la clave de API https://docs.openaq.org/using-the-api/quick-start api_key = '' #ingrese su clave API antes de ejecutar el cliente = OpenAQ(api_key=api_key) #use la clave API generada anteriormente # obtenga las ubicaciones de todos los sensores en los códigos de países elegidos: https://docs.openaq.org/resources/countries ubicaciones = client.locations.list (paises_id=[68,111], límite = 1000) data_locations = ubicaciones.dict() df_sensors_country = json_normalize(data_locations ['resultados']) df_sensors_exploded = df_sensors_country.explode('sensores') df_sensors_exploded['sensor_id']=df_sensors_exploded['sensors'].apply(lambda x: x['id']) df_sensors_exploded['sensor_type']=df_sensors_exploded['sensors'].apply(lambda x: x['name']) df_sensors_pm25 = df_sensors_exploded[df_sensors_exploded['sensor_type'] == "pm25 µg/m³"] df_sensors_pm25 # revisa cada ubicación y extrae las mediciones horarias df_concat_aq_data=pd.DataFrame() to_date = datetime.datetime.now() from_date = to_date – timedelta(days=2) # obtener los datos de los últimos 2 días sensor_list = df_sensors_pm25.sensor_id para sensor_id en sensor_list[0:5]: print("—–") respuesta = client.measurements.list( sensors_id= sensor_id, datetime_from = from_date, datetime_to = to_date, limit = 500 ) print(respuesta) data_measurements = respuesta.dict() df_hourly_data = json_normalize(data_measurements ['resultados']) df_hourly_data["sensor_id"] = sensor_id if len(df_hourly_data) > 0: df_concat_aq_data=pd.concat([df_concat_aq_data,df_hourly_data]) df_concat_aq_data = df_concat_aq_data[["sensor_id","period.datetime_from.utc","period.datetime_to.utc","parameter.name","value"]] df_concat_aq_data
2) EPA AQS Data Mart (archivo regulatorio de EE. UU.; se necesita token)
El mercado de datos AQS de la EPA[4]es un archivo de datos regulatorios de EE. UU. que alberga mediciones de calidad del aire controladas desde miles de estaciones de monitoreo en todo el país. Proporciona registros a largo plazo de contaminantes criterio como PM₂․₅, PM₁₀, O₃, NO₂, SO₂ y CO, junto con metadatos detallados del sitio e indicadores de control de calidad, y se puede acceder gratuitamente a través de una API una vez que se registra y obtiene un token de acceso. También proporciona datos meteorológicos.
Excelente para: datos autorizados de control de calidad y control de calidad de EE. UU.
Regístrese para obtener una cuenta de AQS Data Mart en el sitio web de la EPA de EE. UU. en: https://aqs.epa.gov/aqsweb/documents/data_api.html
Cree un archivo .env en su entorno y agregue sus credenciales, incluido el correo electrónico de AQS y la clave de AQS.
# pip install solicita pandas importa os, solicitudes, pandas como pd AQS_EMAIL = os.getenv("AQS_EMAIL") AQS_KEY = os.getenv("AQS_KEY") url = "https://aqs.epa.gov/data/api/sampleData/byState" params = {"email": AQS_EMAIL, "key": AQS_KEY, "param": "88101", "b fecha":"20250101", "edate": "20250107", "estado": "06"} r = request.get(url, params=params, timeout=60) df = pd.json_normalize(r.json()["Datos"]) print(df[["nombre_estado","nombre_condado","fecha_local","medida_muestra","unidades_de_medida"]].head())
3) AirNow (índices en tiempo real de EE. UU.; clave API)
Aire ahora[5]es una plataforma del gobierno de EE. UU. que proporciona información del índice de calidad del aire (ICA) casi en tiempo real basada en datos de monitoreo regulatorio. Publica valores de AQI actuales y previstos para contaminantes como PM₂․₅ y O₃, junto con puntos de corte de categorías (“Bueno”, “Moderado”, etc.) que son fáciles de comunicar al público. Se puede acceder a los datos mediante programación a través de la API de AirNow una vez que se registre y obtenga una clave API.
Ideal para: incendios forestales y imágenes de AQI de cara al público.
Regístrese para obtener una cuenta API de AirNow a través del portal API de AirNow: https://docs.airnowapi.org/
Desde la página de inicio de sesión, seleccione "Solicitar una cuenta API de AirNow" y complete el formulario de registro con su correo electrónico y detalles básicos. Después de activar su cuenta, encontrará su clave API en su panel de API de AirNow; utilice esta clave para autenticar todas las llamadas a los servicios web de AirNow.
importar sistema operativo, solicitudes, pandas como pd API_KEY = os.getenv("AIRNOW_API_KEY") url = "https://www.airnowapi.org/aq/observation/latLong/current/" params = {"format":"application/json", "latitude": 37.7749, "longitude": -122.4194, "distance":25, "API_KEY": API_KEY} df = pd.DataFrame(requests.get(url, params=params, timeout=30).json()) print(df[["ParameterName", "AQI", "Category.Name", "DateObserved", "HourObserved"]])
4) Servicio de Monitoreo de la Atmósfera de Copernicus (CAMS; Atmosphere Data Store)
El Servicio de Vigilancia de la Atmósfera de Copernicus[6], implementado por el ECMWF para el programa Copernicus de la UE, proporciona reanálisis globales y pronósticos casi en tiempo real de la composición atmosférica. A través del Atmosphere Data Store (ADS), puede acceder a campos cuadriculados para aerosoles, gases reactivos (O₃, NO₂, etc.), gases de efecto invernadero y variables meteorológicas relacionadas, con registros de varios años adecuados tanto para aplicaciones operativas como de investigación. Todos los productos CAMS en ADS son abiertos y gratuitos, sujetos a la aceptación de la licencia Copernicus.
Excelente para: campos de antecedentes globales (aerosoles y gases traza), pronósticos y reanálisis.
Cómo registrarse y obtener acceso API
Vaya al almacén de datos de atmósfera: https://ads.atmosphere.copernicus.eu. Haga clic en Iniciar sesión/Registrarse en la esquina superior derecha y cree una cuenta (gratuita) de Copernicus/ECMWF. Después de confirmar su correo electrónico, inicie sesión y visite su página de perfil para encontrar su clave API de ADS (clave UID +). Siga las instrucciones de ADS “Cómo usar la API” para crear un archivo de configuración (normalmente ~/.cdsapirc) con: url: https://ads.atmosphere.copernicus.eu/api clave:: En la página web de cada conjunto de datos CAMS que desee utilizar, vaya a la pestaña Descargar datos y acepte la licencia en la parte inferior una vez; sólo entonces las solicitudes de API para ese conjunto de datos tendrán éxito.
Una vez configurado, puede utilizar el cliente cdsapi Python estándar para descargar mediante programación conjuntos de datos CAMS desde ADS.
# pip install cdsapi xarray cfgrib import cdsapi c = cdsapi.Client() # Ejemplo: reanálisis global CAMS (EAC4) columna total de ozono (ejemplo de juguete) c.retrieve( "cams-global-reanalysis-eac4", {"variable":"total_column_ozone","date":"2025-08-01/2025-08-02","time":["00:00","12:00"], "format":"grib"}, "cams_ozone.grib")
5) NASA Earthdata (LAADS DAAC / GES DISC; token/inicio de sesión)
Datos terrestres de la NASA[7]proporciona acceso de inicio de sesión unificado a una amplia gama de datos de ciencias de la Tierra, incluidos aerosoles satelitales y productos de gases traza que son cruciales para las aplicaciones de calidad del aire. Dos centros clave para la composición atmosférica son:
LAADS DAAC (Sistema de distribución y archivo de atmósfera y nivel 1 DAAC), que alberga MODIS, VIIRS y otros productos de instrumentos (por ejemplo, AOD, nubes, fuego, radiancia). GES DISC (Centro de servicios de información y datos de ciencias de la Tierra Goddard), que ofrece productos de modelos y satélites como el reanálisis de MERRA-2, OMI, TROPOMI y conjuntos de datos atmosféricos relacionados.
La mayoría de estos conjuntos de datos son de uso gratuito, pero requieren un inicio de sesión de NASA Earthdata; las descargas se autentican mediante autenticación básica HTTP (nombre de usuario/contraseña almacenado en .netrc) o mediante un token de acceso personal (PAT) en los encabezados de solicitud.
Ideal para: productos de gases traza MODIS/VIIRS AOD, MAIAC, TROPOMI.
Cómo registrarse y obtener acceso API/descarga:
Cree una cuenta de inicio de sesión de NASA Earthdata en:
https://urs.earthdata.nasa.gov Confirme su correo electrónico e inicie sesión en su perfil de Earthdata. Debajo de su perfil, genere un token de acceso personal (PAT). Guarde este token de forma segura; puede usarlo en scripts a través de un encabezado Autorización: Portador o en herramientas que admitan tokens Earthdata. Para descargas clásicas basadas en wget/curl, también puede crear un archivo ~/.netrc para almacenar su nombre de usuario y contraseña de Earthdata, por ejemplo: máquina urs.earthdata.nasa.gov contraseña de inicio de sesión
Luego configure los permisos de archivos como solo para usuarios (chmod 600 ~/.netrc) para que las herramientas de línea de comandos puedan autenticarse automáticamente.
Para productos LAADS DAAC, vaya a https://ladsweb.modaps.eosdis.nasa.gov, inicie sesión con sus credenciales de Earthdata y utilice la interfaz de búsqueda y descarga para crear URL de descarga; puede copiar los comandos wget/curl generados automáticamente en sus scripts. Para los conjuntos de datos GES DISC, comience desde https://disc.gsfc.nasa.gov, elija un conjunto de datos (por ejemplo, MERRA-2) y utilice las herramientas “Acceso a datos” o “Subconjunto/Obtener datos”. El sitio puede generar plantillas de script (Python, wget, etc.) que ya incluyen los puntos finales correctos para el acceso autenticado.
Una vez que su inicio de sesión y token de Earthdata estén configurados, LAADS DAAC y GES DISC se comportan como API HTTPS estándar: puede llamarlos desde Python (por ejemplo, con solicitudes, xarray + pydap/OPeNDAP o s3fs para depósitos en la nube) usando sus credenciales o token para descargas autenticadas y programables.
#Descargas a través de HTTPS con inicio de sesión de Earthdata. # solicitudes de instalación de pip solicitudes de importación url = "https://ladsweb.modaps.eosdis.nasa.gov/archive/allData/6/MCD19A2/2025/214/MCD19A2.A2025214.h21v09.006.2025xxxxxx.hdf" # Requiere una cookie token válida; recomiendo usar .netrc o request.Session() con auth # Consulte los documentos de la NASA para descargas basadas en tokens; aquí sólo ilustramos el patrón: # s = request.Session(); s.auth = (NOMBRE DE USUARIO, CONTRASEÑA); r = s.get(url)
6) Catálogos STAC (búsqueda de satélites mediante programación)
Catálogo de activos espaciotemporales (STAC)[8]es una especificación abierta para describir activos geoespaciales, como escenas de satélites, mosaicos y productos derivados, de una manera coherente y legible por máquina. En lugar de explorar manualmente los portales de descarga, consulta una API STAC con filtros como tiempo, cuadro delimitador, cobertura de nubes, plataforma (por ejemplo, Sentinel-2, Landsat-8, Sentinel-5P) o nivel de procesamiento, y obtiene elementos JSON con enlaces directos a COG, NetCDF, Zarr u otros activos.
Excelente para: descubrir y transmitir activos (COG/NetCDF) sin API personalizadas y funciona bien con Sentinel-5P, Landsat, Sentinel-2 y más.
Cómo registrarse y obtener acceso API:
El STAC en sí es sólo un estándar; El acceso depende de la API STAC específica que utilice:
Muchos catálogos STAC públicos (por ejemplo, puntos finales de demostración o investigación) están completamente abiertos y no requieren registro; puede acceder a su punto final /search directamente con HTTP POST/GET. Algunas plataformas en la nube que exponen STAC (por ejemplo, proveedores de nube grandes o comerciales) requieren que usted cree una cuenta gratuita y obtenga credenciales antes de poder leer los activos subyacentes (por ejemplo, blobs en S3/Blob Storage), aunque los metadatos de STAC estén abiertos.
Un patrón genérico que puedes describir es:
Elija un punto final de API STAC para los datos satelitales que le interesan (a menudo documentados como algo como https:///stac o…/stac/search). Si el proveedor requiere registrarse, cree una cuenta en su portal y obtenga la clave API o las credenciales de almacenamiento que recomiendan (puede ser un token, una URL de SAS o una función de acceso a la nube). Utilice una biblioteca cliente STAC en Python (por ejemplo, pystac-client) para buscar en el catálogo: # pip install pystac-client from pystac_client import Client api = Client.open("https://example.com/stac") search = api.search( collections=["sentinel-2-l2a"], bbox=[102.4, 17.8, 103.0, 18.2], # minx, miny, maxx, maxy datetime="2024-01-01/2024-01-31", query={"eo:cloud_cover": {"lt": 20}}, ) elementos = lista(search.get_items()) primer_elemento = elementos[0]activos = first_item.assets # por ejemplo, COG, bandas de control de calidad, metadatos. Para cada elemento STAC devuelto, siga los enlaces href del activo (a menudo URL HTTPS o URI de nube como s3://…) y léalos con la biblioteca adecuada (rasterio/xarray/zarr, etc.). Si se necesitan credenciales, configúrelas mediante variables de entorno o su SDK en la nube según las instrucciones del proveedor.
Una vez configurados, los catálogos STAC le brindan una manera uniforme y programática de buscar y recuperar datos satelitales entre diferentes proveedores, sin tener que reescribir su lógica de búsqueda cada vez que cambia de un archivo a otro.
# pip install pystac-client planetary-computer rasterio from pystac_client import Client from shapely.geometry import box, mapeo importar geopandas como gpd catalog = Client.open("https://earth-search.aws.element84.com/v1") aoi = mapeo(box(-0.3, 5.5, 0.3, 5.9)) # bbox around Accra search = catalog.search(collections=["sentinel-2-l2a"], intersects=aoi, limit=5) items = list(search.get_items()) para ello en items: print(it.id, list(it.assets.keys())[:5]) # por ejemplo, "B04", "B08", "SCL", "visual"
Es preferible utilizar STAC siempre que sea posible, ya que proporcionan metadatos limpios, activos optimizados para la nube y un filtrado sencillo por tiempo/espacio.
7) Google Earth Engine (GEE; creación rápida de prototipos a escala)
Motor de Google Earth[9]es una plataforma de análisis geoespacial basada en la nube que alberga un gran catálogo de conjuntos de datos satelitales, climáticos y de superficie terrestre (por ejemplo, MODIS, Landsat, Sentinel, reanálisis) y le permite procesarlos a escala sin administrar su propia infraestructura. Usted escribe scripts cortos en JavaScript o Python, y GEE maneja el trabajo pesado como el acceso a datos, el mosaico, la reproyección y el cálculo paralelo, lo que lo hace ideal para la creación rápida de prototipos, análisis exploratorios y enseñanza.
Sin embargo, GEE en sí no es de código abierto: es una plataforma cerrada y propietaria donde el código base subyacente no está disponible públicamente. Esto tiene implicaciones para los flujos de trabajo abiertos y reproducibles discutidos en el primer blog de Air for Tomorrow [agregar enlace]:
Excelente para: probar la fusión/reducción de escala en una ciudad/región utilizando conjuntos de datos a escala de petabytes.
Cómo registrarse y obtener acceso
Visite la página de registro de Earth Engine: https://earthengine.google.com. Inicie sesión con una cuenta de Google y complete el formulario de registro no comercial, describiendo su uso previsto (investigación, educación o proyectos personales no comerciales). Una vez que se apruebe su cuenta, podrá: utilizar el editor de código basado en navegador para escribir scripts de JavaScript Earth Engine; y habilite la API de Earth Engine en Google Cloud e instale el paquete Earthengine-api de Python (pip install Earthengine-api) para ejecutar flujos de trabajo desde cuadernos de Python. Cuando comparta su trabajo, considere exportar resultados intermedios clave (por ejemplo, GeoTIFF/COG, NetCDF/Zarr) y documentar sus pasos de procesamiento en código fuente abierto para que otros puedan recrear el análisis sin depender completamente de GEE.
Cuando se utiliza de esta manera, Earth Engine se convierte en un poderoso “laboratorio rápido” para probar ideas, que luego se pueden convertir en tuberías portátiles y completamente abiertas para la producción y la gestión a largo plazo.
# pip install Earthengine-api import ee ee.Initialize() # primera ejecución: ee.Authenticate() en una consola s5p = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2').select('NO2_column_number_density') .filterDate('2025-08-01', '2025-08-07').mean() print(s5p.getInfo()['bandas'][0]['id']) # La exportación y visualización se realizan dentro de GEE; puedes muestrear en una cuadrícula y luego .getDownloadURL()
8) HIMAWARI
Himawari-8 y Himawari-9 son satélites meteorológicos geoestacionarios operados por la Agencia Meteorológica de Japón (JMA). Su Advanced Himawari Imager (AHI) proporciona imágenes multibanda visible, infrarrojo cercano e infrarrojo sobre Asia oriental y el Pacífico central occidental, con escaneos de disco completo cada 10 minutos y una actualización aún más rápida en las regiones objetivo. Esta vista de alta cadencia es extremadamente útil para rastrear columnas de humo, polvo, erupciones volcánicas, tormentas convectivas y la evolución diurna de las nubes, exactamente los tipos de procesos que modulan la calidad del aire cerca de la superficie.
Excelente para: rastrear columnas de humo/neblina diurnas y eventos de incendio, generar AOD de alta frecuencia para llenar los vacíos de la órbita polar y un rápido conocimiento de la situación para ciudades en todo el sudeste y este de Asia (a través de los productos JAXA P-Tree L3).
Cómo acceder y registrarse
Opción A: abrir archivo a través de NOAA en AWS (no es necesario registrarse)
Explore la descripción del conjunto de datos en el Registro de datos abiertos de AWS: https://registry.opendata.aws/noaa-himawari/ Las imágenes Himawari-8 y Himawari-9 están alojadas en depósitos S3 públicos (s3://noaa-himawari8/ y s3://noaa-himawari9/). Dado que los depósitos son legibles en todo el mundo, puede enumerar o descargar archivos de forma anónima, por ejemplo:
aws s3 ls –no-sign-request s3://noaa-himawari9/
o acceder a objetos individuales a través de HTTPS (por ejemplo, https://noaa-himawari9.s3.amazonaws.com/…).
Para los flujos de trabajo de Python, puede usar bibliotecas como s3fs, fsspec, xarray o rasterio para transmitir datos directamente desde estos depósitos sin registro previo, teniendo en cuenta la guía de atribución de JMA/NOAA cuando publique resultados.
Opción B: JAXA Himawari Monitor / P-Tree (cuenta de investigación y educación)
Vaya al portal JAXA Himawari Monitor / P-Tree:
https://www.eorc.jaxa.jp/ptree/ Haga clic en Registro de usuario/Solicitud de cuenta y lea las “Precauciones” y los “Términos de uso”. El acceso a los datos está restringido a fines sin fines de lucro, como investigación y educación; los usuarios comerciales son dirigidos al Centro de Apoyo Empresarial Meteorológico de Japón. Envíe su dirección de correo electrónico en el formulario de solicitud de cuenta. Recibirá un correo electrónico de aceptación temporal y luego un enlace para completar su información de usuario. Después de la revisión manual, JAXA habilita su acceso y le notifica una vez que puede descargar los datos estándar de Himawari y los productos de parámetros geofísicos. Una vez aprobado, puede iniciar sesión para descargar datos Himawari archivados y casi en tiempo real a través de los servicios FTP/HTTP de P-Tree, siguiendo las pautas de JAXA sobre no redistribución y citación.
En la práctica, un patrón común es utilizar los depósitos NOAA/AWS para acceso abierto y programable a imágenes sin procesar, y los productos JAXA P-Tree cuando necesita parámetros de valor agregado (por ejemplo, propiedades de nubes o aerosoles) y está trabajando en proyectos educativos o de investigación sin fines de lucro.
# abre el archivo descargado !pip install xarray netCDF4 !pip install rasterio polars_h3 !pip install geopandas pykrige !pip install polars==1.25.2 !pip install dask[complete] rioxarray h3==3.7.7 !pip install h3ronpy==0.21.1 !pip install geowrangler # Himawari usando – JAXA Himawari Monitor / P-Tree # cree su cuenta aquí y use el nombre de usuario y contraseña enviados por correo electrónico – https://www.eorc.jaxa.jp/ptree/registration_top.html usuario = '' # ingrese el nombre de usuario contraseña = '' # ingrese la contraseña desde ftplib importar FTP desde pathlib importar ruta importar rasterio desde rasterio.transform importar desde_origin importar xarray como xr importar os importar matplotlib.pyplot como plt def get_himawari_ftp_past_2_days(usuario, contraseña): # Detalles de la conexión FTP ftp = FTP('ftp.ptree.jaxa.jp') ftp.login(usuario=usuario, contraseña=contraseña) # verifique el contenido del directorio: /pub/himawari/L2/ARP/031/ # detalles del directorio AOD aquí: https://www.eorc.jaxa.jp/ptree/documents/README_HimawariGeo_en.txt global_path= "/pub/himawari/L3/ARP/031/" directorios = global_path.strip("/").split("/") para directorio en directorios: ftp.cwd(directory) # Listar archivos en el directorio de destino date_month_files = ftp.nlst() # orden files desc date_month_files.sort(reverse=False) print("Archivos en el directorio de destino:", date_month_files) # obtener una lista de todos los meses/días dentro de la ruta "/pub/himawari/L3/ARP/031/" dentro de los últimos 2 meses limited_months_list = date_month_files[-2:] i=0 # para cada mes en la lista_limitada_meses, enumera todos los días dentro del mes en lista_mes_limitada: ftp.cwd(mes) archivos_día_fecha = ftp.nlst() archivos_día_fecha.sort(reverse=False) # combina cada elemento de la lista archivo_día_fecha con el mes: mes +"/" + archivo_día_fecha lista_días_combinados_mes_inter = [mes + "/" + archivo_día_fecha para archivo_día_fecha en archivos_día_fecha] si ==0: list_combined_days_month= list_combined_days_month_inter i=i+1 else: list_combined_days_month= list_combined_days_month + list_combined_days_month_inter ftp.cwd("..") # elimina todos los elementos que contienen diario o mensual de list_combined_days_month list_combined_days_month = [item for item in list_combined_days_month si 'diario' no está en el elemento y 'mensual' no está en el elemento] # obtener la lista de días que queremos descargar: en nuestro caso, los últimos 2 días – para NRT limited_list_combined_days_month=list_combined_days_month[-2:] para mes_día_fecha en limit_list_combined_days_month: #navegue al directorio correspondiente ftp.cwd(month_day_date) print(f"directory: {month_day_date}") # obtener la lista de archivos horarios dentro de cada directorio date_hour_files = ftp.nlst() !mkdir -p ./raw_data/{month_day_date} #para cada archivo horario en la lista para date_hour_file en date_hour_files: target_file_path=f"./raw_data/{month_day_date}/{date_hour_file}" # Descargar el objetivo os.path.exists(target_file_path): con open(target_file_path, "wb") como local_file: ftp.retrbinary(f"RETR {date_hour_file}", local_file.write) print(f"¡Descargado {date_hour_file} exitosamente!") else: print(f"El archivo ya existe: {date_hour_file}") print("————–") # go retroceder 2 pasos en el árbol ftp ftp.cwd("..") ftp.cwd("..") def transform_to_tif(): # obtener la lista de archivos en la carpeta raw_data Month_file_list = os.listdir("./raw_data") Month_file_list #ordenar Month_file_list Month_file_list.sort(reverse=False) nb_errors=0 # obtener la lista de cada carpeta diaria de los últimos 2 meses solo para archivo_mes en lista_archivos_mes[-2:]: print(f"—————————————–") print(f"Mes considerado: {archivo_mes}") lista_archivos_fechas=os.listdir(f"./raw_data/{archivo_meses}") lista_archivos_fechas.sort(reverse=False) # obtener lista de archivos para cada carpeta de día para archivo_fechas en lista_archivos_fechas[-2:]: print(f"—————————") print(f"Día considerado: {date_file}") hour_file_list=os.listdir(f"./raw_data/{month_file}/{date_file}") hour_file_list.sort(reverse=False) #procesar cada archivo horario en un archivo tif y transformarlo en un marco de datos procesado h3 para hour_file en hour_file_list: file_path = f"./raw_data/{month_file}/{date_file}/{hour_file}" hour_file_tif=hour_file.replace(".nc",".tif") salida_tif = f"./tif/{month_file}/{date_file}/{hour_file_tif}" if os.path.exists(output_tif): print(f"El archivo ya existe: {output_tif}") else: intente: dataset = xr.open_dataset(file_path, motor='netcdf4') excepto: #ir al siguiente archivo de hora print(f"error al abrir el archivo {hour_file} – omitiendo ") nb_errors=nb_errors+1 continuar # Acceder a una variable específica nombre_variable = list(dataset.data_vars.keys())[1]# Datos de producto AOT fusionados = conjunto de datos[nombre_variable] # Trazar datos (si son 2D y compatibles) plt.figure() data.plot() plt.title(f'{date_file}') plt.show() # Extraer metadatos (reemplazar con coordenadas reales de sus datos si están disponibles) lon = dataset['longitude'] if 'longitude' in dataset.coords else Ninguno lat = dataset['latitude'] if 'latitude' en dataset.coords else Ninguno # Manejar lat/lon faltante (el ejemplo asume una cuadrícula espaciada uniformemente) si lon es Ninguno o lat es Ninguno: lon_start, lon_step = -180, 0.05 # Valores de ejemplo lat_start, lat_step = 90, -0.05 # Valores de ejemplo lon = xr.DataArray(lon_start + lon_step * range(data.shape[-1]), dims=['x']) lat = xr.DataArray(lat_start + lat_step * range(data.shape[-2]), dims=['y']) # Definir la transformación afín para georreferenciar transform = from_origin(lon.min().item(), lat.max().item(), abs(lon[1]- lon[0]).elemento(), abs(latitud[0]- latitud[1]).item()) # Guardar en GeoTIFF !mkdir -p ./tif/{month_file}/{date_file} con rasterio.open( output_tif, 'w', driver='GTiff', height=data.shape[-2], width=data.shape[-1], count=1, # Número de bandas dtype=data.dtype.name, crs='EPSG:4326', # Sistema de referencia de coordenadas (p. ej., WGS84) transform=transform ) como dst: dst.write(data.values, 1) # Escribe los datos en la banda 1 print(f"Guardado {output_tif} exitosamente!") print(f"{nb_errors} error(s) ") get_himawari_ftp_past_2_days(usuario, contraseña) transform_to_tif()
9) NASA – FIRMS [Destacado especial]
Sistema de información sobre incendios para la gestión de recursos (FIRMS) de la NASA[10]proporciona información casi en tiempo real sobre incendios activos y anomalías térmicas detectadas por instrumentos como MODIS y VIIRS. Ofrece cobertura global con baja latencia (del orden de minutos a horas), proporcionando atributos como potencia radiativa del fuego, confianza y tiempo de adquisición. FIRMS se utiliza ampliamente para el seguimiento de incendios forestales, quemas agrícolas, gestión forestal y como aportación indirecta para la modelización de la calidad del aire y la dispersión del humo.
Excelente para: identificar puntos críticos de incendio que provocan picos de AQ, rastrear las fuentes de las columnas y la progresión de las líneas de incendio, monitorear los residuos de cultivos/quemas de bosques y desencadenar una respuesta rápida. Fácil acceso a través de CSV/GeoJSON/Shapefile, mosaicos de mapas/API, con transmisiones continuas de 24 a 72 h y archivos completos para análisis estacionales.
Cómo registrarse y obtener acceso API
Cree una cuenta gratuita de inicio de sesión de NASA Earthdata en:
https://urs.earthdata.nasa.gov Confirme su correo electrónico e inicie sesión con sus nuevas credenciales. Vaya al sitio de FIRMS que planea usar, por ejemplo: haga clic en Iniciar sesión (arriba a la derecha) y autentíquese con su nombre de usuario y contraseña de Earthdata. Una vez que haya iniciado sesión, podrá: personalizar las vistas de mapas y las opciones de descarga desde la interfaz web, y generar o utilizar URL de API/servicios web de FIRMS que respeten su sesión autenticada. Para el acceso mediante script, puede llamar a los puntos finales de descarga o servicio web de FIRMS (p. ej., GeoJSON, CSV) utilizando herramientas HTTP estándar (p. ej., curl, solicitudes en Python). Si un punto final requiere autenticación, proporcione sus credenciales de Earthdata a través de un archivo .netrc o cookies de sesión, como lo haría con otros servicios de Earthdata.
En la práctica, FIRMS es una forma conveniente de incorporar ubicaciones de incendios recientes a un flujo de trabajo de calidad del aire: puede obtener detecciones de incendios diarias u horarias para una región, convertirlas en un GeoDataFrame y luego intersecarlas con campos de viento, redes de población o redes de sensores para comprender los posibles impactos del humo.
#FIRMS !pip instalar geopandas rtree shapely importar pandas como pd importar geopandas como gpd de shapely.geometry importar punto importar numpy como np importar matplotlib.pyplot como plt importar rtree # obtener límites de Tailandia límites_país = gpd.read_file(f'https://github.com/wmgeolab/geoBoundaries/raw/fcccfab7523d4d5e55dfc7f63c166df918119fd1/releaseData/gbOpen/THA/ADM0/geoBoundaries-THA-ADM0.geojson') borders_country.plot() # Fuente de datos en tiempo real: https://firms.modaps.eosdis.nasa.gov/active_fire/ # Enlaces de los últimos 7 días: modis_7d_url= "https://firms.modaps.eosdis.nasa.gov/data/active_fire/modis-c6.1/csv/MODIS_C6_1_SouthEast_Asia_7d.csv" suomi_7d_url= "https://firms.modaps.eosdis.nasa.gov/data/active_fire/suomi-npp-viirs-c2/csv/SUOMI_VIIRS_C2_SouthEast_Asia_7d.csv" j1_7d_url= "https://firms.modaps.eosdis.nasa.gov/data/active_fire/noaa-20-viirs-c2/csv/J1_VIIRS_C2_SouthEast_Asia_7d.csv" j2_7d_url="https://firms.modaps.eosdis.nasa.gov/data/active_fire/noaa-21-viirs-c2/csv/J2_VIIRS_C2_SouthEast_Asia_7d.csv" urls = [modis_7d_url, suomi_7d_url, j1_7d_url, j2_7d_url] # Crear un vacío GeoDataFrame para almacenar los datos combinados gdf = gpd.GeoDataFrame() for url in urls: df = pd.read_csv(url) # Crear una columna de geometría a partir de latitud y longitud geometría = [Point(xy) for xy in zip(df['longitude'], df['latitude'])] gdf_temp = gpd.GeoDataFrame(df, crs="EPSG:4326", geometría=geometría) # Concatenar el GeoDataFrame temporal al GeoDataFrame principal gdf = pd.concat([gdf, gdf_temp], ignore_index=True) # Filtrar para mantener solo los incendios dentro de los límites del país gdf = gpd.sjoin(gdf, limites_country, how="inner", predicate="within") # Mostrar incendios en el mapa frp = gdf["frp"].astype(float) fig, ax = plt.subplots(figsize=(9,9)) borders_country.plot(ax=ax, facecolor="none", edgecolor="0.3", linewidth=0.8) gdf.plot(ax=ax, Markersize=frp, color="crimson", alpha=0.55) ax.set_title("Incendios dentro de los límites del país (tamaño de burbuja) = Potencia radiativa del fuego )") ax.set_axis_off() plt.show()
Tipos de datos que encontrará (y cómo leerlos correctamente)
El trabajo sobre la calidad del aire rara vez reside en un único y ordenado CSV. Por lo tanto, es útil saber qué tipos de archivos encontrará. Se moverá entre salidas de modelos multidimensionales (NetCDF/GRIB/Zarr), rásteres de satélite (COG/GeoTIFF), mediciones de puntos (CSV/Parquet/GeoParquet) y formatos compatibles con la web (JSON/GeoJSON), a menudo en el mismo cuaderno.
Esta sección es una guía de campo rápida sobre esos formatos y cómo abrirlos sin quedarse atascado.
No es necesario memorizar nada de esto, así que siéntete libre de hojear la lista una vez y luego regresar cuando encuentres una extensión de archivo desconocida.
NetCDF4 / HDF5 (matrices científicas de autodescripción): ampliamente utilizado para reanálisis, productos satelitales y modelos. Metadatos enriquecidos, multidimensionales (tiempo, nivel, latitud, longitud) Extensiones habituales: .nc, .nc4, .h5, .hdf5
Leer:
# pip install xarray netCDF4 import xarray as xr ds = xr.open_dataset("modis_aod_2025.nc") ds = ds.sel(time=slice("2025-08-01","2025-08-07")) print(ds) GeoTIFF optimizado para la nube (COG): formato ráster optimizado para solicitudes de rango HTTP (transmita solo lo que necesita). Común para imágenes de satélite y productos cuadriculados. Extensiones habituales: .tif, .tiff
Leer:
# pip install rasterio import rasterio con rasterio.open("https://example-bucket/no2_mean_2025.tif") as src: window = rasterio.windows.from_bounds(*(-0.3,5.5,0.3,5.9), src.transform) arr = src.read(1, window=window) JSON (anidado) y GeoJSON (características + geometría): Excelente para API y geoespacial liviano. GeoJSON usa WGS84 (EPSG:4326) de forma predeterminada. Extensiones habituales: json, .jsonl, .ndjson, .geojsonl, .ndgeojson
Leer:
# pip install geopandas import geopandas as gpd gdf = gpd.read_file("points.geojson") # columnas + geometría gdf = gdf.set_crs(4326) # asegura WGS84 GRIB2 (meteorología, resultados del modelo): compacto, en mosaico; utilizado frecuentemente por CAMS/ECMWF/NWP. Extensiones habituales: .grib2, .grb2, .grib, .grb. En la práctica, los proveedores de datos suelen añadir también sufijos de compresión, por ejemplo, .grib2.gz o .grb2.bz2.
Leer:
# pip install xarray cfgrib import xarray as xr ds = xr.open_dataset("cams_ozone.grib", motor="cfgrib") Parquet & GeoParquet (columnar, comprimido): ideal para tablas grandes: selección rápida de columnas, inserción de predicados, partición (por ejemplo, por fecha/ciudad). GeoParquet añade un estándar para geometrías. Extensiones habituales: .parquet, .parquet.gz
Leer/Escribir:
# pip install pandas pyarrow geopandas geoparquet import pandas como pd, geopandas como gpd df = pd.read_parquet("openaq_accra_2025.parquet") # solo columnas # Convertir un GeoDataFrame -> GeoParquet gdf = gpd.read_file("points.geojson") gdf.to_parquet("points.geoparquet") # conserva la geometría y CRS CSV/TSV (tablas de texto): simple, universal. Débil a gran escala (E/S lenta, sin esquema), sin geometría. Extensiones habituales: .csv, .tsv (a veces también .tab, menos común)
Leer:
# pip install pandas import pandas as pd df = pd.read_csv("measurements.csv", parse_dates=["datetime"], dtype={"site_id":"string"}) Zarr (fragmentado, nativo de la nube): ideal para análisis en la nube con lecturas paralelas (funciona muy bien con Dask). Extensión habitual: .zarr (a menudo un directorio/tienda que termina en .zarr; ocasionalmente empaquetado como .zarr.zip)
Leer:
# pip install xarray zarr s3fs import xarray as xr ds = xr.open_zarr("s3://bucket/cams_eac4_2025.zarr", consolidado=True)
Nota: Shapefile (vector heredado): funciona, pero frágil (muchos archivos, límite de campo de 10 caracteres). . Este es un formato heredado y es mejor utilizar alternativas como GeoPackage o GeoParquet.
Es importante elegir el formato de archivo geoespacial (o científico) correcto, ya que no es solo una decisión de almacenamiento, sino que afecta directamente la rapidez con la que se pueden leer los datos, la compatibilidad de las herramientas, la facilidad con la que se pueden compartir y la escalabilidad desde un flujo de trabajo de escritorio hasta el procesamiento nativo de la nube. La siguiente tabla (Tabla 1) proporciona una hoja de referencia práctica de “formato a tarea”: para cada necesidad común (desde volcados rápidos de API hasta matrices a escala de nube y mapeo web), enumera el formato más adecuado, las extensiones que normalmente encontrará y la razón principal por la que el formato es una buena opción. Se puede utilizar como punto de partida predeterminado al diseñar canalizaciones, publicar conjuntos de datos o seleccionar qué descargar de un repositorio externo.
.ndgeojson Sencillo; nativo de pilas web
Consejo: Una charla interesante sobre STAC y tipos de datos (especialmente GeoParquet): https://github.com/GSA/gtcop-wiki/wiki/June-2025:-GeoParquet,-Iceberg-and-Cloud%E2%80%90Native-Spatial-Data-Infrastructures
Ahora están disponibles múltiples catálogos STAC abiertos, incluidos puntos finales públicos para productos ópticos, de radar y atmosféricos (por ejemplo, imágenes Landsat y Sentinel a través de proveedores como Earth Search de Element 84 o Planetary Computer de Microsoft). STAC hace que sea mucho más fácil crear secuencias de comandos para "buscar y descargar todas las escenas para este polígono y rango de tiempo" e integrar diferentes conjuntos de datos en el mismo flujo de trabajo.
Conclusión: desde "dónde" se encuentran los datos hasta "cómo" se utilizan
Aire para el mañana: comenzamos con la pregunta “¿Qué respiran estos niños hoy?” Esta publicación proporciona un camino práctico y herramientas para ayudarlo a responder esta pregunta. Ahora sabe dónde residen los datos de calidad del aire libre, incluidas las redes regulatorias, los sensores comunitarios, las mediciones satelitales y los reanálisis. También comprende cuáles son esos archivos (GeoJSON, Parquet/GeoParquet, NetCDF/HDF5, COG, GRIB, Zarr) y cómo recuperarlos con fragmentos compactos y reproducibles. El objetivo va más allá de simplemente descargarlos; es hacer análisis defendibles, rápidos y compartibles que se mantengan en el futuro.
Es posible crear una imagen local creíble en horas, no en semanas. Desde los puntos críticos de incendio (Figura 2) hasta la exposición en rutas escolares (Figura 1), puede crear mapas de exposición (Figura 3).
A continuación: mostraríamos un modelo de calidad del aire real desarrollado por nosotros en la oficina nacional de UNICEF en la República Democrática Popular Lao con el equipo de datos fronterizos de UNICEF EAPRO. Pasaríamos por un modelo abierto de principio a fin. Cuando haya flujos de datos disponibles sobre la calidad del aire a nivel del suelo, cubriremos cómo se puede desarrollar la ingeniería de características, la corrección de sesgos, la normalización y un modelo con una superficie procesable que un regional pueda usar mañana por la mañana.
Colaboradores: Prithviraj Pramanik, AQAI; Hugo Ruiz Verástegui, Anthony Mockler, Judith Hanan, Frontier Data Lab; Risdianto Irawan, UNICEF EAPRO; Soheib Abdalla, Andrew Dunbrack, Oficina de UNICEF en la República Democrática Popular Lao; Halim Jun, Daniel Alvarez, Shane O'Connor, Oficina de Innovación de UNICEF;