Interfaces de programación de aplicaciones (API)#

Abrir en Colab

Trabajo previo#

Lecturas#

Severance, D. C. R. (2016). Chapter 13: Python and Web Services en Python for Everybody: Exploring Data in Python 3 (S. Blumenberg & E. Hauser, Eds.). CreateSpace Independent Publishing Platform. https://www.py4e.com/html3/13-web

Otros recursos#

Documentación oficial sobre el módulo requests de Python
Requests: HTTP for Humans

Lista de API públicas gratuitas
public-apis/public-apis: A collective list of free APIs

Visualizador de JSON en línea
JSON Viewer

Introducción#

Una API (del inglés, Application Programming Interface, en español, Interfaz de Programación de Aplicaciones) es un conjunto de protocolos, herramientas y definiciones que permiten la comunicación y el intercambio de datos entre programas. Puede decirse que una API establece un “contrato” de la forma en la que pueden “hablarse” los programas, al definir lo que pueden solicitar, lo que pueden responder y los formatos en los que pueden realizar este “diálogo”.

Las API de tipo REST (del inglés, Representational State Transfer, en español, Transferencia de Estado Representacional) implementan esta comunicación mediante solicitudes (requests) y respuestas (responses) del protocolo HTTP en formatos como XML y JSON.

En este capítulo, se estudia el acceso a las API de tipo REST mediante el lenguaje de programación Python.

El protocolo HTTP#

El HTTP (del inglés, Hypertext Transfer Protocol, en español, Protocolo de Transferencia de Hipertexto) es el protocolo de comunicación que permite la transferencia de información a través de la Web. Es un protocolo sin estado, lo que significa que cada solicitud se maneja como una transacción independiente que no tiene relación con ninguna solicitud anterior, de modo que la comunicación se compone de pares independientes de solicitudes y respuestas. Al programa que realiza la solicitud se le denomina cliente y al que la responde se le llama servidor.

Métodos de solicitud#

HTTP define un conjunto de métodos de solicitud para indicar el tipo de solicitud que un cliente desea realizar a un servidor.

Los siguientes son algunos de los métodos de solicitud HTTP:

  • GET: pide datos al servidor.

  • POST: envía datos al servidor.

  • DELETE: elimina datos de un servidor.

Así, por ejemplo, si un cliente desea realizar una consulta de datos, debe enviar al servidor una solicitud de tipo GET. Por otra parte, si desea agregar o modificar datos, debe enviar una solicitud de tipo POST.

Códigos de estado de respuesta#

Al atender la solicitud de datos de un cliente, el servidor envía una respuesta con un código de estado y los datos solicitados (si logra atender la solicitud). Los códigos de estado de respuesta de HTTP indican si se ha completado satisfactoriamente la solicitud. Estos códigos se agrupan en cinco clases:

  • Códigos del 100 al 199: respuestas informativas.

  • Códigos del 200 al 299: respuestas satisfactorias.

  • Códigos del 300 al 399: redireccionamientos.

  • Códigos del 400 al 499: errores del cliente.

  • Códigos del 500 al 599: errores del servidor.

Por ejemplo, una respuesta con el código 200 (OK) significa que la solicitud tuvo éxito. Por otra parte, el código 404 (Not found) indica que el servidor no pudo encontrar el recurso solicitado.

Formatos de intercambio de datos#

Existen dos formatos de uso común para intercambiar datos a través de la Web; XML y JSON. XML es más adecuado para documentos completos (ej. documentos de texto, hojas de cálculo, diagramas, metadatos), mientras que JSON se utiliza para elementos de datos más específicos, representados en estructuras similares a las listas y diccionarios de Python.

XML#

El XML (del inglés, Extensible Markup Language, en español, Lenguaje de Marcado Extensible) es un metalenguaje que permite definir lenguajes de marcas. Su formato, basado en texto, es legible tanto para computadoras como para personas. Es un estándar del World Wide Web Consortium (W3C), una organización internacional encargada de mantener estándares para la Web tales como HTML, CSS, DOM y SVG, entre otros. La primera versión de XML se publicó en 1998.

El siguiente en un ejemplo de un documento XML:

<?xml version="1.0" encoding="UTF-8" ?>
<persona>
  <nombre>Juan Pérez</nombre>
  <telefono tipo="intl">
    +1 734 303 4456
  </telefono>
  <email oculto="sí" />
</persona>

Cada par de etiquetas de apertura y cierre (ej. <persona> y </persona>) representa un elemento o nodo. Cada elemento puede tener texto, atributos (ej. tipo, oculto) y otros elementos anidados. Si un elemento XML está vacío (es decir, no tiene contenido), puede representarse mediante una etiqueta de autocierre (ej. <email />).

Python proporciona diversas herramientas para procesar datos XML en el paquete xml.

JSON#

JSON (del inglés, JavaScript Object Notation, en español, Notación de Objetos de JavaScript) es un formato de texto sencillo para el intercambio de datos. Proviene de la sintaxis del lenguaje de programación JavaScript para representar arreglos y objetos, la cual está influenciada por la sintaxis de Python para representar listas y diccionarios. Por este motivo, la representación de conjuntos de datos en JSON es prácticamente idéntica a la de Python. JSON fue descrito por Douglas Crockford a inicios de la década de 2000. Es un estándar de la Organización Internacional de Estándares (ISO) desde 2017.

El siguiente en un ejemplo de sintaxis JSON equivalente a la de XML presentada anteriormente:

{
  "nombre" : "Juan Pérez",
  "telefono" : {
    "tipo" : "intl",
    "numero" : "+1 734 303 4456"
   },
   "email" : {
     "oculto" : "sí"
   }
}

Pueden notarse algunas diferencias con XML. En primer lugar, mientras que en XML pueden añadirse atributos como tipo a etiquetas como telefono, en JSON solamente se usan pares "llave": valor. También ha desaparecido el elemento persona de XML y se ha sustituido por una llave de apertura ({) y otra de cierre (}).

En general, las estructuras de datos representadas mediante JSON son más sencillas que las representadas en XML, debido a que JSON tiene menos capacidades que XML. Sin embargo, JSON tiene la ventaja de que mapea directamente a combinaciones de diccionarios y listas. Y como prácticamente todos los lenguajes de programación tienen algo equivalente a los diccionarios y listas de Python, JSON es un formato muy natural para que dos programas intercambien datos en cualquier lenguaje de programación.

JSON se ha posicionado como el formato preferido para el intercambio de datos entre aplicaciones, debido a su relativa simplicidad en comparación con XML.

El paquete json de Python proporciona varias funciones para manejar datos en formato JSON.

El paquete requests#

El paquete requests de Python es una biblioteca ampliamente utilizada para hacer solicitudes HTTP. Se emplea para interactuar con API, descargar archivos y, en general, hacer solicitudes web.

Métodos principales#

get()#

El método requests.get() se utiliza para enviar una solicitud HTTP GET a una URL (i.e. una dirección web). Su sintaxis básica es:

requests.get(url, params=None, headers=None)

Principales argumentos de entrada:

  • url (obligatorio): dirección web a la que se envía la solicitud.

  • params (opcional, por defecto None): diccionario de Python que se utiliza para adjuntar parámetros a una solicitud GET (ej. filtros para una consulta).

  • headers (opcional, por defecto None): diccionario de Python con información adicional para establer el contexto necesario para procesar la solicitud y generar una respuesta adecuada. Algunos headers (encabezados) comunes son:

    • User-Agent: identifica el tipo de cliente que realiza la solicitud. Por ejemplo:
      'User-Agent': 'mi-aplicacion/1.0.0'

    • Accept: indica al servidor los formatos de datos que el cliente puede procesar. Por ejemplo:
      'Accept': 'application/json'

    • Authorization: envía credenciales o tokens para autenticación. Por ejemplo:
      'Authorization': 'Bearer <token_de_acceso>'

requests.get() retorna un objeto de la clase requests.Response, el cual contiene la respuesta a la solicitud HTTP.

json()#

El método requests.json() retorna el contenido de una respuesta HTTP (un objeto requests.Response) en formato JSON. Su sintaxis básica es:

datos = respuesta.json()

Ejemplo de uso#

import requests

# Solicitud GET
respuesta = requests.get('https://api.github.com/users/octocat')

# Verificación de la respuesta
if respuesta.status_code == 200:
    # La solicitud fue exitosa
    
    # La respuesta se convierte a formato JSON y se despliega (luego de este bloque de código)
    datos = respuesta.json()
    print(datos)
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")
{'login': 'octocat', 'id': 583231, 'node_id': 'MDQ6VXNlcjU4MzIzMQ==', 'avatar_url': 'https://avatars.githubusercontent.com/u/583231?v=4', 'gravatar_id': '', 'url': 'https://api.github.com/users/octocat', 'html_url': 'https://github.com/octocat', 'followers_url': 'https://api.github.com/users/octocat/followers', 'following_url': 'https://api.github.com/users/octocat/following{/other_user}', 'gists_url': 'https://api.github.com/users/octocat/gists{/gist_id}', 'starred_url': 'https://api.github.com/users/octocat/starred{/owner}{/repo}', 'subscriptions_url': 'https://api.github.com/users/octocat/subscriptions', 'organizations_url': 'https://api.github.com/users/octocat/orgs', 'repos_url': 'https://api.github.com/users/octocat/repos', 'events_url': 'https://api.github.com/users/octocat/events{/privacy}', 'received_events_url': 'https://api.github.com/users/octocat/received_events', 'type': 'User', 'site_admin': False, 'name': 'The Octocat', 'company': '@github', 'blog': 'https://github.blog', 'location': 'San Francisco', 'email': None, 'hireable': None, 'bio': None, 'twitter_username': None, 'public_repos': 8, 'public_gists': 8, 'followers': 15059, 'following': 9, 'created_at': '2011-01-25T18:44:36Z', 'updated_at': '2024-09-22T11:25:27Z'}

El paquete json#

El paquete json proporciona funciones para trabajar con datos en formato JSON. Estos métodos convierten estructuras de datos de Python (como diccionarios y listas) en cadenas JSON y viceversa.

Métodos principales#

Los métodos principales para serializar (convertir objetos de Python a JSON) son dumps() y dump().

dumps()#

El método json.dumps() convierte un objeto de Python en una cadena JSON formateada. En otras palabras, serializa objetos Python. El formateo de la cadena (ej. uso de sangrías) puede ayudar a mejorar la legibilidad de los datos. Su sintaxis básica es:

dumps(obj, ensure_ascii=True, indent=None)

Principales argumentos de entrada:

  • obj (obligatorio): objeto Python que se desea convertir a JSON. Puede ser una lista, un diccionario, una hilera de texto, un número, etc.

  • ensure_ascii (opcional, por defecto True): si es False, se permiten caracteres Unicode en la salida.

  • indent (opcional, por defecto None): si se especifica un número entero, la salida se formatea con ese número de espacios para sangría, haciendo el JSON más legible.

dump()#

El método json.dump() escribe un objeto de Python en un archivo como una representación JSON. Su sintaxis básica es:

dump(obj, fp, ensure_ascii=True, indent=None)

Principales argumentos de entrada:

  • obj (obligatorio): objeto Python que se desea serializar.

  • fp (obligatorio): objeto tipo file (archivo) abierto en modo de escritura.

  • ensure_ascii (opcional, por defecto True): si es False, se permiten caracteres Unicode en la salida.

  • indent (opcional, por defecto None): si se especifica un número entero, la salida se formatea con ese número de espacios para sangría, haciendo el JSON más legible.

Ejemplo de uso#

import requests
import json

# Solicitud GET
respuesta = requests.get('https://api.github.com/users/octocat')

# Verificación de la respuesta
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados
    datos = respuesta.json()

    # Formateo de datos JSON, para que sean más legibles
    json_formateado = json.dumps(datos, indent=4, ensure_ascii=False)
    # Despliegue de datos JSON formateados (luego de este bloque de código)
    print(json_formateado)

    # Almacenamiento de datos JSON en un archivo llamado "datos.json"
    with open('datos.json', 'w', encoding='utf-8') as archivo:
        json.dump(datos, archivo, indent=4, ensure_ascii=False)
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")
{
    "login": "octocat",
    "id": 583231,
    "node_id": "MDQ6VXNlcjU4MzIzMQ==",
    "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/octocat",
    "html_url": "https://github.com/octocat",
    "followers_url": "https://api.github.com/users/octocat/followers",
    "following_url": "https://api.github.com/users/octocat/following{/other_user}",
    "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
    "organizations_url": "https://api.github.com/users/octocat/orgs",
    "repos_url": "https://api.github.com/users/octocat/repos",
    "events_url": "https://api.github.com/users/octocat/events{/privacy}",
    "received_events_url": "https://api.github.com/users/octocat/received_events",
    "type": "User",
    "site_admin": false,
    "name": "The Octocat",
    "company": "@github",
    "blog": "https://github.blog",
    "location": "San Francisco",
    "email": null,
    "hireable": null,
    "bio": null,
    "twitter_username": null,
    "public_repos": 8,
    "public_gists": 8,
    "followers": 15059,
    "following": 9,
    "created_at": "2011-01-25T18:44:36Z",
    "updated_at": "2024-09-22T11:25:27Z"
}

URL base y endpoints#

Toda API tiene un URL común que funciona como punto de partida para todas las solicitudes. A este URL se le denomina URL base. Los endpoints son extensiones del URL base que permiten acceder a recursos específicos.

Por ejemplo, la API de GitHub tiene el siguiente URL base:

https://api.github.com/

Algunos de sus endpoints son:

https://api.github.com/users/: datos de usuarios
https://api.github.com/repos/: datos de repositorios
https://api.github.com/orgs/: datos de organizaciones
https://api.github.com/licenses/: datos de licencias

Ejemplos de uso de API#

En esta sección se presentan varios ejemplos de uso de API mediante el módulo requests del lenguaje de programación Python.

GitHub REST API#

GitHub es una plataforma de desarrollo colaborativo que utiliza el sistema de control de versiones Git, permitiendo a los desarrolladores alojar, revisar y gestionar código de manera eficiente. La GitHub REST API ofrece a los desarrolladores la capacidad de interactuar programáticamente con GitHub, facilitando la automatización de tareas y la integración de sus servicios en otras aplicaciones.

De acuerdo con su documentación, el URL base del GitHub REST API es:

https://api.github.com/

Algunos de sus endpoints son:

https://api.github.com/users/: datos de usuarios
https://api.github.com/repos/: datos de repositorios
https://api.github.com/orgs/: datos de organizaciones
https://api.github.com/licenses/: datos de licencias

Seguidamente, se muestran algunos ejemplos de uso de esta API.

Consulta de datos de usuarios#

Documentación
REST API endpoints for users - GitHub Docs

import requests
import json

# Nombre del usuario
usuario = 'octocat'
# URL
url = f'https://api.github.com/users/{usuario}'

# Solicitud GET
respuesta = requests.get(url)

# Verificación de la respuesta
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados
    datos_usuario = respuesta.json()

    # Se imprimen elementos de datos específicos
    print(f"Nombre del usuario: {datos_usuario['name']}")
    print(f"Biografía: {datos_usuario['bio']}")
    print(f"Localización: {datos_usuario['location']}")
    print(f"Cantidad de repositorios públicos: {datos_usuario['public_repos']}")

    # Almacenamiento de datos JSON en un archivo llamado "datos-usuario.json"
    with open('datos-usuario.json', 'w', encoding='utf-8') as archivo:
        json.dump(datos_usuario, archivo, indent=4, ensure_ascii=False)    
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")
Nombre del usuario: The Octocat
Biografía: None
Localización: San Francisco
Cantidad de repositorios públicos: 8

Consulta de datos de repositorios#

Documentación
REST API endpoints for repositories - GitHub Docs

import requests
import json

# Nombre del usuario propietario del repositorio
propietario = 'octocat'
# Nombre del repositorio
repositorio = 'Hello-World'
# URL
url = f'https://api.github.com/repos/{propietario}/{repositorio}'

# Solicitud GET
respuesta = requests.get(url)

# Verificación de la respuesta
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados
    datos_repositorio = respuesta.json()

    # Se imprimen elementos de datos específicos
    print(f"Nombre del repositorio: {datos_repositorio['name']}")
    print(f"Descripción: {datos_repositorio['description']}")
    print(f"Lenguaje principal: {datos_repositorio['language']}")
    print(f"Cantidad de estrellas: {datos_repositorio['stargazers_count']}")

    # Almacenamiento de datos JSON en un archivo llamado "datos-repositorio.json"
    with open('datos-repositorio.json', 'w', encoding='utf-8') as archivo:
        json.dump(datos_repositorio, archivo, indent=4, ensure_ascii=False)
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")
Nombre del repositorio: Hello-World
Descripción: My first repository on GitHub!
Lenguaje principal: None
Cantidad de estrellas: 2675

REST Countries#

REST Countries es una API de tipo REST que proporciona información sobre países de todo el mundo, incluyendo nombres oficiales, capitales, regiones, idiomas, monedas, población, banderas y códigos de país.

De acuerdo con su documentación, el URL base de la versión más reciente de REST Countries es:

https://restcountries.com/v3.1/

Algunos de sus endpoints son:

https://restcountries.com/v3.1/name/: consulta por nombre de país
https://restcountries.com/v3.1/alpha/: consulta por código (CCA2, CCN3, CCA3 or CIOC) de país
https://restcountries.com/v3.1/currency/: consulta por nombre o código de moneda
https://restcountries.com/v3.1/lang/: consulta por nombre o código de idioma

Seguidamente, se muestran algunos ejemplos de uso de esta API.

Consulta por nombre de país#

Documentación
REST Countries

El siguiente código se escribió para ser ejecutado desde un programa Python que lee el nombre (en inglés) de un país desde el teclado. Para probarlo, guarde el código en un archivo con extensión .py y ejecútelo.

import requests
import json

# Nombre del país
pais = input("Ingrese el nombre de un país: ")

# URL
url = f'https://restcountries.com/v3.1/name/{pais}'

# Solicitud GET
respuesta = requests.get(url)

# Verificación de la respuesta
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados en una lista
    datos = respuesta.json()

    # Se cargan los datos del primer país de la lista
    datos_pais = datos[0]

    # Se seleccionan elementos de datos específicos
    nombre_comun = datos_pais['name']['common']
    capital = datos_pais.get('capital', ['No disponible'])[0]
    region = datos_pais.get('region', 'No disponible')
    poblacion = datos_pais.get('population', 'No disponible')
    monedas = datos_pais.get('currencies', {})
    idiomas = datos_pais.get('languages', {})

    # Se unen las monedas en una hilera de texto
    lista_monedas = ', '.join([moneda['name'] for moneda in monedas.values()])

    # Se unen los idiomas en una hilera de texto
    lista_idiomas = ', '.join(idiomas.values())

    print(f"\nInformación sobre {nombre_comun}:")
    print(f"Capital: {capital}")
    print(f"Región: {region}")
    print(f"Población: {poblacion} habitantes")
    print(f"Moneda(s): {lista_monedas}")
    print(f"Idioma(s): {lista_idiomas}")
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")

Ejemplo de los resultados de la ejecución:

Ingrese el nombre de un país: Costa Rica

Información sobre Costa Rica:
Capital: San José
Región: Americas
Población: 5094114 habitantes
Moneda(s): Costa Rican colón
Idioma(s): Spanish

USGS Earthquake Catalog#

La USGS (del inglés, United States Geological Survey, en español, Servicio Geológico de Estados Unidos) es una agencia científica del gobierno federal de Estados Unidos dedicada al estudio del paisaje natural, sus recursos y los peligros naturales que lo amenazan. Tiene varias API que ofrecen acceso a una variedad de datos geológicos y geoespaciales, permitiendo a los desarrolladores integrar información sobre terremotos, recursos hídricos, mapas topográficos y más en sus aplicaciones. Entre los servicios que proporciona se incluyen datos en tiempo real sobre actividad sísmica, niveles y calidad del agua y elevación del terreno.

El USGS Earthquake Catalog es una API de tipo REST que brinda acceso a datos sísmicos en tiempo real y archivados de eventos ocurridos en todo el mundo. Permite consultar información detallada sobre terremotos, incluyendo magnitud, ubicación geográfica, profundidad, fecha y hora de ocurrencia, entre otros parámetros relevantes. Los datos pueden ser filtrados según criterios específicos y están disponibles en varios formatos como GeoJSON, CSV y XML, facilitando su integración en aplicaciones, sitios web y sistemas de monitoreo.

Documentación
API Documentation - Earthquake Catalog

De acuerdo con su documentación, el URL base de Earthquake Catalog es:

https://earthquake.usgs.gov/fdsnws/event/1/

Algunos de sus endpoints son:

https://earthquake.usgs.gov/fdsnws/event/1/query/: consultas personalizadas al catálogo sísmico utilizando parámetros como rango de fechas, magnitudes mínima y máxima, coordenadas geográficas (para definir un área de interés), profundidad y otros.

https://earthquake.usgs.gov/fdsnws/event/1/count/: número de eventos que coinciden con los criterios de búsqueda especificados. Es útil para obtener estadísticas rápidas sin descargar todos los datos.

https://earthquake.usgs.gov/fdsnws/event/1/count/application.wadl: Proporciona una descripción completa de la API en formato WADL (Web Application Description Language), útil para obtener todas las opciones y parámetros disponibles.

Seguidamente, se muestran algunos ejemplos de uso de esta API.

Consulta de terremotos#

import requests
import json
from datetime import datetime, timezone

# URL
url = 'https://earthquake.usgs.gov/fdsnws/event/1/query'

# Parámetros de la solicitud GET
parametros = {
    'format': 'geojson',
    'starttime': '2009-01-01',  # Fecha inicial,
    'endtime': '2009-12-31',    # Fecha final
    'minlatitude': 8.0,         # Latitud mínima de Costa Rica
    'maxlatitude': 11.5,        # Latitud máxima de Costa Rica
    'minlongitude': -86.0,      # Longitud mínima de Costa Rica
    'maxlongitude': -82.0,      # Longitud máxima de Costa Rica
    'minmagnitude': 5           # Magnitud mínima del terremoto    
}

# Solicitud GET
respuesta = requests.get(url, params=parametros)

# Se verifica si la solicitud fue exitosa
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados en una lista
    datos = respuesta.json()

    # Se separan los datos sobre terremotos
    terremotos = datos['features']  # Lista de terremotos

    # Se recorren los datos de terremotos 
    # y se despliegan elementos de datos específicos sobre cada uno
    for terremoto in terremotos:
        propiedades = terremoto['properties']

        # Conversión del tiempo a un formato legible
        timestamp = propiedades['time'] / 1000  # Conversión de milisegundos a segundos
        fecha_hora = datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')

        print(f"Fecha y hora: {fecha_hora}")
        print(f"Lugar: {propiedades['place']}")
        print(f"Magnitud: {propiedades['mag']}")
        print(f"Más información: {propiedades['url']}")
        print("-" * 40)

    # Almacenamiento de datos en un archivo llamado "terremotos.geojson"
    with open('terremotos.geojson', 'w', encoding='utf-8') as archivo:
        json.dump(datos, archivo, indent=4, ensure_ascii=False)        
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")
Fecha y hora: 2009-11-20 17:22:28
Lugar: 64 km NNE of Matina, Costa Rica
Magnitud: 5.2
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000h48n
----------------------------------------
Fecha y hora: 2009-09-06 05:02:44
Lugar: 3 km SSE of Corredor, Costa Rica
Magnitud: 5.1
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000h191
----------------------------------------
Fecha y hora: 2009-05-08 08:33:53
Lugar: 4 km NNW of Río Sereno, Panama
Magnitud: 5
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000gwxr
----------------------------------------
Fecha y hora: 2009-03-13 17:33:12
Lugar: 6 km WSW of Golfito, Costa Rica
Magnitud: 5.1
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000guyu
----------------------------------------
Fecha y hora: 2009-03-11 21:03:58
Lugar: 15 km SW of Golfito, Costa Rica
Magnitud: 5.9
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000guvb
----------------------------------------
Fecha y hora: 2009-03-11 17:26:52
Lugar: 2 km ENE of Golfito, Costa Rica
Magnitud: 5.3
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000guv7
----------------------------------------
Fecha y hora: 2009-03-11 17:24:36
Lugar: 15 km SW of Golfito, Costa Rica
Magnitud: 5.9
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000guv5
----------------------------------------
Fecha y hora: 2009-01-08 19:21:35
Lugar: 10 km NNE of Sabanilla, Costa Rica
Magnitud: 6.1
Más información: https://earthquake.usgs.gov/earthquakes/eventpage/usp000gscg
----------------------------------------

OpenWeatherMap - Weather API#

OpenWeatherMap es un servicio en línea que ofrece datos meteorológicos globales, incluyendo información actualizada del tiempo, pronósticos y datos históricos. OpenWeatherMap - Weather API es una API de tipo REST que brinda algunos servicios gratuitos como reporte del tiempo actual, pronósticos a corto plazo, mapas meteorológicos y alertas climáticas.

De acuerdo con su documentación, el URL base de la versión más reciente de OpenWeatherMap - Weather API es:

https://api.openweathermap.org/data/2.5/

Algunos de sus endpoints son:

https://api.openweathermap.org/data/2.5/weather/: reporte del tiempo para una ubicación específica
https://api.openweathermap.org/data/2.5/forecast/: pronóstico de cinco días con datos cada tres horas
https://api.openweathermap.org/data/2.5/onecall/: datos del tiempo actuales, históricos y pronósticos
https://api.openweathermap.org/data/2.5/air_pollution/: datos sobre calidad del aire

Seguidamente, se muestran algunos ejemplos de uso de esta API. Para ejecutar los ejemplos, debe crear una cuenta de usuario y obtener una API KEY en OpenWeatherMap, la cual debe utilizar en el código fuente.

Tiempo#

Documentación
Current weather data - OpenWeatherMap

import requests
import json

# URL
url = 'https://api.openweathermap.org/data/2.5/weather'

# API KEY de OpenWeatherMap (debe sustituirse por una real)
API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# Parámetros de la solicitud GET
parametros = {
    'lat': 9.93737623,   # Latitud decimal de la Escuela de Geografía de la UCR
    'lon': -84.04258876, # Longitud decimal de la Escuela de Geografía de la UCR
    'appid': API_KEY,    # API_KEY de OpenWeatherMap
    'units': 'metric',   # Unidades métricas
    'lang': 'es'         # Idioma español
}

# Solicitud GET
respuesta = requests.get(url, params=parametros)

# Se verifica si la solicitud fue exitosa
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados
    datos_tiempo = respuesta.json()

    # Se extraen datos específicos
    print(f"Lugar: {datos_tiempo['name']}")
    print(f"Tiempo: {datos_tiempo['weather'][0]['description']}")
    print(f"Temperatura actual: {datos_tiempo['main']['temp']}°C")
    print(f"Humedad: {datos_tiempo['main']['humidity']}%")
    print(f"Velocidad del viento: {datos_tiempo['wind']['speed']} m/s")

    # Almacenamiento de datos en un archivo llamado "tiempo.json"
    with open('tiempo.json', 'w', encoding='utf-8') as archivo:
        json.dump(datos_tiempo, archivo, indent=4, ensure_ascii=False)
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")

Ejemplo de salida:

Lugar: El Prado
Tiempo: muy nuboso
Temperatura actual: 19.07°C
Humedad: 94%
Velocidad del viento: 1.54 m/s

Calidad del aire#

Documentación
Air Pollution - OpenWeatherMap

import requests
import json

# URL
url = 'https://api.openweathermap.org/data/2.5/air_pollution'

# API KEY de OpenWeatherMap (debe sustituirse por una real)
API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# Parámetros de la solicitud GET
parametros = {
    'lat': 9.93737623,   # Latitud decimal de la Escuela de Geografía de la UCR
    'lon': -84.04258876, # Longitud decimal de la Escuela de Geografía de la UCR
    'appid': API_KEY     # API_KEY de OpenWeatherMap
}

# Solicitud GET
respuesta = requests.get(url, params=parametros)

# Se verifica si la solicitud fue exitosa
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados
    datos_calidad_aire = respuesta.json()

    # Se extraen datos específicos
    aqi = datos_calidad_aire['list'][0]['main']['aqi']
    componentes = datos_calidad_aire['list'][0]['components']

    # Mapeo del índice de calidad del aire a descripción
    calidad_aire = {
        1: 'Buena',
        2: 'Aceptable',
        3: 'Moderada',
        4: 'Mala',
        5: 'Muy mala'
    }

    print(f"Índice de calidad del aire (AQI): {aqi} ({calidad_aire.get(aqi, 'Desconocido')})")
    print("Concentración de contaminantes (μg/m³):")
    for contaminante, valor in componentes.items():
        print(f"  {contaminante.upper()}: {valor}")
    
    # Almacenamiento de datos en un archivo llamado "datos-calidad-aire.json"
    with open('datos-calidad-aire.json', 'w', encoding='utf-8') as archivo:
        json.dump(datos_calidad_aire, archivo, indent=4, ensure_ascii=False)
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")

Ejemplo de salida:

Índice de calidad del aire (AQI): 1 (Buena)
Concentración de contaminantes (μg/m³):
  CO: 660.9
  NO: 9.95
  NO2: 5.27
  O3: 0
  SO2: 3.82
  PM2_5: 6.76
  PM10: 7.19
  NH3: 1.17

Ejercicios#

  1. Pruebe los programas que acceden a OpenWeatherMap-Weather API con diferentes coordenadas y otros valores de entrada.

  2. Agregue el dato de porcentaje de nubosidad a la salida del programa que consulta el tiempo.

  3. Agregue el dato de la fecha y la hora de las mediciones a la salida del programa que consulta el tiempo.

  4. Busque otros elementos de datos que sean de interés para agregar a la salida del programa que consulta el tiempo.

  5. Agregue el dato de la fecha y la hora de las mediciones a la salida del programa que consulta la calidad del aire.

  6. Explore el Geocoding API de OpenWeatherMap y elabore dos programas: uno para probar la geocodificación directa y otro para probar la geocodificación reversa.

  7. Explore otros endpoints de OpenWeatherMap - Weather API e implemente programas para probarlos.

GBIF API#

`GBIF (en inglés, Global Biodiversity Information Facility, en español, Infraestructura Mundial de Información en Biodiversidad) es una infraestructura internacional que proporciona acceso libre y abierto a datos sobre biodiversidad de todo el mundo. GBIF API permite acceder datos de registros de presencia de especies (occurrences), información taxonómica y metadatos de colecciones biológicas.

El URL base de GBIF API es: https://api.gbif.org/

Algunos de sus endpoints son:

https://api.gbif.org/v1/species/: taxonomía
https://api.gbif.org/v1/occurrence/: registros de presencia
https://api.gbif.org/v1/literature/: literatura
https://api.gbif.org/v2/map/: mapas

El GBIF API también puede accederse mediante los paquetes pygbif (del lenguaje de programación R) y rgbif (del lenguaje de programación Python).

A continuación, se presentan ejemplos de uso del GBIF API.

Taxonomía#

Documentación
Species API: Technical Documentation

El endpoint https://api.gbif.org/v1/species/match puede buscar un taxón (ej. una especie) por su nombre científico y retornar datos sobre su taxonomía, incluyendo su taxonKey (identificador único).

import requests
import json

# Nombre científico de la especie
nombre_cientifico = 'Panthera onca'

# URL
url = 'https://api.gbif.org/v1/species/match'

# Parámetros de la solicitud GET
parametros = {
    'name': nombre_cientifico,
    'strict': True  # Asegura una coincidencia exacta en la búsqueda
}

# Solicitud GET
respuesta = requests.get(url, params=parametros)

# Verificación de la solicitud
if respuesta.status_code == 200:
    # La solicitud fue exitosa

    # Se cargan en formato JSON los datos retornados
    datos_taxon = respuesta.json()

    # Obtención del taxonKey de la especie
    taxon_key = datos_taxon.get('usageKey', 'No encontrado')

    # Despliegue del taxonKey
    print(f'taxonKey de {nombre_cientifico}: {taxon_key}')    

    # Almacenamiento de datos en un archivo llamado "datos-taxon.json"
    with open('datos-taxon.json', 'w', encoding='utf-8') as archivo:
        json.dump(datos_taxon, archivo, indent=4, ensure_ascii=False)
else:
    # Se produjo un error
    print(f"Error {respuesta.status_code}")
taxonKey de Panthera onca: 5219426

Registros de presencia (occurrences)#

Documentación
Occurrence API: Technical Documentation

El endpoint ‘https://api.gbif.org/v1/occurrence/search’ se utiliza para buscar registros de presencia según diversos criterios (geográficos, taxonómicos, temporales, etc.).

El siguiente bloque de código busca registros de presencia de especies en Costa Rica y que tengan coordenadas geográficas con base en el taxonKey de una especie o taxón. Se define una función llamada obtener_taxon_key() que recibe el nombre científico de una especie y retorna su taxonKey o None (si la especie no es encontrada).

import requests
import json

def obtener_taxon_key(nombre_cientifico):
    url = 'https://api.gbif.org/v1/species/match'

    parametros = {
        'name': nombre_cientifico,
        'strict': True  # Asegura una coincidencia exacta
    }

    respuesta = requests.get(url, params=parametros)
    
    if respuesta.status_code == 200:
        datos = respuesta.json()
        
        # Se revisa si la llave usageKy está presente en datos
        if 'usageKey' in datos:
            return datos['usageKey']
        else:
            return None
    else:
        return None

# Nombre científico de la especie
nombre_cientifico = 'Panthera onca'

# taxonKey de la especie
taxon_key = obtener_taxon_key(nombre_cientifico)

if taxon_key:
    # Se encontró el taxonKey

    # URL
    url = 'https://api.gbif.org/v1/occurrence/search'

    # Parámetros de la solicitud GET
    parametros = {
        'country': 'CR',          # Código de país ISO para Costa Rica
        'taxonKey': taxon_key,
        'limit': 300,             # Número máximo de registros a obtener (máximo 300 por solicitud)
        'hasCoordinate': 'true'   # Solo se incluyen registros de presencia con coordenadas
    }

    # Solicitud GET
    respuesta = requests.get(url, params=parametros)

    # Se verifica si la solicitud fue exitosa
    if respuesta.status_code == 200:
        # La solicitud fue exitosa

        # Se cargan en formato JSON los datos retornados
        datos_registros = respuesta.json()

        # Se extraen las ocurrencias
        registros = datos_registros['results']

        # Lista para las features de GeoJSON
        features = []

        # Se recorren los datos de registros de presencia y se convierten a features GeoJSON
        for registro in registros:
            especie = registro.get('species')
            fecha = registro.get('eventDate')
            localidad = registro.get('locality')
            latitud = registro.get('decimalLatitude')
            longitud = registro.get('decimalLongitude')

            print(f"Especie: {especie}")
            print(f"Fecha: {fecha}")
            print(f"Localidad: {localidad}")
            print(f"Longitud: {longitud}, Latitud: {latitud}")
            print("-" * 40)        

            # Se verifica que las coordenadas están presentes
            if latitud is not None and longitud is not None:
                feature = {
                    "type": "Feature",
                    "geometry": {
                        "type": "Point",
                        "coordinates": [longitud, latitud]  # GeoJSON utiliza el orden [longitud, latitud]
                    },
                    "properties": {
                        "species": especie,
                        "eventDate": fecha,
                        "locality": localidad
                    }
                }
                features.append(feature)

        # Crear el FeatureCollection GeoJSON
        geojson = {
            "type": "FeatureCollection",
            "features": features
        }

        # Almacenamiento de datos en un archivo llamado "datos-registros-presencia.geojson"
        with open('registros-presencia.geojson', 'w', encoding='utf-8') as archivo:
            json.dump(geojson, archivo, indent=4, ensure_ascii=False)

        print(f"Se han guardado {len(features)} registros de presencia en el archivo 'registros-presencia.geojson'")
    else:
        # Se produjo un error
        print(f"Error {respuesta.status_code}")
else:
    print(f'No se encontró el taxonKey de {nombre_cientifico}')
Especie: Panthera onca
Fecha: 2024-01-30T15:18:56
Localidad: None
Longitud: -83.579157, Latitud: 10.467856
----------------------------------------
Especie: Panthera onca
Fecha: 2024-01-25T07:16
Localidad: None
Longitud: -84.655167, Latitud: 10.22839
----------------------------------------
Especie: Panthera onca
Fecha: 2024-02-01T13:24:14
Localidad: None
Longitud: -83.566878, Latitud: 10.449497
----------------------------------------
Especie: Panthera onca
Fecha: 2024-02-06T09:51
Localidad: None
Longitud: -83.565366, Latitud: 8.466594
----------------------------------------
Especie: Panthera onca
Fecha: 2024-02-08T16:38
Localidad: None
Longitud: -83.563344, Latitud: 10.454353
----------------------------------------
Especie: Panthera onca
Fecha: 2024-02-09T11:42
Localidad: None
Longitud: -83.548497, Latitud: 10.469183
----------------------------------------
Especie: Panthera onca
Fecha: 2024-02-09T11:45
Localidad: None
Longitud: -83.449484, Latitud: 10.556402
----------------------------------------
Especie: Panthera onca
Fecha: 2024-03-11T06:40
Localidad: None
Longitud: -84.675464, Latitud: 10.839945
----------------------------------------
Especie: Panthera onca
Fecha: 2024-03-05T17:27
Localidad: None
Longitud: -84.754684, Latitud: 10.32483
----------------------------------------
Especie: Panthera onca
Fecha: 2024-05-25T07:57
Localidad: None
Longitud: -83.45606, Latitud: 10.411646
----------------------------------------
Especie: Panthera onca
Fecha: 2024-07-11T11:45
Localidad: None
Longitud: -85.667942, Latitud: 10.69378
----------------------------------------
Especie: Panthera onca
Fecha: 2024-08-30T15:51:24
Localidad: None
Longitud: -83.403606, Latitud: 10.452461
----------------------------------------
Especie: Panthera onca
Fecha: 2023-02-14T09:10:50
Localidad: None
Longitud: -83.414722, Latitud: 10.505114
----------------------------------------
Especie: Panthera onca
Fecha: 2023-04-10T11:50:04
Localidad: None
Longitud: -85.725034, Latitud: 10.800742
----------------------------------------
Especie: Panthera onca
Fecha: 2023-04-10T11:51:04
Localidad: None
Longitud: -85.738478, Latitud: 10.857479
----------------------------------------
Especie: Panthera onca
Fecha: 2023-06-17T15:53
Localidad: None
Longitud: -85.429583, Latitud: 10.801074
----------------------------------------
Especie: Panthera onca
Fecha: 2023-07-04T16:17:22
Localidad: None
Longitud: -84.171909, Latitud: 10.565713
----------------------------------------
Especie: Panthera onca
Fecha: 2023-07-22T06:32
Localidad: None
Longitud: -84.640117, Latitud: 10.291615
----------------------------------------
Especie: Panthera onca
Fecha: 2023-07-28T15:40
Localidad: None
Longitud: -84.688657, Latitud: 10.241681
----------------------------------------
Especie: Panthera onca
Fecha: 2023-08-02T13:51
Localidad: None
Longitud: -84.752421, Latitud: 10.335011
----------------------------------------
Especie: Panthera onca
Fecha: 2023-08-03T15:00
Localidad: None
Longitud: -84.744394, Latitud: 10.239703
----------------------------------------
Especie: Panthera onca
Fecha: 2023-08-17T06:00
Localidad: None
Longitud: -84.715788, Latitud: 10.378098
----------------------------------------
Especie: Panthera onca
Fecha: 2023-09-15T23:35
Localidad: None
Longitud: -84.713735, Latitud: 10.323172
----------------------------------------
Especie: Panthera onca
Fecha: 2023-09-07T10:00
Localidad: None
Longitud: -84.75432, Latitud: 10.307928
----------------------------------------
Especie: Panthera onca
Fecha: 2023-10-01T10:29:25
Localidad: None
Longitud: -83.152311, Latitud: 10.164605
----------------------------------------
Especie: Panthera onca
Fecha: 2023-10-04T05:53:18
Localidad: None
Longitud: -83.234848, Latitud: 10.106577
----------------------------------------
Especie: Panthera onca
Fecha: 2023-10-11T12:28:54
Localidad: None
Longitud: -85.655421, Latitud: 10.704329
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-10
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-10
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-10
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-11
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.560203, Latitud: 10.763197
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-11
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.560203, Latitud: 10.763197
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-11
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.560203, Latitud: 10.763197
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-13
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.58463, Latitud: 10.72969
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-13
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.58463, Latitud: 10.72969
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-13
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.58463, Latitud: 10.72969
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-24
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-24
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-24
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-04-12T07:13:13
Localidad: None
Longitud: -83.528661, Latitud: 10.59766
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-16
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-16
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-16
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-16
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-16
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-16
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.572084, Latitud: 10.738537
----------------------------------------
Especie: Panthera onca
Fecha: 2022-05-22T08:00
Localidad: None
Longitud: -85.592733, Latitud: 11.02931
----------------------------------------
Especie: Panthera onca
Fecha: 2022-08-22T19:02
Localidad: None
Longitud: -83.562764, Latitud: 10.489799
----------------------------------------
Especie: Panthera onca
Fecha: 2022-09-28T05:25
Localidad: None
Longitud: -85.659663, Latitud: 10.847266
----------------------------------------
Especie: Panthera onca
Fecha: 2022-10-09T18:40
Localidad: None
Longitud: -83.544452, Latitud: 10.544223
----------------------------------------
Especie: Panthera onca
Fecha: 2022-10-28T17:14:58
Localidad: None
Longitud: -84.012202, Latitud: 10.513393
----------------------------------------
Especie: Panthera onca
Fecha: 2022-12-23
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.57318, Latitud: 10.73641
----------------------------------------
Especie: Panthera onca
Fecha: 2022-12-10T11:02:58
Localidad: None
Longitud: -83.454236, Latitud: 10.407485
----------------------------------------
Especie: Panthera onca
Fecha: 2021-03-16
Localidad: RANCHO QUEMADO
Longitud: -83.55255, Latitud: 8.704
----------------------------------------
Especie: Panthera onca
Fecha: 2021-04-10T13:20:47
Localidad: None
Longitud: -84.084341, Latitud: 10.26186
----------------------------------------
Especie: Panthera onca
Fecha: 2021-05-14
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.5949, Latitud: 10.726964
----------------------------------------
Especie: Panthera onca
Fecha: 2021-05-14
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.5949, Latitud: 10.726964
----------------------------------------
Especie: Panthera onca
Fecha: 2021-05-19
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.5949, Latitud: 10.726964
----------------------------------------
Especie: Panthera onca
Fecha: 2021-09-22
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.5949, Latitud: 10.726964
----------------------------------------
Especie: Panthera onca
Fecha: 2020-01-27T12:02
Localidad: None
Longitud: -83.589544, Latitud: 10.563141
----------------------------------------
Especie: Panthera onca
Fecha: 2020-03-26T12:14
Localidad: None
Longitud: -84.753038, Latitud: 10.388769
----------------------------------------
Especie: Panthera onca
Fecha: 2020-03-14T09:43
Localidad: None
Longitud: -83.387481, Latitud: 8.512211
----------------------------------------
Especie: Panthera onca
Fecha: 2020-05-23
Localidad: Estacizxperimental Forestal Horizontes
Longitud: -85.5949, Latitud: 10.726964
----------------------------------------
Especie: Panthera onca
Fecha: 2020-09-10T16:09:05Z
Localidad: None
Longitud: -83.541359, Latitud: 9.876449
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-20
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-20
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-20
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-20
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-20
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-20
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-28
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-28
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-02-28
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-03-18T12:01
Localidad: None
Longitud: -83.536003, Latitud: 10.50904
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-11
Localidad: RANCHO QUEMADO
Longitud: -83.58411, Latitud: 8.67738
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-17
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-17
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-17
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-26
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-26
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-26
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-26
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-26
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-01
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-01
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-01
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-15
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-15
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-04-15
Localidad: RANCHO QUEMADO
Longitud: -83.5835, Latitud: 8.68927
----------------------------------------
Especie: Panthera onca
Fecha: 2019-05-07
Localidad: RANCHO QUEMADO
Longitud: -83.58411, Latitud: 8.67738
----------------------------------------
Especie: Panthera onca
Fecha: 2019-05-31
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-05-31
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-05-31
Localidad: MOGOS
Longitud: -83.40155, Latitud: 8.74807
----------------------------------------
Especie: Panthera onca
Fecha: 2019-07-04
Localidad: RANCHO QUEMADO
Longitud: -83.55246, Latitud: 8.70394
----------------------------------------
Especie: Panthera onca
Fecha: 2019-07-04
Localidad: RANCHO QUEMADO
Longitud: -83.55246, Latitud: 8.70394
----------------------------------------
Especie: Panthera onca
Fecha: 2019-07-04
Localidad: RANCHO QUEMADO
Longitud: -83.55246, Latitud: 8.70394
----------------------------------------
Especie: Panthera onca
Fecha: 2019-07-06
Localidad: RANCHO QUEMADO
Longitud: -83.55246, Latitud: 8.70394
----------------------------------------
Especie: Panthera onca
Fecha: 2019-08-02T08:43:13
Localidad: None
Longitud: -83.433084, Latitud: 10.558145
----------------------------------------
Especie: Panthera onca
Fecha: 2019-09-18T16:22:35
Localidad: None
Longitud: -85.594155, Latitud: 10.843254
----------------------------------------
Especie: Panthera onca
Fecha: 2019-10-08T22:07
Localidad: None
Longitud: -83.692092, Latitud: 10.724513
----------------------------------------
Especie: Panthera onca
Fecha: 2018-04-08T10:07:40
Localidad: None
Longitud: -83.7266, Latitud: 8.78439
----------------------------------------
Especie: Panthera onca
Fecha: 2018-04-07T08:46:16
Localidad: None
Longitud: -83.765998, Latitud: 8.73978
----------------------------------------
Especie: Panthera onca
Fecha: 2018-06-21T20:38:21
Localidad: None
Longitud: -84.181651, Latitud: 10.416283
----------------------------------------
Especie: Panthera onca
Fecha: 2017-12-13T09:06:13
Localidad: None
Longitud: -83.339621, Latitud: 8.657425
----------------------------------------
Especie: Panthera onca
Fecha: 2016-01-29
Localidad: None
Longitud: -83.42066, Latitud: 10.482056
----------------------------------------
Especie: Panthera onca
Fecha: 2015-10-06T15:52
Localidad: None
Longitud: -83.488668, Latitud: 8.839019
----------------------------------------
Especie: Panthera onca
Fecha: 2014-04-15T15:53
Localidad: None
Longitud: -83.45907, Latitud: 10.523513
----------------------------------------
Especie: Panthera onca
Fecha: 2013-04-05T09:33
Localidad: None
Longitud: -83.40461, Latitud: 10.568895
----------------------------------------
Especie: Panthera onca
Fecha: 2013-05-03T11:47
Localidad: None
Longitud: -83.548784, Latitud: 10.485827
----------------------------------------
Especie: Panthera onca
Fecha: 2013-05-23T09:06
Localidad: None
Longitud: -83.378839, Latitud: 10.231784
----------------------------------------
Especie: Panthera onca
Fecha: 2013-09-13
Localidad: None
Longitud: -83.477647, Latitud: 10.461741
----------------------------------------
Especie: Panthera onca
Fecha: 2013-12-28T07:44
Localidad: None
Longitud: -85.64662, Latitud: 10.947836
----------------------------------------
Especie: Panthera onca
Fecha: 2012-12-26
Localidad: None
Longitud: -85.614037, Latitud: 10.651345
----------------------------------------
Especie: Panthera onca
Fecha: 2011-02-15T09:28Z
Localidad: None
Longitud: -85.798497, Latitud: 10.865281
----------------------------------------
Especie: Panthera onca
Fecha: 2011-06-22T17:02Z
Localidad: None
Longitud: -83.542163, Latitud: 10.445335
----------------------------------------
Especie: Panthera onca
Fecha: 2009-03-31T14:32
Localidad: None
Longitud: -83.563265, Latitud: 10.424067
----------------------------------------
Especie: Panthera onca
Fecha: 2009-03-16T15:06
Localidad: None
Longitud: -84.008126, Latitud: 10.205651
----------------------------------------
Especie: Panthera onca
Fecha: 2009-11-08
Localidad: None
Longitud: -83.458064, Latitud: 8.446631
----------------------------------------
Especie: Panthera onca
Fecha: 2007-04-09T10:18
Localidad: None
Longitud: -84.19855, Latitud: 10.260415
----------------------------------------
Especie: Panthera onca
Fecha: 2003-08-04
Localidad: None
Longitud: -85.623591, Latitud: 10.70885
----------------------------------------
Especie: Panthera onca
Fecha: 1993-06-10
Localidad: DELICIAS DE UPALA, 2 KM N OF
Longitud: -85.0146, Latitud: 10.9197
----------------------------------------
Especie: Panthera onca
Fecha: 1993-06-10
Localidad: DELICIAS DE UPALA, 2 KM N OF
Longitud: -85.05, Latitud: 10.96808
----------------------------------------
Especie: Panthera onca
Fecha: None
Localidad: None
Longitud: -84.0, Latitud: 9.95
----------------------------------------
Se han guardado 123 registros de presencia en el archivo 'registros-presencia.geojson'

Visualización#

Para generar las visualizaciones que se muestran en las secciones siguientes, deben instalarse los paquetes matplotlib, plotly, geopandas, leafmap y localtileserver.

Para la instalación en un ambiente conda, pueden ejecutarse los comandos:

conda config --env --add channels conda-forge
conda config --env --set channel_priority strict

mamba install -c conda-forge matplotlib plotly geopandas leafmap localtileserver
Gráfico de registros de presencia por mes#
import pandas as pd
import geopandas as gpd
import plotly.express as px

# Lista de nombres de meses en español
meses_espanol = [
    'Desconocido',  # Índice 0
    'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
    'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
]

# Lectura del archivo GeoJSON en un GeoDataFrame
gdf = gpd.read_file('registros-presencia.geojson')

# Conversión de 'eventDate' a hilera de texto y luego a formato datetime
gdf['eventDate'] = gdf['eventDate'].astype(str)
gdf['eventDate'] = pd.to_datetime(gdf['eventDate'], errors='coerce')

# Extracción del número del mes
gdf['mes_num'] = gdf['eventDate'].dt.month
# Mapear los números de mes a nombres en español
gdf['mes'] = gdf['mes_num'].apply(
    lambda x: meses_espanol[int(x)] if pd.notnull(x) and x >= 1 and x <= 12 else 'Desconocido'
)

# Conteo y ordenamiento de la cantidad de registros de presencia por mes
registros_por_mes = gdf.groupby(['mes_num', 'mes']).size().reset_index(name='cantidad')
registros_por_mes = registros_por_mes.sort_values('mes_num')

# Creación del gráfico de barras interactivo con plotly
fig = px.bar(
    registros_por_mes,
    x='mes',
    y='cantidad',
    title='Cantidad de registros de presencia por mes',
    labels={'mes': 'Mes', 'cantidad': 'Cantidad de registros de presencia'},
    text='cantidad'
)

# Ajustes al gráfico
fig.update_layout(
    xaxis_tickangle=-45,
    xaxis_title='Mes',
    yaxis_title='Registros de presencia',
    title_x=0.5,
    template='plotly_white'
)

# Despliegue del gráfico
fig.show()
Mapa de distribución de registros de presencia#
import leafmap

# Creación de un objeto Map de leafmap centrado en Costa Rica
m = leafmap.Map(center=(9.972725, -84.19451), zoom=7)

# Adición de datos GeoJSON al mapa
m.add_point_layer(
    'registros-presencia.geojson', 
    popup=["species", "eventDate", "locality"], 
    layer_name="Registros de presencia"
)

# Despliegue del mapa
m