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