| Title: | Dental Public Health Indices and Odontogram Visualizations |
|---|---|
| Description: | Computes dental caries indices (DMFT, DMFS, dmft, dmfs) from surface-level clinical examination data and produces odontogram heatmap visualizations of per-tooth-surface outcomes. Supports primary and permanent dentition with configurable teeth per quadrant (5 to 8), separate root and coronal caries tallying, long and wide input formats, stratified output, and FDI/Universal/quadrant tooth numbering conversion. |
| Authors: | David Selvaraj [aut, cre, cph] (ORCID: <https://orcid.org/0000-0003-4055-9493>), Suchitra Nelson [aut] |
| Maintainer: | David Selvaraj <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.5.0 |
| Built: | 2026-07-22 10:56:42 UTC |
| Source: | https://github.com/cran/tooth |
Draws a full-arch odontogram with colour-coded tooth surfaces. Supports primary and permanent dentition (5–8 teeth per quadrant), selective surfaces, stratification, summary statistics with significance testing, and configurable tooth numbering.
build_odontogram( data, value_col = "prop", dentition = "permanent", teeth_per_quadrant = NULL, title = "Surface Odontogram", subtitle = NULL, color_low = "#FFFFFF", color_high = "#C62828", na_color = "grey90", min_val = NULL, max_val = NULL, legend_title = "Proportion", show_roots = TRUE, surfaces = c("buc", "lin", "mes", "dis", "occ", "rootb", "rootl", "rootm", "rootd"), show_labels = TRUE, label_size = 1.8, tooth_label_size = 3, numbering = c("quadrant", "fdi", "universal"), strata = NULL, strata_labels = NULL, stats = NULL, stats_test = NULL, stats_var = NULL, stats_raw = NULL, footnote = NULL, combine = TRUE, ncol = 1 )build_odontogram( data, value_col = "prop", dentition = "permanent", teeth_per_quadrant = NULL, title = "Surface Odontogram", subtitle = NULL, color_low = "#FFFFFF", color_high = "#C62828", na_color = "grey90", min_val = NULL, max_val = NULL, legend_title = "Proportion", show_roots = TRUE, surfaces = c("buc", "lin", "mes", "dis", "occ", "rootb", "rootl", "rootm", "rootd"), show_labels = TRUE, label_size = 1.8, tooth_label_size = 3, numbering = c("quadrant", "fdi", "universal"), strata = NULL, strata_labels = NULL, stats = NULL, stats_test = NULL, stats_var = NULL, stats_raw = NULL, footnote = NULL, combine = TRUE, ncol = 1 )
data |
Data frame with at least |
value_col |
Name of the numeric column to map to fill colour. |
dentition |
|
teeth_per_quadrant |
Integer 5–8 (default derived from |
title, subtitle
|
Plot title/subtitle. |
color_low, color_high
|
Gradient endpoints (default |
na_color |
Fill for missing surfaces (default |
min_val, max_val
|
Lower and upper limits for the colour scale. Both auto-detected when NULL. Set manually to fix the range across multiple plots. |
legend_title |
Legend title. |
show_roots |
Logical; draw root caries bars. |
surfaces |
Character vector of surfaces to draw. |
show_labels |
Logical; show surface abbreviation labels (B, L, M, D, O, RB, RL, RM, RD) inside each surface polygon. |
label_size |
Numeric; size of surface labels. |
tooth_label_size |
Numeric; size of tooth number labels (default 3). |
numbering |
Tooth numbering system for display: |
strata |
Optional column name for stratification. |
strata_labels |
Optional named character vector to relabel strata in panel titles. |
stats |
Optional data frame of per-group summary statistics to display
below each panel. Must contain a column matching |
stats_test |
Method for comparing stats across strata: |
stats_var |
Column name in |
stats_raw |
Optional data frame of individual-level data used for
significance testing. Must contain a column matching |
footnote |
Optional character string displayed below the plot as a caption. Use for abbreviation explanations and p-value definitions. |
combine |
Logical; if |
ncol |
Number of columns when combining stratified panels. |
Summary statistics: Pass a data frame to stats with one row per
stratum. Example:
stats_df <- data.frame(
treatment = c("SDF", "ART"),
n = c(120, 115),
mean_DT = c(2.3, 2.8),
mean_DMFT = c(5.1, 5.6)
)
build_odontogram(d, strata = "treatment", stats = stats_df)
Significance stars: When stats_test and stats_var are set and
raw data is provided via stats_raw, p-values are computed and appended:
*** p < 0.001, ** p < 0.01, * p < 0.05, ns otherwise.
A ggplot object (or list of ggplots if combine = FALSE).
library(tibble) d <- expand.grid( tooth_num = paste0(rep(c("ur","ul","lr","ll"), each=7), 1:7), tooth_surface = c("buc","lin","mes","dis","occ"), stringsAsFactors = FALSE ) d$prop <- runif(nrow(d)) build_odontogram(d, teeth_per_quadrant = 7)library(tibble) d <- expand.grid( tooth_num = paste0(rep(c("ur","ul","lr","ll"), each=7), 1:7), tooth_surface = c("buc","lin","mes","dis","occ"), stringsAsFactors = FALSE ) d$prop <- runif(nrow(d)) build_odontogram(d, teeth_per_quadrant = 7)
Computes Decayed, Missing, and Filled Surfaces per person. Can separate root from coronal surfaces. Accepts long or wide format.
calc_dmfs( data, format = c("long", "wide"), id = "record_id", group = NULL, strata = NULL, lesion_col = "lesion_code", activity_col = "act", filling_col = "filling_code", tooth_code_col = "code", root_lesion_col = NULL, root_surfaces = c("rootb", "rootl", "rootm", "rootd"), decayed_codes = c(3, 4, 5, 6), activity_codes = c(2), filled_codes = c(1, 2, 4, 5, 6, 7, 8), missing_codes = c(1), root_decayed_codes = NULL, consider_activity = TRUE, consider_activity_coronal = NULL, consider_activity_root = NULL )calc_dmfs( data, format = c("long", "wide"), id = "record_id", group = NULL, strata = NULL, lesion_col = "lesion_code", activity_col = "act", filling_col = "filling_code", tooth_code_col = "code", root_lesion_col = NULL, root_surfaces = c("rootb", "rootl", "rootm", "rootd"), decayed_codes = c(3, 4, 5, 6), activity_codes = c(2), filled_codes = c(1, 2, 4, 5, 6, 7, 8), missing_codes = c(1), root_decayed_codes = NULL, consider_activity = TRUE, consider_activity_coronal = NULL, consider_activity_root = NULL )
data |
Data frame. In long format: one row per tooth-surface with columns for id, tooth_num, tooth_surface, and clinical codes. In wide format: one row per person-tooth with surface codes in separate columns. |
format |
|
id |
Person-identifier column (default |
group |
Optional grouping column(s) for repeated measures, e.g.
|
strata |
Optional stratification column(s), e.g. |
lesion_col, activity_col, filling_col, tooth_code_col
|
Column names for ICDAS codes (long format). |
root_lesion_col |
Optional column for root surface lesion codes. When provided, root caries (RDT) is calculated separately from coronal (DT). Set to NULL to ignore root caries (default). |
root_surfaces |
Character vector of surface names considered root
surfaces. Default |
decayed_codes |
Numeric vector of lesion codes considered decayed
(default |
activity_codes |
Numeric vector of activity codes indicating active
caries (default |
filled_codes |
Numeric vector of filling codes indicating a
restoration is present (default |
missing_codes |
Numeric vector of tooth-level codes indicating the
tooth is missing (default |
root_decayed_codes |
Numeric vector for root caries codes (default
same as |
consider_activity |
Logical; overall default for whether a lesion must
also carry an active-caries code ( |
consider_activity_coronal, consider_activity_root
|
Optional logical
overrides for the coronal and root components. |
A tibble with one row per person (and group/strata) containing:
DS, FS, MS, DFS, DMFS, plus optional RDS (root decayed
surfaces) when root_lesion_col is set, and binary indicators.
Computes Decayed, Missing, and Filled Teeth counts per person. Handles both primary and permanent dentition. Can separate root caries from coronal caries. Accepts long or wide format data.
calc_dmft( data, format = c("long", "wide"), id = "record_id", group = NULL, strata = NULL, lesion_col = "lesion_code", activity_col = "act", filling_col = "filling_code", tooth_code_col = "code", root_lesion_col = NULL, root_surfaces = c("rootb", "rootl", "rootm", "rootd"), decayed_codes = c(3, 4, 5, 6), activity_codes = c(2), filled_codes = c(1, 2, 4, 5, 6, 7, 8), present_codes = c(2, 3, 4, 5, 6, 7, 8), missing_codes = c(1), root_decayed_codes = NULL, consider_activity = TRUE, consider_activity_coronal = NULL, consider_activity_root = NULL )calc_dmft( data, format = c("long", "wide"), id = "record_id", group = NULL, strata = NULL, lesion_col = "lesion_code", activity_col = "act", filling_col = "filling_code", tooth_code_col = "code", root_lesion_col = NULL, root_surfaces = c("rootb", "rootl", "rootm", "rootd"), decayed_codes = c(3, 4, 5, 6), activity_codes = c(2), filled_codes = c(1, 2, 4, 5, 6, 7, 8), present_codes = c(2, 3, 4, 5, 6, 7, 8), missing_codes = c(1), root_decayed_codes = NULL, consider_activity = TRUE, consider_activity_coronal = NULL, consider_activity_root = NULL )
data |
Data frame. In long format: one row per tooth-surface with columns for id, tooth_num, tooth_surface, and clinical codes. In wide format: one row per person-tooth with surface codes in separate columns. |
format |
|
id |
Person-identifier column (default |
group |
Optional grouping column(s) for repeated measures, e.g.
|
strata |
Optional stratification column(s), e.g. |
lesion_col, activity_col, filling_col, tooth_code_col
|
Column names for ICDAS codes (long format). |
root_lesion_col |
Optional column for root surface lesion codes. When provided, root caries (RDT) is calculated separately from coronal (DT). Set to NULL to ignore root caries (default). |
root_surfaces |
Character vector of surface names considered root
surfaces. Default |
decayed_codes, activity_codes, filled_codes, present_codes, missing_codes
|
Numeric vectors defining clinical code categories. Defaults match ICDAS.
See the Diagnostic threshold section for |
root_decayed_codes |
Numeric vector for root caries codes (default
same as |
consider_activity |
Logical; overall default for whether a lesion must
also carry an active-caries code ( |
consider_activity_coronal, consider_activity_root
|
Optional logical
overrides for the coronal and root components. |
A tibble with one row per person (and group/strata) containing:
Decayed teeth (coronal)
Filled teeth (not decayed)
Missing teeth
Decayed or filled teeth
Decayed + missing + filled teeth
Count of teeth present
Root-decayed teeth (only when root_lesion_col is set)
Binary indicators
The default decayed_codes = c(3, 4, 5, 6) implements the D3 threshold:
only ICDAS codes 3–6 (localised enamel breakdown through extensive
cavitation) are scored as decayed, while ICDAS 1–2 (non-cavitated initial
enamel lesions) are treated as sound. This D(3)MFT convention is the one
most commonly reported in caries epidemiology. To use the more sensitive D1
threshold that also counts early enamel lesions, pass
decayed_codes = c(1, 2, 3, 4, 5, 6).
When format = "wide", each row is one person (and optional group).
You must supply columns named like {tooth}_{surface}_{code_type} or use
the wide_cols parameter. Alternatively, pass a pivot_spec — but the
easiest approach is to reshape to long with pivot_to_long() first.
Produces crown surface wedges (B/L/M/D/O) and up to four root surface
bars (RB/RL/RM/RD), plus labels, outlines, and diagonals — all as
data frames ready for ggplot2. Any surface can be excluded via the
surfaces argument.
draw_tooth( tooth_id, quadrant, tooth_num, is_upper, surface_values, value_col = "prop", x_offset = 0, y_offset = 0, tooth_size = 1, show_roots = TRUE, surfaces = c("buc", "lin", "mes", "dis", "occ", "rootb", "rootl", "rootm", "rootd"), display_label = NULL )draw_tooth( tooth_id, quadrant, tooth_num, is_upper, surface_values, value_col = "prop", x_offset = 0, y_offset = 0, tooth_size = 1, show_roots = TRUE, surfaces = c("buc", "lin", "mes", "dis", "occ", "rootb", "rootl", "rootm", "rootd"), display_label = NULL )
tooth_id |
Character label, e.g. |
quadrant |
One of |
tooth_num |
Numeric position within the quadrant. |
is_upper |
Logical; TRUE for upper arch. |
surface_values |
Data frame with |
value_col |
Name of the value column in |
x_offset, y_offset
|
Numeric offsets for positioning. |
tooth_size |
Numeric side length of the crown square (default 1). |
show_roots |
Logical; draw root surface bars (default TRUE). |
surfaces |
Character vector of surfaces to include. Omit any you don't want drawn. |
display_label |
Optional custom label for the tooth number (e.g.
FDI notation |
Named list of tibbles: crown, roots, labels, num_label, diags, outline.
Helper to reshape wide-format data (one row per person-tooth, surfaces
as separate columns) into the long format expected by calc_dmft().
pivot_to_long( data, id = "record_id", group = NULL, strata = NULL, lesion_suffix = "_les", filling_suffix = "_fil", activity_suffix = "_act", code_suffix = "_code" )pivot_to_long( data, id = "record_id", group = NULL, strata = NULL, lesion_suffix = "_les", filling_suffix = "_fil", activity_suffix = "_act", code_suffix = "_code" )
data |
Wide data frame. |
id |
Person ID column name. |
group |
Optional grouping columns. |
strata |
Optional stratification columns. |
lesion_suffix, filling_suffix, activity_suffix
|
Suffixes that
identify the surface-level columns (default |
code_suffix |
Suffix for tooth-level code columns (default |
Expects columns following the naming convention:
{tooth}_{surface}_les, {tooth}_{surface}_fil, {tooth}_{surface}_act,
and {tooth}_code for tooth-level status.
A long-format tibble.
A simulated surface-level dental examination dataset for 20 patients,
each with 7 teeth per quadrant (28 teeth) and 5 coronal surfaces plus
2 root surfaces per tooth. Designed for demonstrating and testing
calc_dmft(), calc_dmfs(), and build_odontogram().
sim_examsim_exam
A data frame with 3,920 rows and 7 columns:
Patient identifier (character, "P01" to "P20").
Tooth identifier in quadrant notation (e.g. "ur1", "ll7").
Surface name: buc, lin, mes, dis, occ, rootb, or rootl.
ICDAS lesion code (integer 0-6). 0 = sound, 3-6 = caries.
Filling/restoration code (integer). 0 = none, 1-8 = restored.
Lesion activity code (integer). 1 = inactive, 2 = active.
Tooth-level status code (integer). 1 = missing, 2-8 = present.
data(sim_exam) head(sim_exam) calc_dmft(sim_exam)data(sim_exam) head(sim_exam) calc_dmft(sim_exam)
Takes the output of calc_dmft() and produces a summary table with
n, mean number of teeth, mean DT, mean DMFT, and optionally other
columns — ready to pass directly to build_odontogram() via stats
and stats_raw.
summarise_dmft(dmft_data, group_col, digits = 1)summarise_dmft(dmft_data, group_col, digits = 1)
dmft_data |
Data frame returned by |
group_col |
Column name to summarise by (e.g. |
digits |
Number of decimal places for means (default 1). |
A list with two elements:
Summary data frame with one row per group, containing
n, mean_teeth, mean_DT, mean_DMFT. Column names match
what build_odontogram() expects for stats.
The input data frame, for passing to stats_raw in
build_odontogram().
data(sim_exam) dmft <- calc_dmft(sim_exam) dmft$treatment <- ifelse( as.numeric(gsub("P", "", dmft$record_id)) <= 10, "SDF", "ART" ) result <- summarise_dmft(dmft, "treatment") result$stats # Pass directly to build_odontogram: # build_odontogram(d, strata = "treatment", # stats = result$stats, stats_raw = result$raw, # stats_test = "wilcox", stats_var = "DMFT")data(sim_exam) dmft <- calc_dmft(sim_exam) dmft$treatment <- ifelse( as.numeric(gsub("P", "", dmft$record_id)) <= 10, "SDF", "ART" ) result <- summarise_dmft(dmft, "treatment") result$stats # Pass directly to build_odontogram: # build_odontogram(d, strata = "treatment", # stats = result$stats, stats_raw = result$raw, # stats_test = "wilcox", stats_var = "DMFT")
Creates a tibble of tooth IDs for primary or permanent dentition with a configurable number of teeth per quadrant (5-8).
tooth_config(dentition = c("permanent", "primary"), teeth_per_quadrant = NULL)tooth_config(dentition = c("permanent", "primary"), teeth_per_quadrant = NULL)
dentition |
Character: |
teeth_per_quadrant |
Integer 5-8. Defaults to 8 for permanent, 5 for primary. |
A tibble with columns: quadrant, num, tooth_id, is_upper.
Converts between FDI (ISO 3950), Universal (ADA), and the internal
quadrant format used by this package ("ur1", "ll5", etc.).
tooth_convert(x, from = "fdi", to = "quadrant", dentition = "permanent")tooth_convert(x, from = "fdi", to = "quadrant", dentition = "permanent")
x |
Character or numeric vector of tooth numbers. |
from |
Numbering system of the input: |
to |
Target numbering system: |
dentition |
|
The "universal" system follows the standard ADA conventions:
permanent teeth are numbered 1–32 (1 = upper-right third molar,
32 = lower-right third molar), while primary teeth use the letters
A–T (A = upper-right second primary molar, T = lower-right second
primary molar). FDI two-digit codes are 11–48 for permanent and
51–85 for primary dentition.
Character vector in the target system.
tooth_convert("11", from = "fdi", to = "quadrant") tooth_convert("ur1", from = "quadrant", to = "fdi") tooth_convert(c("1", "16", "17", "32"), from = "universal", to = "fdi") # Primary dentition uses ADA letters A-T for the universal system: tooth_convert("ur1", from = "quadrant", to = "universal", dentition = "primary") # "E" tooth_convert("K", from = "universal", to = "fdi", dentition = "primary")tooth_convert("11", from = "fdi", to = "quadrant") tooth_convert("ur1", from = "quadrant", to = "fdi") tooth_convert(c("1", "16", "17", "32"), from = "universal", to = "fdi") # Primary dentition uses ADA letters A-T for the universal system: tooth_convert("ur1", from = "quadrant", to = "universal", dentition = "primary") # "E" tooth_convert("K", from = "universal", to = "fdi", dentition = "primary")