import pandas as pd
import folium
from datetime import datetime, timedelta
from pyinaturalist import (
Observation,
get_observations,
#pprint,
)
import ipyplot
from itertools import compressA visit to Tajikistan
Tajikistan
Python
pyinaturalist
Folium
A summary of my iNaturalist observations during a visit to Tajikistan for the Internation Conference on Glacier Preservation.
Load Python modules
Download iNaturalist observations
From the end of May to the first week of June 2025
observations = get_observations(user_id='NeoMapas',
d1="2025-05-27",
d2="2025-06-06",
per_page=1000)len(observations['results'])33
Map of observations
map = folium.Map(tiles="Esri NatGeoWorldMap")fg = folium.FeatureGroup(name="iNaturalist observations", control=True, attribution="observers @ iNaturalist").add_to(map)
popup_text = """<img src='{url}'>
<caption><i>{species}</i> observed on {observed_on} / {attribution}</caption> {desc}
"""
for obs in observations['results']:
if obs['quality_grade'] == 'research':
if obs['description'] is None:
desc = ""
else:
desc = obs['description']
pincolor = 'green'
else:
desc = "Observation is not research quality grade."
pincolor = 'gray'
fg.add_child(
folium.Marker(
location=obs['location'],
popup=popup_text.format(
species=obs['species_guess'],
observed_on=obs['observed_on'],
desc=desc,
url = obs['observation_photos'][0]['photo']['url'],
attribution = obs['observation_photos'][0]['photo']['attribution']),
icon=folium.Icon(color=pincolor),
)
)
folium.LayerControl().add_to(map)<folium.map.LayerControl object at 0x105d1c500>
map.fit_bounds(map.get_bounds())
mapMake this Notebook Trusted to load map: File -> Trust Notebook
Travel log
records=list()
for obs in observations['results']:
record = {'quality': obs['quality_grade'],
'description': obs['description'],
'location': obs['place_guess'],
'longitude': obs['location'][1],
'latitude': obs['location'][0],
'species guess': obs['species_guess'],
'Fecha': obs['observed_on'],
}
if len(obs['observation_photos'])>0:
record['url'] = obs['observation_photos'][0]['photo']['url']
record['attribution'] = obs['observation_photos'][0]['photo']['attribution']
records.append(record)inat_obs=pd.DataFrame(records)inat_obs["dia"]=inat_obs.Fecha.apply(datetime.date)inat_obs.groupby('dia').agg({'species guess': ['count',pd.Series.nunique]})| species guess | ||
|---|---|---|
| count | nunique | |
| dia | ||
| 2025-05-28 | 13 | 12 |
| 2025-05-31 | 1 | 1 |
| 2025-06-01 | 9 | 9 |
| 2025-06-02 | 9 | 9 |
| 2025-06-03 | 1 | 1 |
my_observations = Observation.from_json_list(observations)images = [obs.photos[0].small_url for obs in my_observations]
labels = [str(obs) for obs in my_observations]Dushanbe and Hissor Fortress
Observations from our first day in Tajikistan:
Explore observations on iNaturalist
ss = [datetime.date(obs.observed_on).strftime('%d/%m/%Y') in ['28/05/2025',] for obs in my_observations]
ipyplot.plot_images(list(compress(images, ss)), list(compress(labels, ss)), max_images=60,)Siyoma Gorge
ss = [datetime.date(obs.observed_on).strftime('%Y-%m-%d') in ['2025-06-01'] for obs in my_observations]
ipyplot.plot_images(list(compress(images, ss)), list(compress(labels, ss)), max_images=60,)Paseo a Tigrovaya Balka
ss = [datetime.date(obs.observed_on).strftime('%Y-%m-%d') in ['2025-06-02','2025-06-03'] for obs in my_observations]
ipyplot.plot_images(list(compress(images, ss)), list(compress(labels, ss)), max_images=60,)