Regional activity time series visualizations¶
This example shows how to create visualizations of iNaturalist activity over time in a given region. See https://www.inaturalist.org/places to find place IDs.
Visualization are made using Altair, with the following metrics: * Number of observations * Number of taxa observed * Number of observers * Number of identifiers
[1]:
from datetime import datetime
from time import sleep
from typing import Any, BinaryIO, Dict, Iterable, List, Optional, Tuple
import altair as alt
import pandas as pd
from pyinaturalist import (
ICONIC_TAXA,
get_interval_ranges,
get_observation_histogram,
get_observation_identifiers,
get_observation_observers,
get_observation_species_counts,
get_observations,
)
# Adjustable values
PLACE_ID = 6
PLACE_NAME = 'Alaska'
YEAR = 2020
Observations per year¶
[2]:
observations_by_year = get_observation_histogram(
place_id=PLACE_ID,
interval='year',
d1='2008-01-01',
d2=f'{YEAR}-12-31',
verifiable=True,
)
observations_by_year = pd.DataFrame(
[{'date': k, 'observations': v} for k, v in observations_by_year.items()]
)
alt.Chart(observations_by_year).mark_bar().encode(x='year(date):T', y='observations:Q')
alt.Chart(...)
[2]:
Observations per month¶
[3]:
observations_by_month = get_observation_histogram(
place_id=PLACE_ID,
interval='month',
d1='2020-01-02',
d2='2020-12-31',
verifiable=True,
)
observations_by_month = pd.DataFrame(
[{'metric': 'Observations', 'date': k, 'count': v} for k, v in observations_by_month.items()]
)
alt.Chart(observations_by_month).mark_bar().encode(x='month(date):T', y='count:Q')
alt.Chart(...)
[3]:
Histograms with custom metrics¶
The API does not have a histogram endpoint for taxa observed, observers, or identifiers, so we first need to determine our date ranges of interest, and then run one search per date range.
Here are a couple helper functions to make this easier:
[4]:
def count_date_range_results(function, start_date, end_date):
"""Get the count of results for the given date range and search function"""
# Running this search with per_page=0 will (quickly) return only a count of results, not complete results
response = function(
place_id=PLACE_ID,
d1=start_date,
d2=end_date,
verifiable=True,
per_page=0,
)
print(f'Total results for {start_date.strftime("%b")}: {response["total_results"]}')
return response['total_results']
def get_monthly_counts(function, label):
"""Get the count of results per month for the given search function"""
month_ranges = get_interval_ranges(datetime(YEAR, 1, 1), datetime(YEAR, 12, 31), 'month')
counts_by_month = {
start_date: count_date_range_results(function, start_date, end_date)
for (start_date, end_date) in month_ranges
}
return pd.DataFrame(
[{'metric': label, 'date': k, 'count': v} for k, v in counts_by_month.items()]
)
Unique taxa observed per month¶
[5]:
taxa_by_month = get_monthly_counts(get_observation_species_counts, 'Taxa')
alt.Chart(taxa_by_month).mark_bar().encode(x='month(date):T', y='count:Q')
Total results for Jan: 189
Total results for Feb: 196
Total results for Mar: 329
Total results for Apr: 836
Total results for May: 1370
Total results for Jun: 1547
Total results for Jul: 1756
Total results for Aug: 1618
Total results for Sep: 1289
Total results for Oct: 669
Total results for Nov: 419
Total results for Dec: 617
alt.Chart(...)
[5]:
Observers per month¶
[6]:
observers_by_month = get_monthly_counts(get_observation_observers, 'Observers')
alt.Chart(observers_by_month).mark_bar().encode(x='month(date):T', y='count:Q')
Total results for Jan: 38
Total results for Feb: 46
Total results for Mar: 77
Total results for Apr: 148
Total results for May: 372
Total results for Jun: 484
Total results for Jul: 559
Total results for Aug: 594
Total results for Sep: 423
Total results for Oct: 186
Total results for Nov: 92
Total results for Dec: 61
alt.Chart(...)
[6]:
Identifiers per month¶
[7]:
identifiers_by_month = get_monthly_counts(get_observation_identifiers, 'Identifiers')
alt.Chart(identifiers_by_month).mark_bar().encode(x='month(date):T', y='count:Q')
Total results for Jan: 147
Total results for Feb: 166
Total results for Mar: 204
Total results for Apr: 400
Total results for May: 680
Total results for Jun: 688
Total results for Jul: 752
Total results for Aug: 720
Total results for Sep: 570
Total results for Oct: 367
Total results for Nov: 240
Total results for Dec: 257
alt.Chart(...)
[7]:
Combine all monthly metrics into one plot¶
[8]:
combined_results = observations_by_month.append(
[taxa_by_month, observers_by_month, identifiers_by_month]
)
alt.Chart(
combined_results,
title=f'iNaturalist activity in {PLACE_NAME} ({YEAR})',
width=750,
height=500,
).mark_line().encode(
alt.X('month(date):T', axis=alt.Axis(title="Month")),
alt.Y('count:Q', axis=alt.Axis(title="Count")),
color='metric',
strokeDash='metric',
).configure_axis(
labelFontSize=15,
titleFontSize=20,
)
alt.Chart(...)
[8]: