log_likelihood(), est_seroincidence() and est_seroincidence_by()
gain a method argument selecting how several biomarkers are combined.
The new method = "joint" fits the model the methodology article
describes: each person's biomarkers are conditionally independent
given their time since infection, so their densities multiply inside
one integral over that shared latent time
(implemented in C, src/serocalc_joint.c).
The default, method = "composite", is unchanged: it sums the
per-biomarker marginal log-likelihoods, which gives each biomarker its
own latent time (a composite/independence likelihood --- see #637)
and reproduces previous results exactly.
The joint likelihood needs pop_data to identify people
(see ids_varname()), so that each person's readings can be paired,
a noise model for every biomarker, and the same posterior draws
(iter) for every biomarker.
Because it is a genuine likelihood, its Hessian-based standard error
is valid without the cluster_var = ids_varname(pop_data) correction
the composite likelihood calls for.
The methodology article's "Multiple biomarkers" section now compares
the two on simulated data with known incidence. (#646)method = "joint" now refuses a curve_params that carries an iter
column for some biomarkers but not others.
Draws are paired by iter when every biomarker has it and by position
when none does; with only some, the intended pairing is unknown, and
the previous fallback to positional pairing silently combined draws
that the biomarkers carrying iter showed to be ordered differently.
n_t_steps now rejects Inf and values above the largest R integer.
These satisfied "a whole number at least 1" but became NA when
coerced for the C call, which then failed with a message naming an
argument position rather than the argument the caller had set.
A joint fit's log-likelihood graph (build_graph = TRUE) now uses the
same n_t_steps the fit was optimized with.
est_seroincidence()'s ... is shared between nlm()'s control
arguments and log_likelihood()'s, so the graph helpers were called
with explicit arguments only and never saw a caller's n_t_steps:
the plotted curve was drawn at the default quadrature.
No estimate was affected --- the graph is a diagnostic.
A joint fit made with a non-default n_t_steps now records it, so a
cluster-robust standard error recomputes each cluster's score under
the same quadrature the fit was optimized with.
The score previously used the default, pairing a sandwich middle
matrix built from one objective with a Hessian from another.
sim_pop_data_multi() no longer changes the calling session's
random number generator.
It sets up reproducible parallel streams with rngtools::setRNG(),
and with num_cores = 1 that loop runs in the caller's own process,
so the generator was left switched to "L'Ecuyer-CMRG"
after the call returned.
A later set.seed() then produced a different stream
than the same set.seed() had produced before the call,
silently changing the results of unrelated downstream work.
The generator state is now saved on entry and restored on exit.
Simulated output, and its reproducibility across num_cores values,
are unchanged. (#634)
est_seroincidence_by() now forwards ... to nlm()
when num_cores > 1.
The parallel branch assembled its est_seroincidence() arguments
without splicing in ...,
so optimizer tuning arguments such as iterlim were honored
when running serially and silently discarded when running in parallel,
and the two branches could return different estimates for one call.
Both branches now read the forwarded arguments from a single captured
list.
One consequence worth knowing: because ... is now sent to the workers,
an argument that cannot be serialized fails instead of being discarded
in silence, which matches what the serial branch already did. (#629)
est_seroincidence()'s cluster_var argument can now be pointed at
the subject id (e.g. cluster_var = ids_varname(pop_data)) to get a
cluster-robust standard error for a multi-biomarker fit that
accounts for within-person correlation across biomarkers.
log_likelihood() combines biomarkers by summing their marginal
log-likelihoods, which understates the true variance when biomarker
readings from the same person are correlated, as expected when they
share an infection history --- see #637.
A verbose fit with more than one antigen_isos and no cluster_var
now says so, and names the id column to pass.
The default behavior (no cluster_var) is unchanged, and its
standard error is unaffected. (#645)
Restored participant linkage across biomarker rows in the SEES
cross-sectional data and bundled examples. Public IDs are newly generated
pseudonyms; the restricted source identifier is never written to package
artifacts. as_pop_data() and set_id_var() now clarify that their ID
column must identify people rather than individual observations. (#650)
sim_pop_data_multi_cached() and est_seroincidence_by_cached(),
caching wrappers around the two most computationally expensive functions
in the package.
The first call computes and saves the result;
later calls with the same arguments load it instead of recomputing.
The cache is keyed on the arguments,
so changing any of them recomputes automatically.
Pass cache_rerun = TRUE to force recomputation.
Cache-control arguments carry a cache_ prefix
so the wrapped functions' own verbose argument remains reachable. (#631)refit_strata(), which re-fits a chosen subset of strata with
log-likelihood graphs attached.
It is the companion to caching a large fit with build_graph = FALSE:
graphs are attached per stratum, so they make a cached fit far larger on
disk, and the usual pattern is to cache without them and re-fit only the
strata you want to plot.
Strata are selected by the columns that define them rather than by index,
because count_strata() names strata positionally and a subset renumbers
them. (#632)curve_app() for visualizing antigen-antibody
kinetics models with real-time parameter sliders (#392).antibody_decay_curve() and pathogen_decay_curve() functions for
simulating antibody and pathogen decay over time (#392).plot_decay_curve() for plotting decay functions using ggplot2 (#392).t1f() (time to end of active infection) and
y1f() (peak antibody concentration) (#392).autoplot.sim_results() gains x_var, group_var, and color_var
arguments, letting users choose which columns map to the x-axis, group,
and color aesthetics instead of the previous hardcoded sample_size /
lambda.sim mapping.graph.curve.params() now uses the 5-parameter ab_5p() antibody response
model and supports units-aware curve parameters. (#393)ab_5p(), a 5-parameter antibody response model that supports
{units}-aware inputs (e.g. t = units::as_units(50, "days")), building on
the existing bt() active-phase helper. CI now installs the system
udunits2 library on macOS and Windows so the new units dependency can
compile there. (#393)sim_pop_data_2(), a sim_pop_data() alternative built on ab_5p()
that simulates each simulated individual's age (sim_age()) and time
since their last seroconversion (sim_time_since_last_sc()) directly,
rather than simulating an infection history. Both new helper functions,
and sim_pop_data_2() itself, accept units-aware inputs.sim_pop_data_multi() gained a sim_function parameter (default
sim_pop_data) so callers can select sim_pop_data_2() instead. (#393)Split the methodology article's combined "Likelihood and log-likelihood"
definition into two separate, independently cross-referenceable
definitions (#def-likelihood, #def-log-likelihood) --- previously
only the likelihood half had its own citable id.
Formalized the "Cluster-robust standard errors" section of the methodology article: the sandwich estimator now cites Huber (1967), White (1980), and the clustered-data extension by Liang and Zeger (1986), and the Hessian, score function, and other definitions and results in that chapter are now stated as numbered, cross-referenced Quarto theorem/definition divs instead of informal prose.
The methodology, scrub typhus, and antibody-response-model articles no
longer fetch their example data from OSF at render time --- the docs build
was failing whenever OSF was unavailable, on PRs that never touched the
affected vignettes.
n6cp3, hqy4v, u5gxh, and h5js4 are now vendored under
vignettes/precomputed/osf/; the two chunks that only needed rtw5k
filtered to iter < 50 now filter the already-bundled
typhoid_curves_nostrat_100 instead, since the two are identical once
filtered, so no separate copy of rtw5k needed vendoring. (#648)
Removed maintainer-facing implementation notes (OSF/vendoring rationale,
an internal variable-naming decision, why est_seroincidence_by_cached()
is called with build_graph = FALSE) from the R comments the methodology
article renders on the website, replacing them with reader-facing
comments. The notes worth keeping for future editors but with no
reader-facing equivalent moved into HTML comments, invisible on the
published page; a couple of purely build-time asides (e.g. "no network
access needed") were dropped outright as no longer worth keeping.
Listed sim_pop_data_multi_cached(), est_seroincidence_by_cached(), and
refit_strata() in the documentation site's reference index.
All three were exported and had help pages, but no section of
altdoc/reference.yml claimed them, so they were unreachable from the
reference index and the sidebar and fell into the trailing "Other" group.
Surfaced by altdoc::render_docs(), which warns about an unclaimed
non-internal topic; no CI check covers this. (#632)
Merged the "Simulation studies" article
(vignettes/articles/simulate_xsectionalData.qmd) into the methodology
article, which now demonstrates live everything it describes.
The methodology article previously showed serocalculator code in
non-executing chunks and closed with a static screenshot of the simulation
article's recovery study, while the simulation article ran that code without
deriving the theory behind it.
The estimation walkthrough now runs on simulated data where the true rate is
known, and the validation section runs the full multi-cluster recovery study,
the nlm() convergence checks, analyze_sims(), and the renew_params
bias caveat.
The retired article's URL redirects to the merged one. (#632)
The methodology article's simulations are cached to vignettes/precomputed/
via the new *_cached() wrappers, so a docs build reuses them instead of
recomputing once per output format.
Its simulation sections now use the bundled typhoid_curves_nostrat_100
rather than downloading the same curve parameters from OSF;
the two are identical once filtered.
The methodology article's reveal.js slides now show code, folded away by
default, instead of hiding it.
The Word output hides code by default, except in the demonstration chunks
that are never evaluated, which mark themselves echo: true so those
sections do not render empty.
Ported the full Quarto extension set from Morrison-Lab/rpt into
altdoc/_extensions/, registered project-wide in altdoc/quarto_website.yml's
new filters: list: d-morrison/div-anchors and d-morrison/equation-anchors
add hover permalinks to theorem/definition divs and numbered equations;
sun123zxy/callouty-theorem (+ coatless-quarto/custom-callout) render the
methodology vignette's existing #def-/#exm- divs as colored callout
boxes instead of plain numbered text; d-morrison/revealjs-html-links adds a
link back to the standalone HTML page on the methodology vignette's
RevealJS slides.
The slidebreak extension (already in use) moved from
vignettes/_extensions/ to altdoc/_extensions/ alongside the rest, so it
too is now a project-level filter instead of a per-document one.
(#585, #586, #587, #588, #589)
Took the sidebar fold control from altdoc instead of keeping a copy here.
altdoc/sidebar-fold.html and the matching block in altdoc/styles.css are
replaced by include-in-header: $ALTDOC_SIDEBAR_FOLD, which altdoc stages
at render time with script and style together.
The same pair had been copied into ucdavis/bcs, and the two copies had
already drifted -- this repo changed its copy to start folded and nothing
carried that across.
The sidebar still starts folded, now via sidebar_fold: collapsed in
altdoc/reference.yml, so what used to be a source-level divergence is a
one-line setting.
Declared the reference manual's grouping once, in a new altdoc/reference.yml
(#610).
It used to live in two hand-maintained places that nothing kept in step: the
altdoc/reference.qmd index page and the Reference block of
altdoc/quarto_website.yml.
Adding a topic to one and missing the other rendered cleanly and raised no
warning, which is how it went unnoticed on #392.
altdoc now builds both surfaces from the single file, so the two cannot
disagree, and warns about any exported topic no section claims rather than
leaving it off the site in silence.
The published grouping is unchanged: the same nine sections, the same 42
topics, in the same order.
Moved the altdoc dependency off the recursive-qmd-search branch and onto
the default branch, which is what supplies the grouped sidebar above.
That branch has no commits the default branch does not already contain, so
it was holding the docs build behind for nothing.
The branch was named in three places -- Remotes, Config/Needs/website,
and the r-packages input of the docs workflow -- and changing one of them
alone makes the build fail to resolve rather than fall back, since pak
reads the two as conflicting requirements for the same package.
Started showing each topic's name alongside its title in the sidebar.
Titles alone left as_pop_data and load_pop_data as adjacent entries
reading identically, and the same for as_noise_params and
load_noise_params, with nothing to tell a reader which was which.
Stopped .gitignore from hiding new files added under altdoc/.
A bare altdoc entry ignored the whole source directory; the files already
in it stayed tracked only because they predate the rule, so the omission was
invisible until a new one was added and silently skipped by git add.
altdoc/.gitignore already covers the real build artifacts there
(_site/, .quarto/, pkgdown.yml, freeze.rds), and _quarto is still
ignored separately, so the entry protected nothing.
Added a control that folds the documentation website's sidebar away, giving
the content the width it held (#622). Quarto's collapse-level folds
sections within the sidebar; it has no control for the sidebar itself on a
website, so the sidebar held a fixed grid column at every viewport wide
enough to show it. The new navbar button hides it and moves the content's
grid start line into the vacated columns, which at a 1400px viewport
widens the content from 630px to 922px. The state is kept in
localStorage, so it survives navigation between pages. The script that
restores it is included in the page header rather than after the body, so a
folded sidebar never flashes into view.
Below Quarto's 992px breakpoint the button is hidden: the sidebar is already
a drawer laid over the content there, so it holds no width to reclaim.
The documentation website's sidebar now starts folded. Readers arrive on a page to read it, and the navbar already carries the same destinations, so the wider content column is the better default; unfolding the sidebar is remembered, so the choice is still made once per reader rather than once per page.
Fixed two dead external links. The methodology article credited the
Salmonella Typhi photo to a Wikimedia Commons page that was deleted on
2026-03-11; the deletion discussion confirms the image is CDC/PHIL
public-domain work (PHIL ID 2115), so the credit now cites PHIL directly
instead of the dead page. The Ubuntu R install snippet in
.github/copilot-instructions.md fetched pubkey.gpg, which CRAN no longer
serves (404); it now uses marutter_pubkey.asc.
Figures on the documentation website now open an enlarged lightbox view when
selected. Enabled site-wide (lightbox: true) across every format, including
the revealjs slides, and covering both cross-referenced figures and plain
images (#584).
Restored the R code in the documentation website's vignettes and articles.
vignettes/_metadata.yml set echo: false for the html and docx
formats, which applied to every file under vignettes/, so the published
tutorials rendered as prose and figures with no code at all, and the
methodology article's "Estimating seroincidence" section --- whose only
content is a non-evaluated code chunk --- rendered as an empty heading.
Reviewed and revised the methodology article: corrected the standard-error
description (the inverse negative Hessian is the variance, not the
standard error) and the "truncated by age" characterization of the latent
infection-time distribution, added narrative to the previously code-only
"Estimating seroincidence" and "Multiple biomarkers" sections, moved
"In-progress work" out of the "Validation" section into its own section,
promoted "References" to a top-level section, and restored the captions and
image credits on the two typhoid figures (adjacent images with no blank line
between them are parsed as one paragraph, which drops their captions).
Fixed dead documentation links that still used the old pkgdown site layout.
The site root is now a redirect page, so /articles/…, /reference/index.html,
/news/index.html, and /CONTRIBUTING.html no longer resolve; links from
within the site are now relative so they stay on the reader's docs version,
and the links in the README point at paths that exist. Also corrected the
description in the README of which URL serves which docs version, and fixed
the link to the contributing guide in the pull request template.
Fixed a dead link in the README: the in-development documentation pointed at
/main/, which has served nothing since #504 moved development docs to
/dev/. Also removed a duplicated "the" in the same sentence. (#604)
The documentation site now deploys multiple versions side by side, following
rpt's pattern: pushes to main deploy development docs to /dev/,
published releases deploy stable docs to /latest-tag/ (plus an archived
/vX.Y.Z/ copy), and the site root redirects to whichever was deployed most
recently. A "Versions" navbar dropdown links between them. (#504)
Updated the documentation site configuration to promote "Get started",
"Reference", and "News" in the top navigation, and added a grouped
reference.qmd index plus grouped sidebar reference sections that
exclude internal-only topics.
The documentation site's reference index page is now titled "Package index" rather than "Reference", matching the old pkgdown site and distinguishing the page from the navigation entry that links to it. (#594)
Added a "Citation" entry to the documentation site's sidebar. The citation
page was previously reachable only from the navbar "More" dropdown, unlike
rpt and the default sidebar altdoc ships, which both list it. (#594)
Links to the documentation site's old /main/ paths now resolve again.
Before the altdoc migration the development docs were published under the
branch name, so they lived at /main/; they now live at /dev/, which left
every /main/... link dead. The site now serves a root 404.html that
redirects any request under /main/ to the same path under /dev/, deep
links included. Redirection requires JavaScript; without it the page renders
as a plain not-found notice linking to the documentation home page. (#599)
Updated the documentation site's dark-mode styling to match rpt by adding
the same inline-code color override used there, improving contrast on the
home page and article text.
Added introductory lecture slides to the methodology vignette
("Estimating Incidence Rates from Cross-Sectional Serosurveys").
The methodology vignette now loads its slidebreak shortcode explicitly so
the shortcode no longer leaks into HTML output, and rendered vignettes now
suppress package startup messages.
Fixed the date in the vignettes' title blocks, which rendered as
"Invalid Date" (most visibly on the methodology slides' title slide).
vignettes/_metadata.yml set the date with an inline R expression, but
Quarto merges that file into the document metadata without a knitr pass,
so the expression was never evaluated; the date now uses Quarto's own
today keyword. (#597)
Restored the methodology vignette's docx download link, which had been
dropped on the (mistaken) assumption that it needed its own docx: format
block; it renders fine via the docx: default already declared in
vignettes/_metadata.yml.
Completed the measurement-noise model in the methodology vignette
(multiplicative relative error), added a "Combined biological and
measurement noise" section, and added a "Noise and never-infected
subjects" section explaining that additive biological noise spreads a
never-infected subject's measured response over a positive range while
multiplicative measurement noise leaves a true zero at zero. (#561)
Corrected the documentation of the eps measurement-noise parameter
(in example_noise_params_pk/example_noise_params_sees and the
vignettes): eps is the bound on the relative measurement error
(Unif(-eps, eps)), not a coefficient of variation. A measured CV
corresponds to eps = sqrt(3) * CV. (#563)
Added the never-infected density under combined biological and
measurement noise to the methodology vignette: the piecewise
closed form for y_obs = eps_b * (1 + xi), matching Teunis and van
Eijkeren (2020) Equation 19 and verified to integrate to the
never-infected probability. (#567)
Made the never-infected term explicit in the "per-person likelihood"
slide of the methodology vignette: the observed-data likelihood
integral is now shown split into its continuous (ever-infected) and
discrete (T = NA, never-infected) parts, with p(Y=y | T=NA)
defined as a point mass at zero (before noise). (#567)
Explained, in the "Biological noise" section of the methodology
vignette, why the biological-noise width nu is estimated as the
95th percentile of negative controls: Teunis and van Eijkeren (2020)
show that a uniform noise model only needs to match the true noise
distribution's width, not its exact shape, and note that this width
is difficult to verify against a mixed (ongoing-seroresponse)
population -- motivating estimation from a clean negative-control
panel instead. Also noted that the specific choice of the 95th
percentile (rather than, e.g., the 99th or the sample maximum) is an
adopted convention, not a result derived or optimized in the paper.
(#567)
Added the conditional variance Var(y_obs | y_true) for the combined
biological- and measurement-noise model to the methodology vignette,
derived from the independent-product-variance identity and checked
against both single-source special cases already in the vignette.
(#571)
Added Var(y_obs | T=t), marginalizing over between-person heterogeneity
in y_true, to the methodology vignette: derived via the law of total
variance from the Var(y_obs | y_true) formula above, with the
between-person heterogeneity term Var(y_true | T=t) introduced
symbolically (it has no closed form in this framework, since
serodynamics represents curve-parameter heterogeneity as an empirical
posterior sample rather than a stated parametric distribution). Clarified
that the longitudinal model's residual variance is constant on the log
scale conditional on individual random effects, while random waning rates
can induce time-varying marginal population variance that serocalculator
carries forward by averaging over kinetic-parameter draws. (#571)
Moved f_dev0()'s @examples block to a separate example file
(inst/examples/exm-f_dev.R), following the convention already used by
other functions in this package. (#393)
log_likelihood()
equals the sum of the per-biomarker values.
This is the composite (independence) likelihood behavior described in
#637: the code sums per-biomarker marginal log-likelihoods rather than
integrating a shared latent infection time, and this identity should not
change silently if that ever does. (#637)NAMESPACE and DESCRIPTION with roxygen2 8.1.0, which groups
each package's importFrom() symbols into a single multi-line directive
instead of one directive per symbol.
The change is purely one of formatting: the exports, the S3 method
registrations, the compiled-library declaration, and all 75 imports are
unchanged.
docs-check regenerates the documentation and fails when a tracked file
differs afterward, so every run of it since roxygen2 8.1.0 was published
on 2026-08-04 had failed.
Green docs-check runs on other open pull requests are stale rather than
contradictory: each of them predates that release. (#636)@claude agent bot.
.github/workflows/claude.yml's reactive triggers are commented out and its
job carries if: false, so no comment, issue, or review event invokes the
agent, and neither does a manual dispatch (the reusable workflow runs
unattended on workflow_dispatch by design).
Reviews are the only Claude capability left, and they run on request only:
automatic review on pull-request activity is off, and a review starts when a
collaborator comments /review on a pull request.
That dispatch now pins the review run to the pull request's head branch, so
its check-run lands on the right commit.check-readme.yaml
cited a file that was deleted from IndrajeetPatil/statsExpressions's
default branch when its CI moved to reusable workflows; the citation is now
pinned to a commit where the file exists. test-coverage.yaml cited a GitHub
Actions run URL, which expires after roughly 90 days; it now cites the
upstream workflow file..github/CONTRIBUTING.Rmd; .github/CONTRIBUTING.md is now the
hand-maintained source. The .Rmd executed no code (its only chunk was
eval = FALSE), so it rendered to markdown identical to a hand-written file
while adding a source/generated pair with no CI check to keep the two in
sync. (#613)methodology.qmd) formats. Fixed the HTML/revealjs output-filename collision by specifying output-file: methodology-slides.html for revealjs in methodology.qmd's frontmatter; docx goes in _metadata.yml globally since .docx has no collision risk. (#503)news.yaml now calls the central
d-morrison/gha check-news.yml@v2
reusable workflow (bumped from the initial @v1 pin, which predated gha's
fix for this repo's no-changelog label convention) instead of invoking
UCD-SERG/changelog-check-action@v2 directly. (#537, #593)claude.yml and claude-code-review.yml now call the central
d-morrison/gha claude.yml@v2 and
claude-code-review.yml@v2 reusable workflows instead of carrying their own
copy of the agent/review machinery. (#549)docs.yaml now calls the central
d-morrison/gha
altdoc-multiversion-docs.yml@v2 reusable workflow instead of carrying its
own ~360-line copy of the build/deploy logic, and the local
.github/scripts/generate_version_dropdown.py and
generate_multiversion_landing_page.py copies are deleted in favor of the
composite actions in that repo. Fixes made centrally now reach this package
instead of stopping at rpt. Rewrote .github/MULTI_VERSION_DOCS.md, which
still described the pkgdown setup replaced during the altdoc migration.
(#595)methodology vignette's LaTeX macros now come from the shared
d-morrison/macros git submodule
(included via {{< include ../macros/macros.qmd >}}) instead of a local
vignettes/articles/_macros.qmd. The deck adopts the shared macro
vocabulary (e.g. \dens for the density function in place of the local
\pdf). (#534)claude-code-review.yml now sets allowed_bots: github-actions[bot] so the review still runs (and posts feedback) when claude.yml re-dispatches it on an @claude review comment; previously the bot-initiated dispatch aborted with "Workflow initiated by non-human actor".claude.yml now grants the @claude agent the file tools (Read/Glob/Grep/Edit/MultiEdit/Write) in --allowedTools; previously the agent could run checks/git/gh but not edit files, so it fell back to posting diffs for manual application.iterate Claude Code skill (.claude/skills/iterate/) for driving a PR to a clean review verdict.@claude agent and PR-review GitHub Actions workflows (plus Claude/Copilot config: CLAUDE.md, .claude/ settings and slash commands, and path-scoped .github/instructions/) from the UCD-SERG qwt template, adapted to this package. (#523)claude[bot] pushing a commit). (#519)lint-changed-lines CI workflow (calling the reusable
d-morrison/gha
lint-changed-lines.yml@v2 workflow), which flags lint issues only on the
lines a PR actually adds or modifies (rather than whole changed files, as
lint-changed-files does). This lets lint rules be adopted or tightened
incrementally as code is touched, instead of forcing a repo-wide reformat.
Intended to replace lint-changed-files as the lint gate once branch
protection is updated to require it. (#558)docs.yaml's job-level concurrency: group, which resolved to the
same string as the workflow-level group on every non-pull_request event and
so deadlocked the docs job: the run already held that group, so the job
could never acquire it and was failed instantly with no logs. This blocked
every versioned documentation deploy (/dev/, /latest-tag/, /vX.Y.Z/).
The workflow-level group already serializes runs by PR number or ref. (#590)sim_pop_data() and sim_pop_data_multi() now produce identical results
across operating systems. Simulated inter-infection times are now rounded to
whole days, so the number of random draws consumed no longer depends on
platform-specific floating-point results of log() (which previously
shifted the random-number stream out of sync and made simulated values, and
their snapshots, differ between macOS, Windows, and Linux). Simulated
values change slightly as a result of this fix. (#447)cluster_var columns as
multi-way clustering instead of collapsing them to a single interaction.
One-way subset terms now use the CR1 small-sample correction by default,
the floor to model-based variance is optional, and debug output now exposes
the multi-way variance decomposition used in the final standard error.
A negative multi-way variance estimate is now floored at 0 (with a warning)
instead of producing NaN standard errors, and an unavailable subset
variance (for example from a degenerate Hessian) now warns and yields a
missing standard error, instead of a silent NaN.
With floor_to_standard = TRUE it falls back to the model-based variance
instead, unless that variance is itself unusable (e.g. from the same
degenerate Hessian), in which case it also yields a missing standard error.
(#543)strat_ests_barplot() (xlab) and
strat_ests_scatterplot() (ylab) to say "seroincidence" rather than
"seroconversion"/"incidence".load_noise_params() and load_sr_params() now fail gracefully with informative messages when internet resources are unavailable, complying with CRAN policy (#505)autoplot.seroincidence() now raises its "graphs cannot be extracted" error
via cli::cli_abort() rather than stop(), so the message is formatted as a
cross bullet naming the problem and an info bullet naming the
build_graph = TRUE argument that was missing (#392).antibody_decay_curve(), pathogen_decay_curve(), t1f(), and y1f() now
validate their parameters (non-negative values, mu_y != mu_b) and raise an
informative cli::cli_abort() error instead of silently returning NaN or
dividing by zero (#392).plot_decay_curve() now respects its xmax argument instead of always
plotting to x = 100 (#392).dplyr::is.grouped_df() usage with dplyr::is_grouped_df() in df_to_array() for compatibility with newer dplyr releases.cluster_var and stratum_var parameters to est_seroincidence() and
est_seroincidence_by() to support cluster-robust standard error estimation.
When cluster_var is specified, summary.seroincidence() automatically computes
cluster-robust (sandwich) variance estimates to account for within-cluster
correlation in clustered sampling designs such as household or school-based surveys.cluster_var parameter now accepts multiple variables (e.g., c("school", "classroom"))
for multi-level clustered sampling designs. Cluster-robust standard errors will account
for all specified clustering levels.summary.seroincidence() where cluster-robust standard
errors caused [] notation in column names (SE[,1] instead of SE).se_type column to summary.seroincidence() output to clearly indicate whether
"standard" or "cluster-robust" standard errors are being used.est_seroincidence_by() to properly pass cluster and stratum variables through
to stratified analyses. Previously, these variables were dropped during data stratification,
causing errors when trying to use clustering with est_seroincidence_by()..compute_cluster_robust_var() to R/compute_cluster_robust_var.Rggpubr with patchwork for arranging multi-panel plots,
removing the indirect ggrepel transitive dependency.Added support for cluster-robust standard errors in est_seroincidence() through
new cluster_var and stratum_var parameters. When cluster_var is specified,
summary.seroincidence() automatically computes cluster-robust (sandwich) variance
estimates to account for within-cluster correlation in clustered sampling designs
such as household or school-based surveys.
Added compare_seroincidence() function for statistical comparison of seroincidence rates
htest format when comparing two single estimatesImplemented multi-version pkgdown documentation with version dropdown menu
Added chain_color option to graph.curve.params() to control MCMC line color (#455)
Made graph.curve.params() the default sub-method for autoplot.curve_params() (#450)
Added log_x and log_y options to graph.curve.params() sub-method for
autoplot.curve_params() (#453)
Extended sim_pop_data_multi() to loop over multiple sample sizes (#444)
Added new functions analyze_sims() and autoplot.sim_results() (#444)
Rename estimate_scr() to est_seroincidence_by() (#439)
Rename estimate_scr() to est_seroincidence() (#432)
Rename argument curve_params to sr_params for estimation functions (#424)
added documentation for count_strata() (#431)
Rename as_curve_params() to as_sr_params() (#421)
Rename load_curve_params() to load_sr_params() (#421)
added default for xvar in "scatter" option for autoplot.seroincidence.by() (#417)
Extended autoplot.summary.seroincidence.by() to include types for either scatter or bar plots of stratified results (#397)
added option to add lines using group_var input to autoplot.summary.seroincidence.by() (#410)
autoplot.pop_data(type = "age-scatter") now shows legend at bottom (#407)
autoplot.pop_data(type = "age-scatter") now facets by antigen isotype (#406)
Rename est.incidence.by() to estimate_scr_by() (#389)
Rename est.incidence() to estimate_scr() (#389)
Improved warning messages for get_biomarker_names_var()
Added get_*() extractor functions to API (#380)
Added optional CI error bars to autoplot.summary.seroincidence.by() (#372)
Improved y-limit calculation in graph.curve.params() (#368)
Added option for graph.curve.params() to show all curves (#368)
Added color-coding for graph.curve.params() (#383)
Added quantiles parameter to graph.curve.params() and corresponding test in test-graph.curve.params.R (#434)
Removed warn.missing.strata() from API (#366)
Added more details about contributing PRs in Contributing.md (#280)
Added warnings for missing biomarker data (#168):
Split dev and release websites into:
Fixed citations in methodology.qmd article (#360)
Added outline to pkgdown website (#353)
Added verbose option for summary.seroincidence() and
summary.seroincidence.by() (#348)
Extended simulate_xsectionalData.Rmd article to explore
renew_params = TRUE vs renew_params = FALSE (#348)
Renamed variables for consistency (#281, #373):
sim.cs() -> sim_pop_data()sim.cs.multi() -> sim_pop_data_multi()graph.curve.params() where MCMC samples
with the same iteration number from different MCMC chains
would get merged by ggplot2::aes(group = iter) (#382)switched expect_snapshot_data() to an internal function due to CRAN errors (#464)
generalized ab1()
added codecov/test-results-action to test-coverage.yaml workflow
added test for censored data in f_dev() (#399)
added test for autoplot.curve_params()
added test for graph.curve.params() (#368)
reverted Readme source file from qmd to Rmd.
switched pkgdown GHA from any::pkgdown to r-lib/pkgdown (i.e., dev version) (#359)
added test for summary.seroincidence.by() (#352)
Started checking for use of base pipe instead of magrittr pipe by linter (#347)
Removed ldpar() from API (#345)
Added test for sim.cs() (#344)
Added test for internal function ab() (#342)
Reverted name change ldpar()-> row_longitudinal_parameter() (#343)
Removed function 'get_additional_data()' (#332)
Updated documentation examples to include csv files (#328)
Added csv files for use in documentation examples (#329)
Added serocalculator_example() function to help locate example data files (#329)
Fixed a bug in computing the antibody response curve when $r=1$ (#323)
Added example datasets with documentation for examples and testing (#314)
Improved error messaging for autoplot.pop_data() (#234).
Clarified package installation instructions in scrub typhus vignette (#234).
Add as_noise_params (#228)
Updated simulate_xsectionalData.Rmd (linting, removing deprecated functions)
(#289)
Added default value for antigen_isos argument in log_likelihood() (#286)
Updated enteric fever example article with upgraded code and visualizations (#290)
Added template for reporting Issues
(from usethis::use_tidy_issue_template()) (#270)
Added template for pull requests (from https://github.com/bcgov/ssdtools) (#265)
Updated documentation to align with previous CRAN feedback (#328)
Updated tests to use internal testing datasets instead of external links (#328)
Updated test-coverage.yml GHA action to current r-lib standard (#330)
Change default pipe setting (#312)
Add test for missing strata in est.incidence.by (#227)
Added snapshot_value test for est.incidence() (#315)
Sped up lint-changed-files GitHub Action (#317)
Added online preview builds for PRs that change the pkgdown website (#309)
Added test-autoplot.pop_data test (#234)
created unit test for df_to_array() (#276)
fixed dplyr::select() deprecation warning in df_to_array() (#276)
Added devtag to package (using devtag::use_devtag()) (#292)
Added @dev tag to ?df_to_array() (#292)
Generalized get_() and set_() methods to be general-purpose
(no S3 class-specific methods needed yet) (#274).
Updated GitHub Action files and reformatted DESCRIPTION (#268)
Added .gitattributes file (https://git-scm.com/docs/gitattributes)
copied from https://github.com/tidyverse/ggplot2
Added QR code to README.qmd
Added additional automated checks through GitHub actions, including:
README.qmd still compiles
(advice from preventive-r-package-care) (#259)NEWS.md for updated change log (#257)Added test-summary.pop_data test
Modified test-est.incidence test
Added stratification to summary.pop_data
Added verbose option for check_pop_data(), changing default behavior
to avoid printing an OK message.
Renamed llik() to log_likelihood()
Renamed fdev() to f_dev()
Renamed df.to.array() to df_to_array()
Renamed getAdditionalData() to get_additional_data()
Removed clean_pop_data() function
Remove clean_pop_data() dependency functions documentation examples
Added age, value, id and standardize arguments to load_pop_data()
Added the following methods to pop_data class:
set_age()set_value()set_id_var()get_age()get_values()ids()get_age_var()get_values_var()ids_varname()Added additional warnings to load_pop_data()
Added scales::pseudo_log_trans() to autoplot.pop_data() to avoid log 0
Added test-est.incidence-status.R test to check output when standardize option is FALSE on load_pop_data()
Replaced column name comparison on check_pop_data() to use attribute name on pop_data class
n_points argument to plot_curve_params_one_ab()type = "age-scatter" option for autoplot.pop_data()serocalculator vignetteSpell-checking of function documentation and tutorial articles.
Added functions and methods:
load_pop_data()check_pop_data()summary.pop_data()autoplot.pop_data()load_curve_params()Renamed graph.decay.curves.by() to autoplot.curve_params()
plot() methods have been renamed to autoplot(), matching general convention for ggplot2-based graphics.
added visualization of curve parameters
sim.cs() now has format argument to specify long or wide format for output.
Fixed bug in passing antigen_isos from est.incidence.by() to est.incidence().
Rolled back required R version from 4.2 to 4.1
Forking from the seroincidence package and adding Teunis et al 2020 approach.