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.