Package {tanner}


Type: Package
Title: Puberty Stage Line Diagrams and SDS for Tanner Pubertal Stages
Version: 1.8.0
Date: 2026-07-18
Description: Plots Tanner pubertal stage measurements (genital, pubic hair, testicular volume, breast, menarche) against Dutch 1997 growth-study references as stage line diagrams, and converts observed stages to age-conditional standard deviation scores (SDS). Testicular volume can be entered as a raw orchidometer reading in ml. Implements the method of van Buuren and Ooms (2009) <doi:10.1002/sim.3567>.
License: MIT + file LICENSE
URL: https://github.com/growthcharts/tanner, https://growthcharts.org/tanner/
BugReports: https://github.com/growthcharts/tanner/issues
Encoding: UTF-8
Depends: R (≥ 3.5.0)
Imports: haven
LazyData: true
RoxygenNote: 7.3.3
Suggests: testthat (≥ 3.0.0), knitr, rmarkdown
VignetteBuilder: knitr
Config/testthat/edition: 3
NeedsCompilation: no
Packaged: 2026-07-28 20:39:47 UTC; buurensv
Author: Stef van Buuren [aut, cre], Jeroen Ooms [aut]
Maintainer: Stef van Buuren <stef.vanbuuren@tno.nl>
Repository: CRAN
Date/Publication: 2026-08-06 13:10:02 UTC

Calculate the standard deviation score (SDS) of a pubertal stage

Description

Calculates the SDS for a pubertal stage measurement, given the patient's age and observed stage, by interpolating between the surrounding reference percentiles.

Usage

calculate_sds(age, stage, type, ref = tanner::nl1997)

Arguments

age

Vector of patient ages. The length of age determines the length of the return value (see Value below).

stage

Vector of patient stages, the same length as age (one stage per age; not recycled). For type = "tv" this is the raw testicular volume in **ml**, as read off a Prader orchidometer or otherwise measured; it need not be one of the 12 Prader bead volumes (1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25) — any intermediate value (e.g. 11 or 16 ml) is bracketed between the surrounding reference percentiles. For all other types, stage is the integer Tanner stage (1-5 for "gen", "phb", "bre", "phg"; 1-2 for "men"). A stage shorter or longer than age is not supported: it is silently truncated or padded rather than recycled (e.g. a length-1 stage does not apply to every element of age) and can also produce NAs, a warning, or a "subscript out of bounds" error depending on type – do not rely on any of these behaviors, always pass stage the same length as age.

type

Reference type: one of "gen", "phb", "tv", "bre", "phg" or "men".

ref

Reference data, as produced by nl1997.

Details

Implements the mid-P value method of van Buuren & Ooms (2009), equation (6): treating the observed stage c as a coarsened version of a continuous latent variable, uniformly distributed within the stage's probability interval [P(Y<c|X), P(Y<c+1|X)). The mid-P value pi_c = P(Y<c|X) + P(Y=c|X)/2 is the mean of that latent variable, and Z = qnorm(1 - pi_c) = qnorm(1 - (P(Y>=c|X) + P(Y>=c+1|X))/2) converts it to a Z-score/SDS. This is why the SDS averages the surrounding-stage percentiles rather than looking up a single stage's percentile directly: the averaging is the mid-P value itself, not an ad hoc smoothing step. The same formula applies to tv's 12 Prader bead categories, treating each raw ml reading as belonging to the bead-category interval it falls into (see below).

Value

A numeric vector of SDS values, the same length as age (one value per element of age).

References

van Buuren S, Ooms JCL (2009). Stage line diagram: An age-conditional reference diagram for tracking development. Statistics in Medicine, 28(11), 1569-1579. doi:10.1002/sim.3567

Examples

# a single boy, genital stage 3 at age 12
calculate_sds(age = 12, stage = 3, type = "gen")

# a boy's genital-stage trajectory over three visits
calculate_sds(age = c(10, 12, 14), stage = c(1, 3, 4), type = "gen")

# testicular volume in ml, interpolated between Prader beads
calculate_sds(age = 13, stage = 11, type = "tv")

Find segments of constant stage in a vector

Description

Determines the runs (segments) in z over which the value does not change, ignoring missing values. Used by interpolate_trajectory to split a patient's stage trajectory into per-stage segments.

Usage

find_stage_segments(z)

Arguments

z

A vector, typically of pubertal stages.

Value

A logical matrix with one row per segment and one column per element of z, where TRUE marks membership of that element in the segment.


Interpolate a pubertal stage trajectory along reference curves

Description

Computes the x/y coordinates needed to plot a patient's pubertal stage trajectory along the reference curves, including the interpolated segments between measurement ages within the same stage.

Usage

interpolate_trajectory(refx, refy, patx, pats)

Arguments

refx

Vector of reference ages.

refy

Matrix of reference values, one column per stage.

patx

Vector of patient ages.

pats

Vector of patient stages (column indices into refy).

Value

A list with components x, y, stage and patient (a logical flag indicating whether a point is an observed patient measurement or an interpolated reference point).

Examples

# reference ages and genital stage percentile curves for boys
refx <- seq(8, 21, 0.25)
refy <- tanner::nl1997_lines$gen[, -1]

# a boy observed at G1 at age 10, still G1 at age 11, then G3 at age 13
patx <- c(10, 11, 13)
pats <- c(1, 1, 3)

curve <- interpolate_trajectory(
  refx = refx, refy = refy, patx = patx, pats = pats
)
curve

# curve$patient flags the observed measurements; the other points
# interpolate along the reference curve between them
plot(curve$x, curve$y, type = "l")
points(curve$x[curve$patient], curve$y[curve$patient], pch = 16)

Dutch 1997 pubertal stage references

Description

Reference percentiles for pubertal stage variables by age, based on the Dutch 1997 growth study (Fredriks et al., 2000). Used by calculate_sds to convert an observed age/stage combination into a standard deviation score.

Usage

nl1997

Format

A list with six components, one per pubertal stage variable: gen, phb, tv, bre, phg and men. Each component is a data frame whose first column is age and whose remaining columns hold the age at which 50 the reference population reaches each stage.

Source

Fredriks AM, van Buuren S, Burgmeijer RJ, et al. (2000). Continuing positive secular growth change in The Netherlands 1955-1997. Pediatric Research, 47(3), 316-323. Percentiles were refit in R from data-raw/data/pub.ref.1997r.txt, correcting testis-volume (tv) fitting errors present in the original S-Plus-fitted pub.ref.1997.txt; the genital-stage columns match Table 5 of van Buuren S (2014). Growth charts of human development. Statistical Methods in Medical Research, 23(4), 346-368. doi:10.1177/0962280212473300


Dutch 1997 pubertal stage reference lines

Description

Reference curves, expressed as standard deviation scores (SDS) by age, derived from nl1997. Used by plot_stadia to draw the percentile lines on a puberty stadia plot.

Usage

nl1997_lines

Format

A list with six components, one per pubertal stage variable: gen, phb, tv, bre, phg and men. Each component is a matrix whose first column is age and whose remaining columns hold the SDS curve for each stage.

Source

Derived from nl1997; see data-raw/R/create_references.R.


Plot a puberty stadia diagram

Description

Plots Tanner pubertal stage measurements for one or more persons against the Dutch 1997 reference curves, expressed as standard deviation scores (SDS) by age.

Usage

plot_stadia(
  data = pub.data,
  persons = unique(data$id),
  plotline = c(TRUE, FALSE, FALSE),
  type = c(TRUE, FALSE, FALSE),
  colors = c("#0060A0", "#00A000", "#A00000"),
  overlay = FALSE,
  ovsex = "M",
  ref = tanner::nl1997_lines,
  title = "Tanner pubertal stages - Patient ",
  padid = TRUE
)

Arguments

data

A data frame with columns id, age, sex and the pubertal stage variables (gen, phb, tv for males; bre, phg, men for females). tv (testicular volume) is the raw reading in **ml** — any value, not just the 12 Prader orchidometer bead volumes (1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25) — the trajectory is traced along the nearest reference curve. The other stage variables are the integer Tanner stage.

persons

Vector of person identifiers (values of data$id) to plot.

plotline

Logical vector of length 3 indicating which reference lines to draw.

type

Logical vector of length 3 indicating which pubertal stage variables to plot.

colors

Character vector of length 3 with the colors used for the three pubertal stage variables.

overlay

If TRUE, plot all persons on a single graph.

ovsex

Sex ("M" or "F") used to select the reference lines when overlay = TRUE.

ref

Reference data used to draw the reference lines, as produced by nl1997_lines.

title

Plot title.

padid

If TRUE, append the person identifier to the title.

Value

Invisibly returns NULL; the function draws on the current graphics device.


Draw a person's pubertal stage trajectory on a puberty stadia plot

Description

Internal helper used by plot_stadia to draw a single person's pubertal stage trajectory, interpolated along the reference curves, on the current plot.

Usage

plot_stadia_data(ages, pubs, sex, type, colors, ref)

Arguments

ages

Vector of ages at measurement.

pubs

Data frame with the pubertal stage variables for this person; tv is the raw testicular volume in ml (see plot_stadia).

sex

"M" or "F".

type

Logical vector of length 3 indicating which pubertal stage variables to plot.

colors

Character vector of length 3 with the colors for the three pubertal stage variables.

ref

Reference data, as produced by nl1997_lines.

Value

Invisibly returns NULL; the function draws on the current graphics device.


Draw the frame, percentile bands and axes of a puberty stadia plot

Description

Internal helper used by plot_stadia to draw the plot frame, the early/late percentile bands, the TNO logo and the axes.

Usage

plot_stadia_general(
  i = " ",
  opt = c(TRUE, TRUE, TRUE, TRUE, TRUE),
  title = " ",
  padid = TRUE
)

Arguments

i

Person identifier appended to the title when padid = TRUE.

opt

Logical vector of length 5 selecting which elements to draw: frame and title, extreme percentile regions, TNO logo, axes, margin reference text.

title

Plot title.

padid

If TRUE, append i to the title.

Value

Invisibly returns NULL; the function draws on the current graphics device.


Draw reference percentile lines on a puberty stadia plot

Description

Internal helper used by plot_stadia to add the Dutch reference lines for males (Genital, Pubic hair, Testis) or females (Breast, Pubic hair, Menarche) to the current plot.

Usage

plot_stadia_lines(plotlines, colors, sex, ref)

Arguments

plotlines

Logical vector of length 3 indicating which reference lines to draw.

colors

Character vector of length 3 with the colors for the three pubertal stage variables.

sex

"M" or "F".

ref

Reference data, as produced by nl1997_lines.

Value

Invisibly returns NULL; the function draws on the current graphics device.


Directory where generated plot and data files are written

Description

Set on package load to a "plotfiles" subdirectory of tempdir(). Used by the rApache handlers plotter and plotterpro as the destination directory for generated PDF, PNG, CSV and TXT files, and by upload_tryCatch_pro as the destination for uploaded data files and the .RData file it hands off to plotterpro. The directory itself is only created lazily, on the first actual write inside these handlers – not merely by loading the package – so calling library(tanner) to use unrelated functions like calculate_sds has no disk side effects. Reassign this before calling the handlers to change where they read/write.

Usage

plotdumpdir

Format

An object of class character of length 1.


rApache handler for the puberty plot webapp

Description

Reads pubertal staging data from the rApache GET request, builds a puberty plot and writes it to PDF and PNG files in plotdumpdir. This function is intended to be called from the rApache web frontend shipped in inst/webapps, not interactively from R.

Usage

plotter()

Value

Invisibly returns the generated file name stem (also written, via cat(), to the response – under rApache, standard output is the HTTP response body).

See Also

Other webapp-internals: plotterpro(), upload_tryCatch_pro()


rApache handler for the professional puberty plot webapp

Description

Reads a saved data file (written by upload_tryCatch_pro) from plotdumpdir, as referenced in the rApache POST request, calculates SDS values for the pubertal stages, and writes the results and a puberty plot to CSV, TXT and PDF files, also in plotdumpdir. This function is intended to be called from the rApache web frontend shipped in inst/webapps, not interactively from R.

Usage

plotterpro()

Value

Invisibly returns the JSON response string (also written, via cat(), to the response – under rApache, standard output is the HTTP response body).

See Also

Other webapp-internals: plotter(), upload_tryCatch_pro()


Snap raw testicular volume readings to the nearest Prader bead curve

Description

Internal helper used by plot_stadia_data to trace a tv trajectory along the single nearest reference curve, since tv is recorded as a raw ml reading rather than one of the 12 Prader bead volumes. Unlike calculate_sds's tv handling (which interpolates continuously between the two surrounding beads), this snaps to whichever bead is closest, since a trajectory line can only follow one reference curve at a time.

Usage

snap_tv_to_nearest_bead(ml, refy_colnames)

Arguments

ml

Vector of raw testicular volume readings, in ml.

refy_colnames

Column names of the tv reference curves (e.g. "T1", "T2", ..., "T25"), i.e. colnames(ref$tv[, -1]) (see nl1997_lines), with the leading "age" column already dropped.

Value

Integer vector the same length as ml: the column index (into refy_colnames) of the nearest bead curve, or NA where ml is NA.


Description

Plots the current TNO logo (upright "TN" wordmark plus a ring-shaped "O") using the current coordinate system. Used by plot_stadia_general to brand the puberty stadia plots.

Usage

tnologo(col = "darkblue", bcol = "white", at = c(0, 0), size = 300, aspect = 1)

Arguments

col

Foreground color.

bcol

Background color.

at

(x, y) coordinate of the lower left corner of the logo.

size

Horizontal size, measured in the units of the x-axis.

aspect

Unit size of the y-axis divided by the unit size of the x-axis.

Value

Invisibly returns NULL; the function draws on the current graphics device.


Parse Prader bead ml thresholds from tv reference column names

Description

Internal helper shared by calculate_sds and snap_tv_to_nearest_bead: both need the raw ml threshold each "T"-prefixed tv reference column represents (e.g. "T12" -> 12), though what they do with those thresholds afterward differs (bracket-and-interpolate vs. snap-to-nearest).

Usage

tv_ml_thresholds(colnames)

Arguments

colnames

Character vector of "T"-prefixed column names (e.g. "T1", "T2", ..., "T25"), as found in ref$tv (see nl1997/nl1997_lines), with any leading "age" column already excluded.

Value

Numeric vector the same length as colnames: the ml threshold each column represents.


rApache handler for uploading puberty data files

Description

Validates an uploaded data file (referenced in the rApache FILES request), saves it as an .RData file in plotdumpdir, and writes a JSON summary of the data per person to the response. This function is intended to be called from the rApache web frontend shipped in inst/webapps, not interactively from R.

Usage

upload_tryCatch_pro()

Value

Invisibly returns the HTML/JSON response string (also written, via cat(), to the response – under rApache, standard output is the HTTP response body).

See Also

Other webapp-internals: plotter(), plotterpro()