This release adds support for quantal endpoints, introduces configuration presets, and changes how model selection works. As model selection has changed, results with the new version may be slightly different. The changes are listed in order of importance.
The model.list argument had no effect. toxdrc_modelling() accepted
model.list but omitted it from the list it returned, so modelcomp() always
fell back to its internal defaults. Custom model lists are now used in its place.
The default model list for continuous data is now LL.4 alone, rather
than LL.4, LN.4, W1.4 and W2.4. Model comparison is opt-in. To restore
comparisons, supply more than one entry to model.list to restore it.
getECx() now defaults to type = "relative", matching
toxdrc_modelling(). Previously the two disagreed, so calling the function
directly and running the pipeline gave different answers from the same
arguments.
runtoxdrc() gained the N, endpoint and preset arguments, and its
configuration arguments now default to NULL so that a preset can supply
them. Named calls are unaffected; positional calls after quiet will shift.
model.list must be a named list whose names match the model each entry
holds, for example list("LL.4" = LL.4()). Its default is now NULL and is selected
based on endpoint type.
Naming a column in IDcols that does not exist is now an error. Previously
averageresponse() warned and continued, so the column was quietly absent
from the results.
A reference, blank or control label that does not match the data is now an
error. Previously it resulted in NaN through the threshold calculation.
Configuration helpers validate their arguments, so calls such as
toxdrc_qc(cv.flag = "yes") or toxdrc_modelling(level = 95) now fail
rather than being accepted.
Quantal endpoints. Set endpoint = toxdrc_endpoint(type = "binomial")
and give the group sizes with N to fit binary data such as mortality.
Models are fitted with drc::drm(type = "binomial"), weighted by group size,
and default to comparing LL.2 against LL.3u. Replicates are pooled by
group size rather than averaged, so a proportion from 30 of 60 counts for
more than one from 1 of 4. The response may be given as a proportion or, with
response.type = "count", as the number affected.
Blank correction, normalization and Grubbs' outlier removal are refused for
quantal data, each with an error naming the alternative. "Res var" is
unavailable as model.metric, since a binomial fit has no residual variance.
interpolateECx() estimates an effect concentration by log-linear
interpolation between the bracketing concentrations, for quantal tests where
no concentration produced a partial effect and no model can be fitted. The
EC50 is the geometric mean of the two, which does not depend on the unknown
shape of the curve. Enable it in the pipeline with
toxdrc_modelling(interpolate = TRUE); such estimates are marked
best_model_name = "interpolated" and carry no confidence interval. Effect
levels other than 50% are computed with a warning, since with no partial
responses they largely restate the bracketing concentrations.
toxdrc_preset() returns complete configurations for common designs:
"continuous", "quantal", and "normalized" for blank-corrected data
expressed relative to a control. Pass one as preset to runtoxdrc();
anything given explicitly overrides it. Presets are ordinary lists and can be
printed to see every setting. Contact the package authours for support with
additional presets.
acutetox, a simulated acute lethality dataset with a quantal endpoint.
Its three substances exercise a normal fit, the no-partial-response case that
triggers interpolation, and control mortality that favours LL.3u. Counts are
constructed deterministically from known curves, so the generating values can
be recovered exactly. See data-raw/acutetox.R.
getECx() returned a bare data frame when drc::ED() failed, even when
list_obj was supplied, so runtoxdrc() received the wrong object for that
subset. It now returns the list.
The placeholder returned when no estimate could be produced had different
column names from a successful result, because data.frame() renamed
"Effect Measure" and "Std. Error" by default.
Condensing results failed when a run produced both subsets with point estimates and subsets without, because the two produced different columns.
Fields such as model and model_df disappeared from an entry when nothing
could be fitted, because assigning NULL to a list element removes it. They
are now present and NULL.
mselect2() returned the baseline model twice, once in its own right and
once as a member of the comparison list, and collapsed to a vector when only
one model was supplied.
A failed lack-of-fit test aborted the whole run. drc::modelFit() performs
its own optimisation and can fail on data the model itself fitted; it is now
caught and recorded as NA.
runtoxdrc() failed when IDcols was not supplied. The whole dataset is now
treated as a single subset.
Model comparison was fragile in a way that could silently produce a table of
NA scores. mselect2() refits candidates with update(), which
re-evaluates the model's stored call, so models must be fitted in a way that
leaves that call resolvable.
With quiet = TRUE, drc's own reports of failed optimisations are no longer
printed. They are written directly to the console rather than raised as
conditions, so neither suppressWarnings() nor suppressMessages() affected
them.
Errors are raised as classed conditions inheriting from toxdrc_error, so
they can be caught and tested by class rather than by matching message text.
Messages name the offending value and, where useful, the alternative.
Function documentation revised throughout, including corrected cross references and several malformed help pages.
Test coverage expanded substantially, including the previously untested internals and the numerical plausibility of estimates rather than only their structure.