Tutorial 1: Observations¶
This notebook will give a quick introduction to things you can do using data from your own iNaturalist observations.
[1]:
from datetime import datetime, timedelta
import ipyplot
from dateutil.relativedelta import relativedelta
from IPython.display import Image
from pyinaturalist import (
ICONIC_TAXA,
Observation,
TaxonCount,
UserCount,
enable_logging,
get_observation_histogram,
get_observation_identifiers,
get_observation_observers,
get_observation_species_counts,
get_observations,
pprint,
)
from rich import print
enable_logging()
Basic observation search¶
We’ll start with the observation search page. get_observations() supports all the same search filters as the ones you see on iNaturalist.org:
Let’s start by searching for all of your own observations:
[2]:
# Replace with your own username
USERNAME = 'jkcook'
response = get_observations(user_id=USERNAME, page='all')
my_observations = Observation.from_json_list(response)
Observation data¶
Take a look at one of the observations to see what information it contains:
[3]:
print(my_observations[0])
Observation( id=30688807, created_at=datetime.datetime(2019, 8, 12, 15, 22, 47, tzinfo=tzlocal()), captive=False, community_taxon_id=78444, description='Located in Green Meadows West Prairie\n\nSpecies IDs:\nhttps://sites.google.com/site/gmwprairie/gmw-prairie-flora', faves=[], geoprivacy=None, identifications_count=1, identifications_most_agree=True, identifications_most_disagree=False, identifications_some_agree=True, license_code='CC-BY-NC', location=(41.67206561, -93.72957587), mappable=True, num_identification_agreements=1, num_identification_disagreements=0, oauth_application_id=2, obscured=False, observed_on=datetime.datetime(2019, 8, 12, 10, 16, tzinfo=tzoffset('Etc/UTC', 0)), outlinks=[{'source': 'GBIF', 'url': 'http://www.gbif.org/occurrence/2429228652'}], out_of_range=None, owners_identification_from_vision=False, place_guess='Johnston, IA, USA', place_ids=[ 1, 24, 1582, 9853, 59613, 64422, 64423, 66741, 82256, 97394, 116535, 129109, 137509, 154492, 155074 ], positional_accuracy=12, preferences={'prefers_community_taxon': None}, project_ids=[48611], project_ids_with_curator_id=[], project_ids_without_curator_id=[48611], public_positional_accuracy=12, quality_grade='research', quality_metrics=[], reviewed_by=[1436999, 2115051], site_id=1, sounds=[], species_guess='Rocky Mountain bee plant', tags=[], updated_at=datetime.datetime(2019, 10, 16, 3, 43, 4, tzinfo=tzlocal()), uri='https://www.inaturalist.org/observations/30688807', uuid='aea799e1-4754-4eaf-adca-84720cdeaeb2', votes=[], annotations=[ [12] 12|13 (0 votes) ], comments=[], identifications=[ [66501609] 🌱 Species: Peritoma serrulata (Rocky Mountain beeplant) (improving) added on Aug 12, 2019 by jkcook, [74656703] 🌱 Species: Peritoma serrulata (Rocky Mountain beeplant) (supporting) added on Oct 16, 2019 by colincroft ], ofvs=[], photos=[ [47956314] https://inaturalist-open-data.s3.amazonaws.com/photos/47956314/original.jpeg?1565623377 (CC-BY-NC, 1365x2048) ], project_observations=[ ProjectObservation(id=33209242, preferences={'allows_curator_coordinate_access': True}, project={'id': 48611}, user_id=2115051, uuid='0ae36f62-59e8-4b90-affd-eb1ddb437262') ], taxon=[78444] 🌱 Species: Peritoma serrulata (Rocky Mountain beeplant), user=[2115051] jkcook (Jordan Cook) )
Observation data compared to the web UI¶
Here is how some of those fields correspond to what you see on an observation page on iNaturalist.org:
You’ll notice that there are many more fields available; see the Observation docs for a complete list.
Previewing data¶
In many cases, you will want to quickly preview API results without looking through the full details for each result. pyinaturalist.pprint()
can be used to show a condensed table of almost all response types. Here’s an example with just the first 30 results:
[4]:
pprint(my_observations[:30])
ID Taxon ID Taxon Observed on User Location ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 30688807 78444 🌱 Species: Peritom… Aug 12, 2019 jkcook Johnston, IA, USA serrulata (Rocky Mountain beeplant) 30688955 47912 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Asclepias tuberosa (butterfly milkweed) 30689111 60251 🌱 Species: Verbena Aug 12, 2019 jkcook Johnston, IA, USA hastata (blue vervain) 30689221 121968 🌽 Species: Aug 12, 2019 jkcook Johnston, IA, USA Andropogon gerardi (big bluestem) 30689306 121968 🌽 Species: Aug 12, 2019 jkcook Johnston, IA, USA Andropogon gerardi (big bluestem) 30689425 128701 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Desmanthus illinoensis (Illinois bundleflower) 30689463 121976 🌻 Species: Silphiu… Aug 12, 2019 jkcook Johnston, IA, USA laciniatum (compass plant) 30689506 136376 🌻 Species: Aug 12, 2019 jkcook Johnston, IA, USA Rudbeckia triloba (Brown-eyed Susan) 30689603 121976 🌻 Species: Silphiu… Aug 12, 2019 jkcook Johnston, IA, USA laciniatum (compass plant) 30689780 81594 🌾 Species: Elymus Aug 12, 2019 jkcook Johnston, IA, USA hystrix (bottlebrush grass) 30690105 127907 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Chamaecrista fasciculata (partridge pea) 30690175 141767 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Veronicastrum virginicum (Culver's root) 30690204 48678 🌼 Genus: Solidago Aug 12, 2019 jkcook Johnston, IA, USA (goldenrods) 30690327 128701 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Desmanthus illinoensis (Illinois bundleflower) 30726806 127186 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Securigera varia (purple crownvetch) 30727162 128695 🥕 Species: Eryngiu… Aug 12, 2019 jkcook Johnston, IA, USA yuccifolium (rattlesnake master) 30727377 136561 🌾 Form: Elymus Aug 12, 2019 jkcook Johnston, IA, USA canadensis glaucifolius 30727961 48662 🦋 Species: Danaus Aug 12, 2019 jkcook Green Meadows West plexippus (Monarch) Prairie 30728796 120215 🐝 Species: Bombus Aug 12, 2019 jkcook Green Meadows West griseocollis Prairie (Brown-belted Bumble Bee) 30728902 55556 🐛 Species: Aug 12, 2019 jkcook Green Meadows West Oncopeltus fasciatus Prairie (Large Milkweed Bug) 30729015 81599 🌻 Species: Silphiu… Aug 12, 2019 jkcook Green Meadows West perfoliatum (cup Prairie plant) 30729970 47911 🌱 Species: Aug 12, 2019 jkcook Johnston, IA, USA Asclepias syriaca (common milkweed) 30729981 130382 🌻 Species: Aug 12, 2019 jkcook Johnston, IA, USA Heliopsis helianthoides (false sunflower) 30730005 204330 🌱 Species: Iris Aug 12, 2019 jkcook Johnston, IA, USA domestica (Blackberry Lily) 30730009 128695 🥕 Species: Eryngiu… Aug 12, 2019 jkcook Johnston, IA, USA yuccifolium (rattlesnake master) 30730021 54781 🌳 Species: Quercus Aug 12, 2019 jkcook Johnston, IA, USA macrocarpa (bur oak) 30730033 127907 🌱 Species: Aug 12, 2019 jkcook Green Meadows West Chamaecrista Prairie fasciculata (partridge pea) 30730042 48627 🌻 Species: Aug 12, 2019 jkcook Johnston, IA, USA Echinacea purpurea (purple coneflower) 30730087 62741 🌻 Species: Aug 12, 2019 jkcook Johnston, IA, USA Rudbeckia hirta (black-eyed Susan) 30730133 56031 🌱 Genus: Calystegi… Aug 12, 2019 jkcook Green Meadows West (false bindweeds) Prairie
Observation species¶
On iNaturalist.org, the next tab of the observation search page is Species. You can get this information with get_observation_species_counts().
For example, all the frogs and toads observed in Mexico:
Here is how to get that same information from the API:
[5]:
# Note: 6793 is the place ID for Mexico, and 20979 is the taxon ID for the Order Anura
response = get_observation_species_counts(place_id=6793, taxon_id=20979)
Then we can see a preview of the top 10 results:
[6]:
taxa = TaxonCount.from_json_list(response['results'][:10])
pprint(taxa)
ID Rank Scientific name Count ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 24277 species 🐸 Smilisca baudinii 2241 517119 species 🐸 Rhinella horribilis 2005 23933 species 🐸 Hyla arenicolor 1839 65551 species 🐸 Hyla eximia 1764 65860 species 🐸 Incilius valliceps 1553 65849 species 🐸 Incilius nebulifer 877 65975 species 🐸 Lithobates berlandieri 854 135027 species 🐸 Agalychnis dacnicolor 798 554652 species 🐸 Rheohyla miotympanum 797 1148187 species 🐸 Trachycephalus vermiculatus 753
Observation identifiers¶
get_observation identifiers() gets us information shown on the next tab: Identifiers:
[7]:
response = get_observation_identifiers(place_id=6793, taxon_id=20979)
users = UserCount.from_json_list(response['results'][:10])
pprint(users)
ID Username Display name Count ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 22707 coatzin_tutor M. Domínguez-Laso 5392 46681 cris-tzabcan Cristian Olvera 4852 1051916 pedro_nahuat Pedro E. Nahuat-Cervera 2655 17327 yamaneko Rafael Paredes Montesinos 2245 3656 eligarcia-padilla Elí García-Padilla 1894 523033 opuntia24 Miguel A. Chavez Caballero 1726 1315 escalante-pasos Jorge Armín Escalante Pasos 1611 8489 josecamx José Carlos Arenas Monroy 1596 36855 sonoran Chris Grünwald Herp.mx 1534 23647 jhvaldez_tutor Jorge H. Valdez 1454
Observation observers¶
And get_observation observers() gets us information from the Observers tab:
[8]:
response = get_observation_observers(place_id=6793, taxon_id=20979)
users = UserCount.from_json_list(response['results'][:10])
pprint(users)
ID Username Display name Count ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1051916 pedro_nahuat Pedro E. Nahuat-Cervera 424 28799 luis_diaz-gamboa Luis Díaz-Gamboa 336 71758 andrea_navarro20 Andrea Navarro 332 23647 jhvaldez_tutor Jorge H. Valdez 322 46555 magazhu Cheryl Harleston López Espino 318 5772 juancruzado Juan Cruzado Cortés 311 54220 aplomadobirdy Big Birdy 282 21626 francisco3_ Francisco Farriols Sarabia 201 376395 emmguevara Emmanuel Guevara Lazcano 187 4095390 eric_centenero-alcala Eric Centenero Alcalá 173
Observation photos¶
When you’re working in Jupyter, there are a number of ways to preview observation photos. For these examples, we’ll use your own observation data from the first step in this tutorial.
Viewing individual observation photos¶
Use Photo.show()
to see a photo from a single observation:
[9]:
my_observations[-4].photos[0].show()

Observation photo grid¶
We can use ipyplot to preview observation images. Observation.photos
contains a list of Photo objects, and we can use those to get a thumnail URL for first photo from each observation. For image labels, just call str(observation)
to get a summary of the observation (who/what/when/where).
[10]:
images = [obs.photos[0].thumbnail_url for obs in my_observations[:15]]
labels = [str(obs) for obs in my_observations[:15]]
ipyplot.plot_images(images, labels)
Observation photo grid grouped by iconic taxon¶
We can organize this a bit more by grouping these photos by iconic taxon. Use ipyplot.plot_class_tabs
to group by label, and use Observation.taxon.iconic_taxon_name
as the image labels:
[11]:
images = [obs.photos[0].thumbnail_url for obs in my_observations]
labels = [obs.taxon.iconic_taxon_name for obs in my_observations]
ipyplot.plot_class_tabs(images, labels, max_imgs_per_tab=15)
Observation histogram¶
Another useful format is the observation histogram, which shows the number of observations over a given interval
.
The default is month_of_year
, which will show counts of all your observations by month, for all years combined:
[12]:
histogram = get_observation_histogram(user_id=USERNAME)
print(histogram)
{1: 8, 2: 1, 3: 19, 4: 26, 5: 32, 6: 59, 7: 14, 8: 402, 9: 92, 10: 65, 11: 23, 12: 6}
Another option is week
:
[13]:
histogram = get_observation_histogram(user_id=USERNAME, interval='week')
# Print just the most recent 10 weeks
for date, count in list(histogram.items())[-10:]:
print(f'{date}: {count}')
2021-04-19 00:00:00: 5
2021-04-26 00:00:00: 0
2021-05-03 00:00:00: 0
2021-05-10 00:00:00: 1
2021-05-17 00:00:00: 0
2021-05-24 00:00:00: 0
2021-05-31 00:00:00: 0
2021-06-07 00:00:00: 1
2021-06-14 00:00:00: 7
2021-06-21 00:00:00: 12
Or month
:
[14]:
histogram = get_observation_histogram(user_id=USERNAME, interval='month')
# Print just the most recent 12 months
for date, count in list(histogram.items())[-12:]:
print(f'{date}: {count}')
2020-07-01 00:00:00: 12
2020-08-01 00:00:00: 8
2020-09-01 00:00:00: 8
2020-10-01 00:00:00: 1
2020-11-01 00:00:00: 1
2020-12-01 00:00:00: 0
2021-01-01 00:00:00: 1
2021-02-01 00:00:00: 0
2021-03-01 00:00:00: 3
2021-04-01 00:00:00: 17
2021-05-01 00:00:00: 1
2021-06-01 00:00:00: 20