Local supporter

Categorize species from classifications

by | Jun 20, 2025 | How To, Learn, Paradigm

When I got my species list from GBIF, they came with their biological classifications of Kingdom, Phylum, Class, Order, Family, and Genus. None of those told me whether a Coragyps atratus was a plant, animal, or amoeba. I searched and read about 10 web pages about biological classifications and still could not align those terms with my categories. I asked ChatGPT for help, expecting something like a T-chart. What I got was another round of Apps Script. And by another round, I mean another ten rounds of tweaking code that ChatGPT swore was the final solution.

Nevertheless, I could hug ChatGPT for saving me from biology madness. Here’s the script that worked, except that shellfish became mammals because even ChatGPT didn’t know their classification:

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu("Species Tools")
    .addItem("Categorize Next Batch", "categorizeSpeciesBatch")
    .addToUi();
}

function categorizeSpeciesBatch() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const maxRowsPerRun = 50; // adjust to suit execution time
  let rowsProcessed = 0;

  for (let i = 1; i < data.length; i++) {
    const taxonUrl = data[i][2]; // Column C = iNaturalist taxon URL
    const categoryCell = sheet.getRange(i + 1, 7); // Column G = category

    if (categoryCell.getValue()) continue; // Skip if already categorized

    const match = taxonUrl.match(/taxa\/(\d+)/);
    if (!match) continue;

    const taxonId = match[1];
    try {
      const response = UrlFetchApp.fetch(`https://api.inaturalist.org/v1/taxa/${taxonId}`);
      const json = JSON.parse(response.getContentText());
      const iconic = json.results[0]?.iconic_taxon_name?.toLowerCase() || "";

      let category = "";

      switch (iconic) {
        case "plantae":
          category = "Plants";
          break;
        case "aves":
          category = "Birds";
          break;
        case "reptilia":
        case "amphibia":
          category = "Reptiles & Amphibians";
          break;
        case "actinopterygii":
        case "chondrichthyes":
          category = "Fish";
          break;
        case "insecta":
        case "arachnida":
        case "myriapoda":
          category = "Bugs";
          break;
        case "mammalia":
        default:
          category = "Mammals";
      }

      categoryCell.setValue(category);
      rowsProcessed++;
      Utilities.sleep(1000); // pause to respect API rate limits

      if (rowsProcessed >= maxRowsPerRun) break;
    } catch (e) {
      Logger.log(`Error at row ${i + 1}: ${e.message}`);
    }
  }

  SpreadsheetApp.getUi().alert(`Processed ${rowsProcessed} rows. Run again to continue.`);
}

As usual, AI requires human oversight. I brought my species list back to Excel to give it a look-see. I sorted it by every single biological classification in hierarchical order. That lineup really exposed the need for a human touch. For example, only FOUR spiders made the cut when I saved only species that had been reported at least 10 times. How can I see Hunstman spiders all summer long at GTM and they don’t get reported? Meanwhile, I count at least THIRTEEN different species of mosquitos?! Yep, this list is just a starting point.

Back to categorizing these critters. The “Reptiles & Amphibians” title feels like two categories. I changed all occurrences of that title to “Herps”. Also, I could see that some Arthropods are bugs and some Arthropods are fish. Are crabs fish? I’m going with fish, since they’re in FWC’s Fish Rules app. I changed ChatGPT’s default Mammals to Fish for the crabs.

I will continue to tweak my species list. For now, it’s time to load these babies into WordPress.

Questions? Suggestions? Send me a note.

7 + 6 =