{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1885a594",
   "metadata": {},
   "source": [
    "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/niconoe/pyinaturalist/main?filepath=examples%2FData%2520Visualizations%2520-%2520Regional%2520Observation%2520Stats.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "separate-stylus",
   "metadata": {},
   "source": [
    "# Regional observation stats\n",
    "\n",
    "This example shows how to get some general statistics on all observations in a given region.\n",
    "See https://www.inaturalist.org/places to find place IDs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "thirty-banking",
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import sleep\n",
    "\n",
    "import altair as alt\n",
    "import pandas as pd\n",
    "from IPython.display import Image\n",
    "from pyinaturalist import (\n",
    "    get_observations,\n",
    "    get_observation_species_counts,\n",
    "    get_observation_observers,\n",
    "    get_observation_identifiers,\n",
    ")\n",
    "from pyinaturalist.constants import ICONIC_TAXA\n",
    "\n",
    "\n",
    "# Adjustable values\n",
    "PLACE_ID = 6\n",
    "PLACE_NAME = 'Alaska'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "touched-fusion",
   "metadata": {},
   "source": [
    "### General stats\n",
    "Total observations, unique taxa, identifiers, and observers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "indirect-authority",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total observations: 160888\n",
      "Total taxa observed: 5868\n",
      "Total identifiers: 5003\n",
      "Total observers: 5972\n"
     ]
    }
   ],
   "source": [
    "total_observations = get_observations(\n",
    "    place_id=PLACE_ID,\n",
    "    verifiable=True,\n",
    "    per_page=0,\n",
    ")['total_results']\n",
    "print(f'Total observations: {total_observations}')\n",
    "\n",
    "total_taxa = get_observation_species_counts(\n",
    "    place_id=PLACE_ID,\n",
    "    verifiable=True,\n",
    "    per_page=0,\n",
    ")['total_results']\n",
    "print(f'Total taxa observed: {total_taxa}')\n",
    "\n",
    "total_identifiers = get_observation_identifiers(place_id=PLACE_ID, per_page=0)['total_results']\n",
    "print(f'Total identifiers: {total_identifiers}')\n",
    "\n",
    "total_observers = get_observation_observers(place_id=PLACE_ID, per_page=0)['total_results']\n",
    "print(f'Total observers: {total_observers}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "outside-airline",
   "metadata": {},
   "source": [
    "### Stats by iconic taxon\n",
    "Show a breakdown of observations and taxa observed for each of the iconic taxa (major species groups), using their corresponding icons on iNaturalist.\n",
    "Here are a couple helper functions to make this easier:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "preceding-divide",
   "metadata": {},
   "outputs": [],
   "source": [
    "THROTTLING_DELAY = 1.0  # Time to wait in between subsequent requests\n",
    "TAXON_IMAGE_URL = 'https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/{taxon}-75px.png'\n",
    "iconic_taxa = list(ICONIC_TAXA.values())\n",
    "iconic_taxa.remove('Unknown')\n",
    "\n",
    "\n",
    "# Run one search for each iconic taxon\n",
    "def get_iconic_taxa_counts(function):\n",
    "    iconic_taxa_counts = {}\n",
    "    for taxon_name in iconic_taxa:\n",
    "        total_taxon_observations = function(\n",
    "            place_id=PLACE_ID,\n",
    "            iconic_taxa=taxon_name,\n",
    "            verifiable=True,\n",
    "            per_page=0,\n",
    "        )['total_results']\n",
    "\n",
    "        iconic_taxa_counts[taxon_name] = total_taxon_observations\n",
    "        print(f'Total results for {taxon_name}: {total_taxon_observations}')\n",
    "        if taxon_name != iconic_taxa[-1]:\n",
    "            sleep(THROTTLING_DELAY)\n",
    "    return iconic_taxa_counts\n",
    "\n",
    "\n",
    "def get_iconic_icon(taxon_name):\n",
    "    return TAXON_IMAGE_URL.format(taxon=taxon_name.lower())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "medium-joining",
   "metadata": {},
   "source": [
    "#### Observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "interim-republic",
   "metadata": {
    "scrolled": true,
    "tags": [
     "nbsphinx-thumbnail"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total results for Animalia: 9427\n",
      "Total results for Aves: 28266\n",
      "Total results for Amphibia: 380\n",
      "Total results for Reptilia: 4\n",
      "Total results for Mammalia: 9825\n",
      "Total results for Actinopterygii: 2215\n",
      "Total results for Mollusca: 5810\n",
      "Total results for Arachnida: 1882\n",
      "Total results for Insecta: 17786\n",
      "Total results for Plantae: 63246\n",
      "Total results for Fungi: 20499\n",
      "Total results for Chromista: 951\n",
      "Total results for Protozoa: 479\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<div id=\"altair-viz-42bc8a999cab44a4b9dcf7bb1c0b513f\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-42bc8a999cab44a4b9dcf7bb1c0b513f\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-42bc8a999cab44a4b9dcf7bb1c0b513f\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm//vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm//vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm//vega-lite@4.8.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm//vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function loadScript(lib) {\n",
       "      return new Promise(function(resolve, reject) {\n",
       "        var s = document.createElement('script');\n",
       "        s.src = paths[lib];\n",
       "        s.async = true;\n",
       "        s.onload = () => resolve(paths[lib]);\n",
       "        s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "        document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "      });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else if (typeof vegaEmbed === \"function\") {\n",
       "      displayChart(vegaEmbed);\n",
       "    } else {\n",
       "      loadScript(\"vega\")\n",
       "        .then(() => loadScript(\"vega-lite\"))\n",
       "        .then(() => loadScript(\"vega-embed\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 400, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-ec7b64f503479131e91eb7ed862c19fd\"}, \"mark\": \"image\", \"encoding\": {\"url\": {\"type\": \"nominal\", \"field\": \"img\"}, \"x\": {\"type\": \"nominal\", \"field\": \"iconic taxon\", \"sort\": \"-y\"}, \"y\": {\"type\": \"quantitative\", \"field\": \"observations\"}}, \"height\": 500, \"title\": \"Verifiable observations in Alaska by iconic taxon\", \"width\": 750, \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.8.1.json\", \"datasets\": {\"data-ec7b64f503479131e91eb7ed862c19fd\": [{\"iconic taxon\": \"Animalia\", \"observations\": 9427, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/animalia-75px.png\"}, {\"iconic taxon\": \"Aves\", \"observations\": 28266, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/aves-75px.png\"}, {\"iconic taxon\": \"Amphibia\", \"observations\": 380, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/amphibia-75px.png\"}, {\"iconic taxon\": \"Reptilia\", \"observations\": 4, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/reptilia-75px.png\"}, {\"iconic taxon\": \"Mammalia\", \"observations\": 9825, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/mammalia-75px.png\"}, {\"iconic taxon\": \"Actinopterygii\", \"observations\": 2215, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/actinopterygii-75px.png\"}, {\"iconic taxon\": \"Mollusca\", \"observations\": 5810, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/mollusca-75px.png\"}, {\"iconic taxon\": \"Arachnida\", \"observations\": 1882, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/arachnida-75px.png\"}, {\"iconic taxon\": \"Insecta\", \"observations\": 17786, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/insecta-75px.png\"}, {\"iconic taxon\": \"Plantae\", \"observations\": 63246, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/plantae-75px.png\"}, {\"iconic taxon\": \"Fungi\", \"observations\": 20499, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/fungi-75px.png\"}, {\"iconic taxon\": \"Chromista\", \"observations\": 951, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/chromista-75px.png\"}, {\"iconic taxon\": \"Protozoa\", \"observations\": 479, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/protozoa-75px.png\"}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total_observations_by_iconic_taxon = get_iconic_taxa_counts(get_observations)\n",
    "\n",
    "# Create a chart, sorted by number of observations, using the appropriate iNaturalist icons\n",
    "observations_df = pd.DataFrame([\n",
    "    {'iconic taxon': k, 'observations': v, 'img': get_iconic_icon(k)}\n",
    "    for k, v in total_observations_by_iconic_taxon.items()\n",
    "])\n",
    "alt.Chart(\n",
    "    observations_df,\n",
    "    title=f'Verifiable observations in {PLACE_NAME} by iconic taxon',\n",
    "    width=750,\n",
    "    height=500,\n",
    ").mark_image().encode(\n",
    "    x=alt.X('iconic taxon:N', sort='-y'),\n",
    "    y='observations:Q',\n",
    "    url='img'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "unlikely-mongolia",
   "metadata": {},
   "source": [
    "#### Taxa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "hybrid-investor",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total results for Animalia: 550\n",
      "Total results for Aves: 346\n",
      "Total results for Amphibia: 7\n",
      "Total results for Reptilia: 2\n",
      "Total results for Mammalia: 80\n",
      "Total results for Actinopterygii: 143\n",
      "Total results for Mollusca: 295\n",
      "Total results for Arachnida: 131\n",
      "Total results for Insecta: 1196\n",
      "Total results for Plantae: 1791\n",
      "Total results for Fungi: 1195\n",
      "Total results for Chromista: 96\n",
      "Total results for Protozoa: 26\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<div id=\"altair-viz-ab7e6aad620949649ec1c01aeea6bea4\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-ab7e6aad620949649ec1c01aeea6bea4\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-ab7e6aad620949649ec1c01aeea6bea4\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm//vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm//vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm//vega-lite@4.8.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm//vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function loadScript(lib) {\n",
       "      return new Promise(function(resolve, reject) {\n",
       "        var s = document.createElement('script');\n",
       "        s.src = paths[lib];\n",
       "        s.async = true;\n",
       "        s.onload = () => resolve(paths[lib]);\n",
       "        s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "        document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "      });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else if (typeof vegaEmbed === \"function\") {\n",
       "      displayChart(vegaEmbed);\n",
       "    } else {\n",
       "      loadScript(\"vega\")\n",
       "        .then(() => loadScript(\"vega-lite\"))\n",
       "        .then(() => loadScript(\"vega-embed\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 400, \"continuousHeight\": 300}}, \"data\": {\"name\": \"data-8b8c0ae60a628974b6b10136c4df2e0e\"}, \"mark\": \"image\", \"encoding\": {\"url\": {\"type\": \"nominal\", \"field\": \"img\"}, \"x\": {\"type\": \"nominal\", \"field\": \"iconic taxon\", \"sort\": \"-y\"}, \"y\": {\"type\": \"quantitative\", \"field\": \"unique taxa\"}}, \"height\": 500, \"title\": \"Unique taxa observed in Alaska by iconic taxon\", \"width\": 750, \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.8.1.json\", \"datasets\": {\"data-8b8c0ae60a628974b6b10136c4df2e0e\": [{\"iconic taxon\": \"Animalia\", \"unique taxa\": 550, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/animalia-75px.png\"}, {\"iconic taxon\": \"Aves\", \"unique taxa\": 346, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/aves-75px.png\"}, {\"iconic taxon\": \"Amphibia\", \"unique taxa\": 7, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/amphibia-75px.png\"}, {\"iconic taxon\": \"Reptilia\", \"unique taxa\": 2, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/reptilia-75px.png\"}, {\"iconic taxon\": \"Mammalia\", \"unique taxa\": 80, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/mammalia-75px.png\"}, {\"iconic taxon\": \"Actinopterygii\", \"unique taxa\": 143, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/actinopterygii-75px.png\"}, {\"iconic taxon\": \"Mollusca\", \"unique taxa\": 295, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/mollusca-75px.png\"}, {\"iconic taxon\": \"Arachnida\", \"unique taxa\": 131, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/arachnida-75px.png\"}, {\"iconic taxon\": \"Insecta\", \"unique taxa\": 1196, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/insecta-75px.png\"}, {\"iconic taxon\": \"Plantae\", \"unique taxa\": 1791, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/plantae-75px.png\"}, {\"iconic taxon\": \"Fungi\", \"unique taxa\": 1195, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/fungi-75px.png\"}, {\"iconic taxon\": \"Chromista\", \"unique taxa\": 96, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/chromista-75px.png\"}, {\"iconic taxon\": \"Protozoa\", \"unique taxa\": 26, \"img\": \"https://raw.githubusercontent.com/inaturalist/inaturalist/main/app/assets/images/iconic_taxa/protozoa-75px.png\"}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.Chart(...)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total_taxa_by_iconic_taxon = get_iconic_taxa_counts(get_observation_species_counts)\n",
    "\n",
    "# Create a chart, sorted by number of observations, using the appropriate iNaturalist icons\n",
    "taxa_df = pd.DataFrame([\n",
    "    {'iconic taxon': k, 'unique taxa': v, 'img': get_iconic_icon(k)}\n",
    "    for k, v in total_taxa_by_iconic_taxon.items()\n",
    "])\n",
    "alt.Chart(\n",
    "    taxa_df,\n",
    "    title=f'Unique taxa observed in {PLACE_NAME} by iconic taxon',\n",
    "    width=750,\n",
    "    height=500,\n",
    ").mark_image().encode(\n",
    "    x=alt.X('iconic taxon:N', sort='-y'),\n",
    "    y='unique taxa:Q',\n",
    "    url='img'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "historical-friendship",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 33836 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Including the rendered image so the chart will display outside Jupyter, e.g. on GitHub's notebook viewer\n",
    "Image('images/total_observations_by_iconic_taxon.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "architectural-temperature",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 34196 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image('images/total_taxa_by_iconic_taxon.png')"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
