import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
from datetime import datetime
from pyinaturalist import get_observations
import ipyplotMis fotos del año 2006
En 2006 organizamos el primer curso de NeoMapas y tuvimos un grupo de estudiantes y voluntarios viajando por Venezuela para colectar mariposas y escarabajos coprófagos.
Para poner estas observaciones de 2006 en contexto temporal de mis contribuciones a iNat, pueden revisar este gráfico
Después de terminar de actualizar mis observaciones de otros años (2008, 2010, 2012) he decidido repetir el proceso para el año 2006. Este documento me permite visualizar las fotos que ya están en iNaturalist y así evitar subir fotos por duplicado. En este año recopilé varias fotos compartidas por los estudiantes y voluntarios de las actividades de NeoMapas, pero me ha tomado bastante tiempo organizarlas y encontrar los datos pertinentes para asignar las coordenadas geográficas y fechas correctas.
Cargar módulos en Python
Importamos los módulos necesarios:
Y declaramos una función útil para leer los datos temporales de la respuesta del API de iNat:
def as_date(x):
if type(x) == str:
y = datetime.strptime(x, "%Y-%m-%d").date()
else:
y = datetime.date(x)
return(y)Descargar datos
Los datos espaciales de los estados de Venezuela están disponibles a través de esta página del Humanitarian Data Exchange: https://data.humdata.org/dataset/cod-ab-ven Usamos read_file del modulo geopandas para abrir esta capa desde el url de descarga.
zipurl = 'https://data.humdata.org/dataset/5b141d29-534f-4f01-a0bc-41e2f375d925/resource/b6cf4bf5-418a-49ad-80ec-b84d0e0e0d41/download/ven_adm_ine_20210223_shp.zip'
vzla_estados=gpd.read_file(zipurl,
layer='ven_admbnda_adm1_ine_20210223',
columns=['ADM1_ES','geometry'])Usamos get_observations con un intervalo de fechas que incluye todo el año 2010:
observations = get_observations(user_id='NeoMapas',
d1="2006-01-01",
d2="2006-12-31",
per_page=1000)Este número aumenta a medida que cargamos observaciones en iNat:
len(observations['results'])190
Usamos este loop para guardar la información básica de cada observación:
records=list()
for obs in observations['results']:
record = {
'uri':obs['uri'],
'species guess': obs['species_guess'],
'location': obs['place_guess'],
'longitude': obs['location'][1],
'latitude': obs['location'][0],
'Fecha_obs': as_date(obs['observed_on']),
'Fecha_reg': as_date(obs['created_at'])
}
if len(obs['observation_photos'])>0:
record['url'] = obs['observation_photos'][0]['photo']['url'].replace("square","medium")
record['attribution'] = obs['observation_photos'][0]['photo']['attribution']
records.append(record)Y las transformamos en un marco de datos con información espacial para usar con geopandas:
gs = [Point(float(obs['longitude']), float(obs['latitude'])) for obs in records]
inat_obs=gpd.GeoDataFrame(records, geometry=gs, crs="EPSG:4326")Resumen de las observaciones por estado
Primero combinamos la información de iNat con los estados de Venezuela. Usamos la función sjoin_nearest porque algunas observaciones provienen de la costa y las coordenadas de especies amenazadas están protegidas.
crs_lacanoa="EPSG:24719"inat_obs_estados = gpd.sjoin_nearest(
inat_obs.to_crs(crs_lacanoa),
vzla_estados.to_crs(crs_lacanoa),
distance_col="distances",
how="left",
max_distance=50000,
lsuffix='in',
rsuffix='vzla')inat_obs_estados.fillna({'ADM1_ES':'No info'},inplace=True)
inat_obs_estados['mes'] = [fobs.month for fobs in inat_obs_estados['Fecha_obs']]Agrupamos las observaciones por la localidad y mes, y obtenemos una tabla resumen de las observaciones del año:
aggfuns = {
'species guess': 'count',
}
inat_obs_estados.groupby(['ADM1_ES','mes']).agg(aggfuns).unstack().fillna(0)| species guess | ||||||||
|---|---|---|---|---|---|---|---|---|
| mes | 1 | 2 | 4 | 5 | 7 | 8 | 9 | 12 |
| ADM1_ES | ||||||||
| Anzoátegui | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| Aragua | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
| Barinas | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 9.0 | 7.0 | 0.0 |
| Bolívar | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 19.0 | 0.0 | 0.0 |
| Carabobo | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| Distrito Capital | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
| Falcón | 0.0 | 0.0 | 0.0 | 0.0 | 6.0 | 0.0 | 0.0 | 0.0 |
| Guárico | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
| La Guaira | 0.0 | 0.0 | 0.0 | 2.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| Lara | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 3.0 | 0.0 |
| Miranda | 0.0 | 0.0 | 2.0 | 0.0 | 20.0 | 0.0 | 1.0 | 0.0 |
| Monagas | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| Mérida | 0.0 | 0.0 | 0.0 | 0.0 | 14.0 | 0.0 | 0.0 | 0.0 |
| Sucre | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
| Táchira | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 | 6.0 | 0.0 | 0.0 |
| Yaracuy | 0.0 | 21.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| Zulia | 0.0 | 0.0 | 0.0 | 0.0 | 16.0 | 0.0 | 0.0 | 0.0 |
Filtrar por fecha
Con estas líneas de código podemos filtrar por fecha de observación:
inat_obs['mes'] = [fobs.month for fobs in inat_obs['Fecha_obs']]En noviembre visitamos México:
Progreso
Aquí se puede ver el progreso que he hecho en cargar las fotos del año 2008, creo que estas son todas las que tengo respaldadas:
aggfuns = {
'Fecha_obs': ["min", "max"],
'location': ['count',pd.Series.nunique],
'species guess': [pd.Series.nunique],
}
inat_obs.groupby('Fecha_reg').agg(aggfuns)| Fecha_obs | location | species guess | |||
|---|---|---|---|---|---|
| min | max | count | nunique | nunique | |
| Fecha_reg | |||||
| 2020-09-26 | 2006-09-10 | 2006-09-10 | 1 | 1 | 1 |
| 2023-11-18 | 2006-07-13 | 2006-09-03 | 8 | 4 | 8 |
| 2024-01-24 | 2006-02-20 | 2006-02-23 | 21 | 5 | 20 |
| 2024-04-04 | 2006-09-03 | 2006-09-03 | 1 | 1 | 1 |
| 2025-03-22 | 2006-04-21 | 2006-04-21 | 2 | 1 | 2 |
| 2025-07-26 | 2006-05-05 | 2006-05-05 | 2 | 2 | 2 |
| 2025-07-27 | 2006-09-25 | 2006-09-25 | 1 | 1 | 1 |
| 2025-08-09 | 2006-01-02 | 2006-01-02 | 2 | 2 | 1 |
| 2025-08-11 | 2005-12-31 | 2006-08-30 | 17 | 5 | 15 |
| 2025-08-12 | 2006-07-13 | 2006-08-24 | 11 | 7 | 10 |
| 2025-08-14 | 2006-07-12 | 2006-09-04 | 48 | 12 | 29 |
| 2025-08-15 | 2006-07-01 | 2006-08-03 | 44 | 12 | 27 |
| 2025-08-16 | 2006-07-12 | 2006-07-31 | 32 | 5 | 5 |
Todas las observaciones
Y cierro aquí con todas las imágenes de las observaciones de este año:
images = inat_obs.sort_values('Fecha_obs')['url']
labels = inat_obs.sort_values('Fecha_obs')['species guess']
ipyplot.plot_images(list(images), list(labels), max_images=200,)