<jupyter_start><jupyter_text>[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/niconoe/pyinaturalist/main?filepath=examples%2FData%2520Visualizations%2520-%2520Regional%2520Activity%2520Report.ipynb)  Regional activity time series visualizationsThis 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](https://altair-viz.github.io), with the following metrics:* Number of observations* Number of taxa observed* Number of observers* Number of identifiers<jupyter_code>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<jupyter_output><empty_output><jupyter_text>Observations per year![observations_by_year.png](attachment:33d81806-a688-4fcf-b278-537fff262835.png)<jupyter_code>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')<jupyter_output><empty_output><jupyter_text>Observations per month![observations_by_month.png](attachment:840647ed-7e77-487c-bd37-3ec486b892f2.png)<jupyter_code>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')<jupyter_output><empty_output><jupyter_text>Histograms with custom metricsThe 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:<jupyter_code>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()]
    )<jupyter_output><empty_output><jupyter_text>Unique taxa observed per month![taxa_by_month.png](attachment:884fc13d-ab11-4598-afc2-51cd26bc3ac1.png)<jupyter_code>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')<jupyter_output>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<jupyter_text>Observers per month![observers_by_month.png](attachment:0d1b739a-5b48-45fd-8dd8-da77e7a1dbb5.png)<jupyter_code>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')<jupyter_output>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<jupyter_text>Identifiers per month![identifiers_by_month.png](attachment:577562d8-828a-40ed-b19a-fd1b77573af7.png)<jupyter_code>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')<jupyter_output>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<jupyter_text>Combine all monthly metrics into one plot![combined_activity_stats.png](attachment:47837a56-463a-44d9-918f-561037883070.png)<jupyter_code>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,
)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10748433893834487, 'fraction_numerical': 0.0520936366633696, 'mean_word_length': 6.013872832369942, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 30, 'https://': 4, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '213783', 'license': 'MIT', 'n_tokens_mistral': 2281, 'n_tokens_neox': 2053, 'n_words': 497, 'path': 'examples/Data Visualizations - Regional Activity Report.ipynb', 'repo_name': 'niconoe/pyinaturalist', 'size': '6066'}