ToothNotation
Convert between dental tooth-numbering systems — FDI (ISO 3950), Universal, and Palmer — with one source of truth and 293 verifying tests.
Tooth numbering is a perennial source of error and re-implementation in dental software: the US uses the Universal system (1–32, A–T), most of the world uses FDI / ISO 3950 (two-digit quadrant codes), and clinicians often chart in Palmer notation. Every project that touches teeth ends up rewriting these conversions, usually with subtle off-by-one and inverted-quadrant bugs.
ToothNotation does it once, correctly, with FDI as the canonical internal key — so every conversion is derived from a single representation rather than a tangle of pairwise lookup tables. It ships as a small dependency-free Python package, a CLI, and an interactive React odontogram you can drop into a teaching site or chart UI.
from toothnotation import convert, parse
convert("36", "fdi", "universal") # "19"
convert("19", "universal", "fdi") # "36"
convert("UR6", "palmer", "universal") # "3"
t = parse("36") # auto-detects the system
t.name # "lower left first molar"
t.universal # "19"
str(t.palmer) # "LL6"
t.dentition, t.arch # ("permanent", "lower")
Why trust it
Tooth maps are easy to get wrong, so correctness is the whole point of the library:
- FDI-canonical design. Every system parses to an FDI code and every output is derived from it. There is exactly one source of truth, not six pairwise maps to keep in sync.
- 293 tests, including every one of the 52 teeth round-tripped through all
three systems (
FDI → system → FDImust return the original). This catches any off-by-one or inverted quadrant across the whole dentition, not just spot checks. - Hand-verified anchors against ISO 3950 and ADA references (e.g. FDI
11= Universal8= PalmerUR1; FDI48= Universal32).
$ pytest -q
293 passed
Install
pip install toothnotation
No runtime dependencies. Python 3.9+.
Use it
Python
from toothnotation import convert, parse, all_teeth, detect_system
detect_system("19") # "universal" (not a valid FDI code)
detect_system("36") # "fdi"
detect_system("UR6") # "palmer"
[t.universal for t in all_teeth("primary")] # ['A', 'B', ... 'T']
tooth = parse("65")
tooth.name # "upper left second primary molar"
tooth.tooth_type # "second primary molar"
The Tooth object exposes fdi, universal, palmer, name, quadrant,
arch, side, dentition, tooth_type, and position (counting from the
midline), plus .to("fdi" | "universal" | "palmer").
Command line
toothnotation convert 36 fdi universal # 19
toothnotation info UR6 # full detail, auto-detected
toothnotation chart --system universal # print the chart
Interactive chart (React)
toothchart.jsx is a self-contained component — an anatomically arranged
odontogram that displays any of the three systems, lets you click a tooth for full
detail, and converts codes live. Palmer brackets are drawn the way they appear on a
paper chart (the quadrant corner is marked with real borders, not an approximated
glyph). The conversion logic is ported from the Python package and verified with
the same round-trip checks.
Drop it into a teaching site, a charting UI, or a patient-education page.
The three systems, briefly
| System | Permanent | Primary | Example (lower-left first molar) |
|---|---|---|---|
| FDI (ISO 3950) | 11–48 (quadrant + position) |
51–85 |
36 |
| Universal (US) | 1–32 |
A–T |
19 |
| Palmer | quadrant + 1–8 |
quadrant + A–E |
LL6 |
Contributing
Issues and PRs welcome — especially additional reference anchors, alternative Palmer text conventions, and bindings in other languages. Every conversion change must keep the exhaustive round-trip tests green.
Citing
If this is useful in research or software, please cite it (see CITATION.cff). A
short software paper is in paper.md.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file toothnotation-0.1.0.tar.gz.
File metadata
- Download URL: toothnotation-0.1.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d3481933f67cf811ab6192239c9f2eb6e15df195679aae9f1c624b866a15560
|
|
| MD5 |
4a864e8a9b680b4dd796c9f9af013a27
|
|
| BLAKE2b-256 |
06d50e4ff8a2ebb96d4a4086c797e9b3820df20a520dab22a71c6d50cef09fb8
|
File details
Details for the file toothnotation-0.1.0-py3-none-any.whl.
File metadata
- Download URL: toothnotation-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0342c35ed0e781d8aa681e4022d4a361cd4b90bad64b7350c1e7078336b37889
|
|
| MD5 |
cf9066a9b0a89faf1553c394a147f0af
|
|
| BLAKE2b-256 |
c15f78476c6650c17853e4a8e57d30243a9734d9de88a674c9eaabf1a13803bf
|