plotter(), plotterpro() and
upload_tryCatch_pro() now return their HTML/JSON response
as a string (invisibly) instead of only writing it via
cat(). Under rApache, standard output is the actual HTTP
response body, so the cat() calls remain and the
deployment’s behavior is unchanged; the return value simply gives a
normal R caller (including R CMD check’s console-output
scanner) an object to work with instead of unsuppressable console
text.
plotter() now saves and restores the global
error option via an immediate on.exit()
instead of leaving options(error = dump.frames) in effect
for the rest of the R session after the function returns.
calculate_sds(..., type = "tv") no longer has a
discontinuity at Prader bead boundaries: a raw ml reading is now mapped
onto a continuous bead-index scale before interpolating, so both the low
and high percentiles in the mid-P formula move together and the SDS
varies smoothly with ml instead of jumping right at each bead threshold
(e.g. 11.99ml vs 12.00ml).
calculate_sds(..., type = "tv") now correctly
returns NA for an NA age or stage, instead of
a finite but wrong value. The continuous bead-index interpolation above
used approx()’s default na.rm = TRUE, which
silently drops NA (x, y) pairs from the interpolation table
before interpolating – so an NA age (which makes every real
bead percentile NA) left only the two artificial boundary
values (P(TV>=0)=1, P(TV>=Inf)=0) in the
table, and interpolated between just those two instead of propagating
the NA.
interpolate_trajectory()’s returned
stage component is now the same length as
x/y/patient. It was previously
built from the cumulative length of the output-so-far across all
segments instead of the current segment’s own length, making it longer
than the other three components whenever a patient had more than one
stage segment.
Documented that calculate_sds()’s return value is
always the same length as age, and that stage
must be the same length as age (not recycled) – a length-1
stage, or any other length mismatch, is unsupported and can
silently truncate, warn, produce NAs, or error depending on
type.
Added vignettes/tanner.Rmd, covering a fuller
plot_stadia() walkthrough across its
type/plotline/colors/overlay
arguments, how raw tv (ml) readings are handled differently
by calculate_sds() (continuous interpolation) versus
plot_stadia() (snap to the nearest Prader bead curve), and
the mid-P value SDS methodology of van Buuren & Ooms (2009) –
including why it is a discrete/ordinal method distinct from LMS/BCCG
continuous-measurement SDS (e.g. centile::y2z()).
Originally written as a Quarto vignette (tanner.qmd,
%\VignetteEngine{quarto::html}); converted to classic
knitr::rmarkdown (VignetteBuilder: knitr)
after CI revealed an unresolved upstream Windows-only bug in the Quarto
vignette engine (see “Continuous integration” below) that would have
blocked CRAN submission, since CRAN’s own build machines check
Windows.
Added a “Package structure” section to the README distinguishing
the supported general-purpose library API (plot_stadia*,
interpolate_trajectory, find_stage_segments,
calculate_sds, tnologo) from the rApache
webapp request handlers (plotter, plotterpro,
upload_tryCatch_pro) kept only for the existing deployment.
plotter(), plotterpro() and
upload_tryCatch_pro() are now also grouped under a
@family webapp-internals roxygen tag, so they
cross-reference each other in ?tanner and on the pkgdown
site.
Added a pkgdown site (_pkgdown.yml), with a
reference index split into “Plotting & analysis”, “Reference data”,
and “Webapp internals” sections, and
URL/BugReports fields in
DESCRIPTION.
Added full citations for van Buuren S (2014), “Growth charts of
human development,” Statistical Methods in Medical Research,
23(4), 346-368, in nl1997’s source documentation.
testthat unit tests for
calculate_sds(), interpolate_trajectory(),
find_stage_segments(), and smoke tests for the
plot_stadia* drawing functions (which draw to a graphics
device and return invisible NULL, so are tested by
asserting they run without error). Extracted the tv
ml-to-nearest-bead snapping logic out of plot_stadia_data()
into an internal snap_tv_to_nearest_bead() helper so it can
be unit tested directly.calculate_sds() and
snap_tv_to_nearest_bead() each independently parsed the ml
threshold from "T"-prefixed tv reference column names
(e.g. "T12" -> 12); extracted the shared
parsing step into an internal tv_ml_thresholds() helper.
Pure refactor, no behavior change – the bracket-and-interpolate
vs. snap-to-nearest logic that follows at each call site is
untouched.Added .github/workflows/R-CMD-check.yaml (a standard
R CMD check matrix across macOS/Windows/Ubuntu) and
.github/workflows/pkgdown.yaml (builds and deploys the
pkgdown site to GitHub Pages on push to master).
windows-latest was briefly excluded from the check matrix
after CI revealed that the quarto::html vignette engine
hits an unresolved upstream Windows-only bug during
R CMD build (the Quarto subprocess can’t see the temporary
library R CMD build just installed the package into;
r-lib/rcmdcheck#236); re-added once the vignette was converted to
classic knitr::rmarkdown (see “Documentation” above), which
doesn’t hit this bug since it renders in-process rather than via an
external Quarto subprocess.
_pkgdown.yml now sets
template: bootstrap: 5 (Quarto-rendered articles require
it; the default Bootstrap 3 made the pkgdown site build fail before it
ever reached the deploy step) and llm-docs: false
(pkgdown’s llms.txt generation, not needed here and fragile
against the runner’s pandoc version).
library(tanner) no longer creates a
plotdumpdir directory (or writes to disk at all) as a side
effect of loading the package. The directory is now created lazily, on
the first actual write inside
plotter()/plotterpro()/upload_tryCatch_pro();
plotdumpdir remains exported and mutable.
plotdumpdir now defaults to a
"plotfiles" subdirectory of tempdir() instead
of the hardcoded /tmp/plotfiles, and
upload_tryCatch_pro()’s uploaded-file and
.RData handoff files move there too (previously hardcoded
to /tmp independently of plotdumpdir). This is
a behavior change for the rApache deployment: tempdir()
must resolve to a writable location that stays stable across the upload
and plot requests for a given user session (true for a single
long-running R process, which is how rApache normally hosts an R
interpreter per worker). Unix-only /tmp was also a
portability problem for R CMD check/CI on Windows and macOS
runners, even though the webapp handlers themselves only ever ran on
Linux.
Renamed three exported functions to consistent
snake_case, matching plot_stadia()’s existing
naming style:
calculateSDS() -> calculate_sds()findXY() ->
interpolate_trajectory()findSegments() ->
find_stage_segments()There are no backwards-compatible aliases for the old names; update any code calling them directly.
Renamed the two bundled reference datasets, following the
<population><year> naming convention used by
the nlreferences and clopus packages:
pub.ref -> nl1997pub.ref.lines -> nl1997_linesgenital.pdf,
boy.pdf, and the breast stage-line-diagram template),
sourced by sampling exact pixel colors and by recovering the original
plotting script (figures.r) that generated them.plot_stadia() silently ignoring its own
padid argument: the function always appended the patient id
to the title regardless of what was passed, so
padid = FALSE (already used by plotter())
never actually worked.foreign::read.spss() with
haven::read_sav() in upload_tryCatch_pro();
haven moved from Depends to
Imports.README.Rmd to README.qmd
(Quarto), for better editor support and to avoid a pandoc version
mismatch on this system. Replaced the synthetic example data in the
first README figure with a real patient’s genital-stage trajectory,
recovered from the original demo dataset
(pubertal demo data.txt) used to produce
genital.pdf/ boy.pdf, and noted the data
source in the figure title.pubertyplot to
tanner, and the GitHub repository moved to
growthcharts/tanner. Update
library(pubertyplot) calls to library(tanner),
and devtools::install_github(...) calls to point at
growthcharts/tanner.Replaced the bundled testicular-volume reference data with a
corrected R refit (pub.ref.1997r.txt). The previously
shipped pub.ref.1997.txt was an older S-Plus fit that the
original 2008 fitting script’s own validation had already flagged as
containing errors in the tv (testicular volume) curves —
some tv percentiles were missing entirely at younger ages.
The refit’s genital-stage percentiles match Table 5 of van Buuren S
(2014), “Growth charts of human development,” Statistical Methods in
Medical Research, 23(4), 346-368, https://doi.org/10.1177/0962280212473300, exactly.
pub.ref and pub.ref.lines were rebuilt from
the corrected data via
data-raw/R/create_references.R.
pub.ref$tv / pub.ref.lines$tv now carry
the full 12-point testicular volume scale (1, 2, 3, 4, 5, 6, 8, 10, 12,
15, 20, 25 ml), up from 7 columns previously.
calculateSDS() and plot_stadia()
previously required tv to be recoded from a raw ml reading
into a bead-index (1-8, then later 1-12) by hand before use.
tv is now passed as the raw ml value
directly — no recoding step required — and calculateSDS()
correctly interpolates readings that fall between Prader
orchidometer beads (e.g. 11 ml or 16 ml), rather than requiring one of
the 12 standard bead volumes. plot_stadia() traces the
trajectory along the nearest reference curve for the same off-bead
readings.
Removed the manual tv recoding tables from
plotter(), plotterpro() and the README
examples, since they are no longer needed.
upload_tryCatch_pro()’s upload validation for
tv now accepts any plausible ml reading (0-30) instead of
rejecting anything outside the old fixed bead list.
The single-patient web app’s testicular volume dropdown
(inst/webapps/puberty/puberty.js) now offers the correct 12
Prader bead volumes (1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25), replacing
the previous incomplete/incorrect 8-value list.
Regenerated the bundled demo data
(inst/webapps/pubertypro/demo.csv, demo.txt,
demo.sav) with tv values spanning the
corrected 12-point scale, including off-bead readings, since the
original demo values were from a different orchidometer scale and no
longer matched the corrected reference data.
Fixed the testis reference lines and labels in
plot_stadia() / plot_stadia_lines(), which
still only drew 8 of the 12 reference curves and labeled them with the
old bead volumes.
@examples block to
findXY().R/data.R, man pages for every exported function)..rda data
files.tools/run_mock_webapp.R, a local server (via
httpuv) that serves the puberty and pubertypro
browser frontends and answers their AJAX endpoints without needing a
real Apache + rApache deployment.plotdumpdir rather than the
package-namespace variable that
plotter()/plotterpro() actually read
from).plot.stadia) to
underscore form (plot_stadia) to avoid the misleading
appearance of S3 methods.T/F with
TRUE/FALSE in default arguments and call
sites.foreign::read.spss() with
haven::read_sav() for reading uploaded .sav
files in upload_tryCatch_pro(), moving haven
from Depends to Imports.