shewhart_regression() with model = "gompertz" or "logistic":
the fitted value of the first row of a phase is now the difference
of the fitted cumulative curve, C_hat(1) - C_hat(0), like every
other row. Since audit #35 it was C_hat(1) - 1, which assumes the
fitted curve passes through the origin; a phase that starts
mid-wave is fitted by a curve well above 1 at .N = 0, and the
whole fitted cumulative value landed on the first day (137 deaths
for 28 observed in Pernambuco, 2020-04-15). Centre line and limits
change on the first row of such phases only, and in Phase II
nothing changes.dummy no longer closes phases too
short for the model. A 7-level factor adds 6 coefficients, and the
old minimum of n_consec + 1 rows (8 for "we_seven_same") fitted
a trend-plus-weekday model exactly, with sigma = 0. A phase now
needs at least twice its number of coefficients before it can be
closed, and the piece after the cut at least the number of
coefficients plus 2. Without a covariate the thresholds are
unchanged, so charts without dummy are identical.phase_changes with a covariate) now
extrapolates the previous phase with a warning, instead of drawing
limits of width zero. A base phase that short is an error.?shewhart_arl
(10.1080/00401706.1987.10488266; the old one pointed to another
paper).shewhart_regression() gains limits_scale = c("original", "model").
With "model", sigma comes from the moving ranges of the residuals
on the transformed scale of the model's left-hand side, the band
g_hat +- 3 sigma is formed there and back-transformed: for
model = "log" the multiplicative, asymmetric bands of Perla et al.
(2020) and Ferraz et al. (2020), whose lower limit never falls below
0. .sigma is then on the model scale, the new columns
.model_value / .model_center hold what the runs rules are
applied to, and the rules run on that scale. For linear, Gompertz
and logistic models both options coincide. The default is unchanged.log(), log10(), log2(),
log1p() or sqrt() of the response (plus a constant, optionally in
I()) now have their fitted values back-transformed to the scale of
the data; previously the centre line stayed on the model scale.monitor() on a regression chart honours the stored limits_scale
and lower_bound (both now kept in metadata), so Phase II limits
are exactly the constructor's forward projection of the last phase.shewhart_regression(phase_changes = integer(0)) fits a single
phase without detection and needs only 3 observations, so a
prospective replay can calibrate one phase at a time with
calibrate() and judge the following days with monitor()."log", "loglog" and "auto" (when it picks log) stop with a
clear error naming the first negative value instead of producing
NaN limits; also in monitor()..phase_label of a regression chart with a Date (or date-time)
index carries the end of each phase: "Base (until 2020-05-11)",
"Phase 1 (until 2020-05-18)", ..., "Monitoring" (pt "até", es
"hasta", fr "jusqu'au").autoplot() for regression charts gains phase_dates (NULL:
automatic for a date index; TRUE / FALSE force it) and
legend_position = c("top", "inside"); "inside" stacks the legend
in the top-left corner of the panel, as in the articles' figures.
Dated labels at the top wrap to rows of three.cvd_brazil: daily new COVID-19 deaths for Brazil,
Pernambuco and Sao Paulo, 2020-02-25 to 2020-12-31, from Wesley
Cota's covid19br compilation of the Ministry of Health bulletins. The
raw values are kept, including one PE correction of -37 deaths on
2020-09-03.vignette("article-charts"): reproduces the charts of Ferraz et al.
(2020, SBPO and Revista Brasileira de Estatistica) -- the unadapted
individuals chart, Brazil and Recife with the articles' phases
(legend identical to the figures) and with automatic detection,
Pernambuco and Sao Paulo, and the "Monitoramento" segment as a
calibrate() + monitor() projection -- with a table of what
differs from the originals (closes #2).vignette("prospective-replay"): replays the articles' "simulation"
of prospective monitoring day by day with calibrate() /
monitor() (frozen limits and daily refits), compares the phase
dates with the articles' and with phase_rule, and adds a Monte
Carlo study of the strategy on Poisson counts with known change
points: spurious phases, detection delays, and the in-control ARL
of the seven- and nine-point rules against 2^k - 1 (closes #3).shewhart_capability() on Xbar-R / Xbar-S charts no longer multiplies
the chart's sigma by sqrt(n) (it is already the per-individual
sigma), and computes the mean and Pp/Ppk from the individual
measurements instead of the subgroup means. Cp was depressed by
sqrt(n) and Pp could be Inf. Subgroup charts now carry their
individual measurements in metadata$values (#2).shewhart_capability() bootstrap intervals re-estimate sigma within
in every replicate with the chart's own estimator (whole subgroups
resampled for Xbar charts, consecutive pairs for individual charts).
The Cp/Cpk interval used to be an interval for Pp/Ppk. Capability now
errors for chart types where it is undefined (attribute, regression,
multivariate) (#24).monitor() on an I-MR chart now returns the moving-range columns
(.mr, seeded with the last Phase I value, and the stored MR limits),
so autoplot() and as_plotly() work on Phase II I-MR charts (#3).limits = "binomial" /
"poisson") flag Nelson 1 against the plotted exact limits, not
against 3 sigma; monitor() keeps the exact method instead of
falling back to 3-sigma limits (#10).as_plotly() places the regression
legend below the plot (#12, GitHub issue #1).NA does not fire (#14).glance()$pct_violations is now the share of points flagged by at
least one rule (mean(.flag_any)) and can no longer exceed 1 (#17).tidy() on a regression chart follows the documented
chart / line / value schema (long format, with .phase and
endpoint columns) (#18).as_plotly() forwards locale, show_violations and
show_sigma_zones to autoplot() (#19).show_sigma_zones = TRUE now draws the 1- and 2-sigma zones on the
top panel of I-MR, Xbar-R and Xbar-S plots (#20).shewhart_p() and monitor() reject subgroups with n = 0 instead
of silently producing NaN proportions (#32).lubridate and vdiffr removed from Suggests (unused).inv_box_cox() gains an example; cran-comments.md describes the
1.3.0 submission.phase1-phase2, getting-started,
variables-charts, attributes-charts, diagnostics and box-cox
vignettes (#37).monitor() on a regression chart no longer restarts the
within-phase position .N at 1: Phase II continues from the last
position of the last Phase I phase, so an in-control continuation is
predicted on the extrapolated trend instead of the start of the
phase (audit #1). The last-phase .N is stored in
metadata$phase_n_end.monitor() on a regression chart now uses the residual sigma of the
last phase (the phase whose fit it extrapolates), stored in
metadata$phase_sigma, instead of the median sigma across phases
(audit #11). sigma_hat of the Phase II object is that sigma..N) and inherits its sigma, instead of
restarting the previous curve at .N = 1 with a sigma estimated
from 1-2 residuals. A NULL fit no longer deletes its slot in
$fits, which shifted every later phase (audit #34).calibrate(trim_outliers = TRUE) now trims a running copy of the
data, so violation positions of a trimmed fit are mapped to the rows
that fit was built on. Previously an observation dropped in one
iteration could come back in the next and the loop oscillated until
max_trim_iter. Subgrouped charts (Xbar-R, Xbar-S, subgrouped
Hotelling) drop whole subgroups instead of individual rows, which
used to abort with "unequal sizes" (audit #4).shewhart_regression(start_base = ) is no longer ignored when
phase_changes is supplied. start_base now defaults to NULL:
10 with automatic detection; with phase_changes, the base phase
ends at the first supplied change unless start_base is given
explicitly, in which case it adds a cut (audit #21).model = "auto" no longer maps a square-root Box-Cox lambda (~0.5)
to "loglog", a transform stronger than log. Lambda is rounded to
the nearest rung the menu offers: < 0.25 gives "log", anything
else "linear". Rounding also removes the floating-point asymmetry
that treated lambda = -0.1 and 0.1 differently. The covid-recife
and box-cox vignettes are corrected accordingly (audit #22).+1 offset of the cumulative
fit (cumsum(y) + 1); increments are C(.N) - C(.N - 1) with
C(0) = 1 (audit #35).Gompertz() now includes the factor e of the Zwietering et al.
(1990) parameterisation, so k is the maximum slope and lag the
tangent intercept, as documented. Previous curves had maximum slope
k / e (audit #26).2^k - 1 for a run of k same-side points) in
?shewhart_regression and the regression-charts and
arl-simulation vignettes (audit #27).covid-recife vignette: death-count limits are now clipped with
lower_bound = 0, and the Perla et al. (2020) and Ferraz et al.
(2020) citations now match the published papers (audit #25).shewhart_mcusum(): the default decision intervals (k = 0.5) held
ARL_0 ~ 200 only for p = 2; with the old table ARL_0 was ~140 at
p = 3 and ~85 at p = 5. The table for p = 2..10 was re-derived by
Monte Carlo (dev/calibrate-h-tables.R, 20,000 paths per cell);
p = 2 reproduces Crosier's 5.50 (5.48). Default h is larger for
every p > 2 (finding 5).shewhart_mewma(): the default h table was wrong for p >= 3
(ARL_0 ~136 at lambda = 0.1, p = 4) and was a steady-state table
used with the time-varying default. There are now two simulated
tables, one per covariance mode, and the lookup follows
steady_state (finding 6).shewhart_ewma(): default L is now 2.86, which with
lambda = 0.2 gives ARL_0 ~ 370 as documented; the old L = 2.7
gave ~240 (finding 7).shewhart_ewma() / monitor(): runs-rule flags now fire exactly at
the plotted limits for any L (the sigma-equivalent was inverted,
placing the alarm at 9 se / L). Zones for rules 5-8 are thirds of
the limit width; this is documented (finding 8).shewhart_xbar_r(), shewhart_xbar_s(), subgrouped
shewhart_hotelling() and their monitor() counterparts keep
subgroups in order of first appearance instead of sorting labels
(S1, S10, S11, S2, ...), which scrambled runs rules and the x
axis (finding 9).shewhart_ewma(), shewhart_cusum() and their monitor() methods
now reject missing values; a single NA used to switch off every
later alarm silently (finding 13).monitor() on an MCUSUM chart stores the final S vector, so
chained Phase II batches continue the accumulator (finding 15).monitor() on an MEWMA chart continues Z from the last Phase I
(or previous Phase II) value with the matching covariance, instead
of restarting at 0 (finding 16).shewhart_hotelling() and its monitor() keep a Date
(or other classed) index instead of turning it numeric (finding 29).monitor() on an Xbar-S chart fitted with
sigma_method = "pooled_sd" and unequal subgroup sizes no longer
warns on every call that sizes differ from the (average) Phase I
size (finding 33).The multivariate side of the package now has the natural pair of
memory-based charts. Both follow the calibrate() / monitor()
Phase I / Phase II workflow.
shewhart_mewma() — Multivariate Exponentially Weighted Moving
Average (Lowry, Woodall, Champ & Rigdon 1992). The multivariate
analogue of shewhart_ewma(): joint monitoring of p > 1
correlated variables for small persistent shifts in the vector
mean. Time-varying and steady-state covariance both supported.
Decision interval h calibrated by lookup in Prabhu & Runger
(1997) Table 3 (ARL_0 ~ 200).shewhart_mcusum() — Multivariate CUSUM (Crosier 1988). The
multivariate analogue of shewhart_cusum(). Uses Crosier's
shrinkage operator: at each step the cumulative vector is
shrunk towards zero by k / C_i where C_i is its Mahalanobis
norm; if the norm falls below k, the cumulative vector resets
to zero. Decision interval h calibrated by lookup in
Crosier (1988) Table 1 for k = 0.5, ARL_0 ~ 200,
p = 2..10. Phase II monitoring continues from the calibration's
final S vector (Crosier 1988 §5).autoplot() method now uses shewhart_palette() and
shewhart_theme(), so plots from any chart family share the
same editorial look (off-white surface, single horizontal grid,
bold left-aligned title, sequential phase palette, hollow firebrick
rings on out-of-control points). Out-of-control marks
centralised in a new internal violation_layers() helper, sized
at halo 1.7 / ring 1.4 / stroke 0.7.Phase 0, Phase 1, … labels via
the phase_n and new legend_phases locale entries.arl-simulation vignette's hand-rolled chart was using
theme_minimal() with default ggplot2 colours; now uses
shewhart_theme() and the package palette so it matches the rest.R/autoplot.R (two comments,
one string literal) replaced with ASCII alternatives or the
— escape so R CMD check no longer warns about non-ASCII
source.This release closes the remaining items from dev/ROADMAP.md §11
that were left for after v1.1: a plotly bridge and external numerical
validation against the long-established qcc package.
as_plotly() with a shewhart_chart method that
converts any chart into an interactive plotly figure. For
two-panel charts (I-MR, X̄-R, X̄-S) the helper produces a
plotly::subplot() with a synchronised x-axis. plotly is in
Suggests, so it is only loaded on demand.tooltip argument is forwarded to plotly::ggplotly() for
full control of what hover boxes display.tests/testthat/test-vs-qcc.R (skipped silently if qcc is
not installed) compares the limits computed by shewhartr to the
reference values from the qcc package on its canonical example
datasets — pistonrings for the variables charts, orangejuice
for p / np, circuit for c. Every centre line and 3-sigma limit
agrees with qcc to within 1e-3 absolute tolerance.test-monitor.R no longer triggers the (correct) "small c_bar"
cli_warn from chart-c.R: the test data uses lambda = 12 so
the normal approximation is well-behaved. The 1-warning warning
in devtools::test() is gone; the suite is now FAIL 0 / WARN 0.This release closes most of the items left open in dev/ROADMAP.md §11.
shewhart_hotelling() is the package's first multivariate chart —
a Hotelling T² chart for jointly monitoring p > 1 correlated
variables. Both individual observations (subgroup = NULL) and
subgrouped data are supported, with the appropriate exact Phase I
limits (Beta for individuals, F for subgroups) and the slightly
wider Phase II limits as derived in Tracy, Young & Mason (1992)
and Montgomery (2019, Chapter 11). The implementation follows
Mason & Young (2002).T² statistic per row, its
decomposition by variable (the contribution of each variable to
the alarm — useful when T² signals but no univariate chart does),
and a logical flag against the appropriate chart-level UCL.multivariate-charts walks through the standard worked
example: a chemical process with three correlated quality
characteristics, showing how the multivariate chart catches a
correlation-breaking shift that any of the three univariate charts
would miss.monitor() now dispatches to monitor_ewma() and monitor_cusum()
(R/calibrate.R), so the calibrate(..., chart = "ewma") /
monitor(new_data, calib) workflow now works uniformly across
every chart in the package — not just the Shewhart-style ones.calibrate() accepts the new keys "ewma", "cusum", "hotelling".SSgompertzDummy self-starter is more robust: starting values for
b2 and b3 are now derived from the cumulative-mid-point heuristic
rather than hard-coded constants, fixing the convergence failure
with typical sample sizes that previously required \dontrun{} in
the example.This release is a comprehensive reposition of the package. The original
(v0.1.x, distributed as Shewhart) was COVID-focused and provided a
single function family for regression-based control charts. v1.0.0
is a full general-purpose SPC toolkit while preserving the
regression-chart speciality that motivated the package.
Rename. As part of the reposition, the package has been renamed
Shewhart → shewhartr to follow modern lowercase R-package
conventions and to free the name "Shewhart" for the methodology in
text and documentation. Update existing code with
library(shewhartr) (formerly library(Shewhart)).
The API has been substantially redesigned. Existing scripts written
against v0.1.x will not run unchanged.
covid-recife), not as
the organising principle.qcc and qicharts2, and
emphasises five differentiators: tidyverse-native API, broom
integration, regression-based charts as a first-class citizen,
embedded methodology (ARL, Box-Cox, runs tests), and an explicit
Phase I / Phase II workflow.shewhart_i_mr(), shewhart_xbar_r(), shewhart_xbar_s().shewhart_p(), shewhart_np(), shewhart_c(),
shewhart_u(). The c and u charts accept limits = "poisson" for
exact Poisson quantile limits rather than the normal approximation.shewhart_regression() replaces the old shewhart()
function with a cleaner API, an extensible model menu (auto,
linear, log, loglog, gompertz, logistic, plus user
formulas), automatic phase detection via configurable runs rules,
and proper handling of irregular time grids.shewhart_ewma() (Roberts 1959) for the
Exponentially Weighted Moving Average chart, with both time-varying
and steady-state limits, and shewhart_cusum() (Page 1954) for the
two-sided tabular CUSUM chart with configurable reference value k
and decision interval h. Both fit in the same S3 / broom / autoplot
pipeline as the classical charts.shewhart_runs() implements the eight Nelson rules (1984, 1985)
plus a Western Electric "7 in a row" variant for backward
compatibility. Rule sets are user-configurable on every chart.shewhart_arl() performs Monte Carlo Average Run Length simulation
for arbitrary rule combinations.shewhart_box_cox() returns the profile log-likelihood, optimal
lambda, and 95% CI in the Box & Cox (1964) tradition.shewhart_diagnostics() produces a five-panel Tukey-style residual
diagnostic display.shewhart_capability() computes Cp/Cpk/Pp/Ppk with bootstrap
confidence intervals.calibrate() and monitor() provide an explicit Phase I / Phase II
workflow.shewhart_chart with a
specific subclass.print(), summary(), autoplot(), tidy(), glance() and
augment() methods are provided for every chart type.locale argument
("en", "pt", "es", "fr") that controls plot labels and
informative messages. Validation errors remain in English to
facilitate cross-user debugging.Depends collapsed: the package no longer depends on the entire
tidyverse meta-package or on tibbletime/pals/scales. The new
Imports are minimal and explicit.plotly moved to Suggests to avoid pulling a heavy dependency
for users who don't need interactive plots.cli::cli_abort() / cli::cli_warn()
with multi-line, informative messages..onAttach() no longer prints a banner.data-raw/build_all.R script generates six synthetic datasets
(tablet_weight, bottle_fill, pcb_solder, claims_p,
temperature_drift, bacterial_growth).pkgdown at
https://castlaboratory.github.io/shewhartr/. Ten topical articles,
including a dedicated memory-based-charts vignette covering
EWMA, CUSUM and the trade-offs versus Shewhart-style charts.shewhart() (the plotting function) has been removed. Use
shewhart_regression() followed by autoplot().shewhart_fit() is no longer exported. Use shewhart_regression().shewhart_model() is no longer exported. Use shewhart_regression().shewhart_7points() is no longer exported. Use
shewhart_runs(rule = "we_seven_same") for the same behaviour, or
the recommended shewhart_runs(rule = "nelson_2_nine_same").phase_rule = "we_seven_same" to recover the
old behaviour..onAttach() has been removed..
(.fitted, .upper, .lower, .flag_*).