$ \ifdefined\HCode % we are running tex4ht % don't load the physics package \require{physics} % \require{siunitx} \else % we are running LaTeX % \usepackage{physics} \fi \renewcommand{\phi}{\varphi} \renewcommand{\epsilon}{\varepsilon} \newcommand\define[1]{\textbf{#1}\index{#1}} % Letters/Font \DeclareMathOperator{\bF}{\mathbb{F}} \DeclareMathOperator{\bQ}{\mathbb{Q}} \DeclareMathOperator{\bZ}{\mathbb{Z}} \DeclareMathOperator{\bR}{\mathbb{R}} \DeclareMathOperator{\bC}{\mathbb{C}} \DeclareMathOperator{\bE}{\mathbb{E}} \DeclareMathOperator{\bN}{\mathbb{N}} \DeclareMathOperator{\bM}{\mathbb{M}} \DeclareMathOperator{\bH}{\mathbb{H}} \DeclareMathOperator{\bP}{\mathbb{P}} \DeclareMathOperator{\cH}{\mathcal{H}} \DeclareMathOperator{\cA}{\mathcal{A}} \DeclareMathOperator{\cB}{\mathcal{B}} \DeclareMathOperator{\cC}{\mathcal{C}} \newcommand\bb[1]{\mathbb{#1}} \newcommand\mc[1]{\mathcal{#1}} \newcommand{\w}[1]{\wedge#1} \newcommand\mean[1]{\bar{#1}} \newcommand\conj[1]{\bar{#1}} \DeclareMathOperator*{\argmin}{arg\,min} \DeclareMathOperator*{\argmax}{arg\,max} % Grouping Operators \newcommand{\floor}[1]{\left\lfloor#1\right\rfloor} \newcommand{\ceil}[1]{\left\lceil#1\right\rceil} \newcommand{\parens}[1]{\left(#1\right)} % note that we defined bracks not brace/braces because brace is already used by amsmath \newcommand{\bracks}[1]{\left\{#1\right\}} \newcommand{\sqbracks}[1]{\left[#1\right]} \newcommand{\clop}[1]{\left[#1\right)} \newcommand{\opcl}[1]{\left(#1\right]} \newcommand{\angles}[1]{\langle#1\rangle} \newcommand{\p}[1]{\left(#1\right)} % \newcommand{\b}[1]{\left\{#1\right\}} \newcommand{\q}[1]{\left[#1\right]} \newcommand{\abs}[1]{\left|#1\right|} \newcommand{\n}[1]{\left\lVert#1\right\rVert} % probability \DeclareMathOperator{\Cov}{Cov} \DeclareMathOperator{\Var}{Var} \DeclareMathOperator{\Cor}{Cor} \DeclareMathOperator{\median}{median} % https://tex.stackexchange.com/questions/154530/resolved-a-conditional-independence-symbol-that-looks-good-with-mid \newcommand{\ind}{\mathrel{\text{\scalebox{1.07}{$\perp\mkern-10mu\perp$}}}} % or \newcommand{\ind}{\perp\!\!\!\!\perp} % now included in the physics package %\newcommand{\norm}[1]{\left\lVert#1\right\rVert} \DeclareMathOperator{\Bias}{Bias} \DeclareMathOperator{\Range}{Range} % linear algebra \DeclareMathOperator{\nullity}{nullity} \DeclareMathOperator{\rowrank}{row rank} \DeclareMathOperator{\colrank}{column rank} % now in the physics package % \DeclareMathOperator{\tr}{Tr} % \DeclareMathOperator{\Tr}{Tr} \DeclareMathOperator{\perm}{perm} \DeclareMathOperator{\GL}{GL} \DeclareMathOperator{\SL}{SL} \DeclareMathOperator{\imm}{imm} \DeclareMathOperator{\poly}{poly} \DeclareMathOperator{\Lie}{Lie} \DeclareMathOperator{\Cl}{Cl} \DeclareMathOperator{\Span}{span} \DeclareMathOperator{\Int}{int} \DeclareMathOperator{\adj}{adj} % abstract algebra \DeclareMathOperator{\Aut}{Aut} \DeclareMathOperator{\id}{id} \DeclareMathOperator{\Id}{Id} \DeclareMathOperator{\Inn}{Inn} \DeclareMathOperator{\irr}{irr} \DeclareMathOperator{\Frac}{Frac} \DeclareMathOperator{\Frob}{Frob} % category theory \DeclareMathOperator{\ob}{ob} \DeclareMathOperator{\Set}{Set} \DeclareMathOperator{\Grp}{Grp} \DeclareMathOperator{\Ring}{Ring} \DeclareMathOperator{\Top}{Top} \DeclareMathOperator{\Vect}{Vect} \DeclareMathOperator{\End}{End} \DeclareMathOperator{\Hom}{Hom} \DeclareMathOperator{\im}{im} % \DeclareMathOperator{\Vec}{Vec} \DeclareMathOperator{\Rel}{Rel} \DeclareMathOperator{\Mon}{Mon} \DeclareMathOperator{\Pre}{Pre} \DeclareMathOperator{\SRel}{SRel} \DeclareMathOperator{\Ab}{Ab} \DeclareMathOperator{\Perm}{Perm} \DeclareMathOperator{\Nat}{Nat} \DeclareMathOperator{\Cat}{Cat} % now in physics package % \DeclareMathOperator{\op}{op} \DeclareMathOperator{\FinStoch}{FinStoch} \DeclareMathOperator{\Stoch}{Stoch} % number theory \DeclareMathOperator{\rad}{rad} \DeclareMathOperator{\Disc}{Disc} \DeclareMathOperator{\res}{res} \DeclareMathOperator{\lcm}{lcm} % differential geometry \DeclareMathOperator{\Man}{Man} \DeclareMathOperator{\supp}{supp} \DeclareMathOperator{\Diff}{Diff} \DeclareMathOperator{\VB}{VB} % complexity theory \DeclareMathOperator{\fspace}{FSPACE} \DeclareMathOperator{\sspace}{SPACE} \DeclareMathOperator{\pspace}{PSPACE} \DeclareMathOperator{\AR}{AR} \DeclareMathOperator{\MA}{MA} \DeclareMathOperator{\B}{B} \DeclareMathOperator{\ARMA}{ARMA} \DeclareMathOperator{\diag}{diag} \DeclareMathOperator{\IMA}{IMA} \DeclareMathOperator{\ARIMA}{ARIMA} \DeclareMathOperator{\Vol}{Vol} \DeclareMathOperator{\essup}{essup} \DeclareMathOperator{\essinf}{essinf} \DeclareMathOperator{\Bernoulli}{Bernoulli} \DeclareMathOperator{\Law}{Law} \DeclareMathOperator{\Normal}{Normal} \DeclareMathOperator{\Geometric}{Geometric} \DeclareMathOperator{\Poisson}{Poisson} \DeclareMathOperator{\Uniform}{Uniform} \DeclareMathOperator{\Beta}{Beta} \DeclareMathOperator{\TV}{TV} \DeclareMathOperator{\io}{i.o.} \DeclareMathOperator{\ale}{a.e.} \DeclareMathOperator{\as}{a.s.} \DeclareMathOperator{\iid}{i.i.d.} % least fixed point \DeclareMathOperator{\lfp}{lfp} \DeclareMathOperator{\sign}{sign} \DeclareMathOperator{\pval}{p.v.} \DeclareMathOperator{\sgn}{sgn} \DeclareMathOperator{\dom}{dom} \DeclareMathOperator{\Ran}{Ran} \DeclareMathOperator{\Hol}{Hol} \DeclareMathOperator{\cl}{cl} \DeclareMathOperator{\Pol}{Pol} \DeclareMathOperator{\sinc}{sinc} \DeclareMathOperator{\E}{\mathbb{E}} \DeclareMathOperator{\Pr}{\mathbb{P}} \DeclareMathOperator{\R}{\mathbb{R}} $

Using iNaturalist, Obsidian, and Anki to learn plant taxonomy

Published: 27 Jun 2025

Last updated: 27 Jun 2025

Categories Tags

Using iNaturalist, Obsidian, and Anki to learn plant taxonomy

Obsidian graph of taxonomy notes
My Obsidian taxonomy notes 1.

I wanted to share a workflow that other people might also find useful for learning taxonomy with Obsidian and Anki. I have had a very casual interest in learning the names of local native plants for years, and I found a pretty straightforward way I wanted to document here.

Step 1: Find a species of interest & learn about it

If you want to start from your local neighborhood, the first step is finding plants nearby you, uploading them to iNaturalist, and getting confirmation of their identity by local enthusiasts. After doing this, ideally read about the species on Wikipedia to have more semantic memory of it, and keep the Wikipedia page open for adding a note about it to your vault.

Step 2: Add an Obsidian note for the species

I use Obsidian to keep track of the notes in my vault, but the important part that enables this workflow to work is just having a local note for each taxon.

Note structure

In my vault, I have a directory called life/, in which all files are Markdown notes of some taxonomic level. Files are named in the format {Rank} {Name}.md, e.g. life/Kingdom Animalia.md. I keep nodes for anything Kingdom level and above (so Domain, a few Clades, and some Unranked levels) in this directory. Within life/, I have a subdirectory for each kingdom-level taxonomic group, named like life/animalia/. This is because taxonomic names are unique at the kingdom level, but not above that. I store nodes for anything below the Kingdom level within its corresponding Kingdom subdirectory, and the I have nodes that fill in to make something almost a tree (see Step 3 below).

Within the Markdown file for a taxon, I link to subtaxa with a YAML child node. For example, here is my Genus Monotropa.md note:

---
aliases:
  - 水晶蘭屬
child:
  - "[[life/plantae/Species Monotropa uniflora|Species Monotropa uniflora]]"
  - "[[life/plantae/Species Monotropa hypopitys|Species Monotropa hypopitys]]"
role: "[[wiki/mycoheterotroph|mycoheterotroph]]"
etymology: "Greek monos, 'single,' and tropos, 'a turn' or trope, 'a turning,'"
created: 2024-08-25T22:18:57-04:00
modified: 2025-01-03T06:40:54-05:00
---

I only include additional information outside the YAML sometimes. I have child registered to form a hierarchy with the Obsidian Breadcrumbs plugin, which lets me conveniently view the tree without having to render it with an outside script.

Leaf nodes that I intend to make into cards have image YAML fields that I use to identify them in my script mentioned below in Step 3. For example, here’s the note for Species Monotropa uniflora.md:

---
aliases: 水晶蘭, ghost pipe
child:
image: "[[external/ALL_PHOTOS/2024/08/20240824_141830.jpg]]"
tags: inat, anki
---

[[life/fungi/Family Russulaceae|Family Russulaceae]]

I previously used the tags to also identify which Markdown notes I wanted to make into Anki notes, but now I just use the image blanks.

Adding notes / building the tree

To find information about the taxon levels, I use a mix of Wikipedia, then Wikispecies, and, if necessary, outside resources. This is usually pretty simple, and I’ve thought about writing a script to directly pull the info from Wikimedia to add the notes. For maybe 5% of notes, though, there is some discrepancy that makes this a bit harder.

For these reasons, I haven’t written the script yet, but it wouldn’t be hard to do.

Step 3: Convert the Markdown notes to a CSV with a script

I have the script in this gist in the vault directory scripts/ , and I run it from the root. The script first tries to build an “pseudo-tree” from the note structure. I call it a pseudo-tree because there are some hybrids like Graptosedum ‘Francesco Baldi’ that are hybrids of plants in two different genera. Besides these exceptions, to make it a tree, I also added nodes for Unranked Life, Unranked Virus, and Unranked Replicators to allow viruses to be part of the tree as well since that made the code simpler 😬

The code does a few checks like that there are no orphan nodes not part of the pseudo-tree as well. I run the script whenever I’ve added enough new notes that I want Anki cards for them. The script produces a CSV containing the taxon’s scientific name, common names, image, rank, genus, and family. The family blank actually also includes subfamily, tribe, etc in it, but I would separate these out if I wanted to drill them individually; in reviewing, I grade myself on knowing the family name.

Script:

I use an external script here rather than a plugin like Obsidian_to_Anki for two reasons. First, I wanted to get images linked in the YAML into the generated Anki cards, and this didn’t seem possible with the plugin. Second, an external script can get ancestral information about the cards, such as the family name.

Step 4: Import the CSV into Anki and study the cards

I produce two cards from each note, one to learn the species (or genus) name, and another to learn the family name. As will be mentioned in Step 5, the family name is important to learn because families have shared characteristics useful for identification.

The taxonomy note fields match the CSV fields

  1. scientific_name
  2. common_names
  3. image
  4. rank
  5. genus
  6. family

Card 1 front

{{image}}

Card 1 back

{{FrontSide}}
<hr id=answer>
{{scientific_name}}
<br>
{{common_names}}
<br>
{{rank}}
<br>
{{genus}}
<br>
{{family}}

Card 2 front

{{scientific_name}}
<br>
{{common_names}}
<br>
{{image}}

Card 2 back

{{FrontSide}}
<hr id=answer>
{{rank}}
<br>
{{genus}}
<br>
{{family}}

Also, I should add that I have only been doing the Anki cards for plants thus far. I anticipate learning the species/genus names for fungi and maybe animals as well, but not their family names.

Step 5: Learn info about the family level after learning about several member species/genera

The family level is the level at which botanists can generally recognize plants previously unknown to them. I find it useful to know a few member species prior to learning the characteristics of families in order to give the family more semantic meaning, just as it’s useful in learning category theory to know a few examples from math before generalizing them. A good resource for learning about native family characteristics in North America is Elpel’s Botany in a Day.

Footnotes

  1. A more powerful graph renderer would show this as a tree with only a couple of exceptions. Maybe I’ll render it dynamically here in the future? 

  2. I try to get taxon names in both English and Chinese 

  3. Also, some subfamilies were originally their own families. Elpel, the text mentioned below in Step 5, still lists the old names in some cases, and I wanted to include the characteristics he mentions in the subfamily notes.