# Monthly O/E ratio monitoring with control limits
set.seed(77)
n_mo <- 30
oe_ratios <- c(
rnorm(18, 1.0, 0.12), # in control
rnorm(12, 1.28, 0.10) # drift begins at month 19
)
center <- mean(oe_ratios[1:18])
sd_ic <- sd(oe_ratios[1:18])
ucl <- center + 3*sd_ic
lcl <- max(0, center - 3*sd_ic)
tibble(month=1:n_mo, oe=oe_ratios) |>
mutate(flag = oe > ucl | oe < lcl) |>
ggplot(aes(month, oe)) +
geom_hline(yintercept=c(lcl, center, ucl),
color=c("#253554","#94a3b8","#253554"), linewidth=c(0.8,1,0.8),
linetype=c(2,1,2)) +
geom_line(color="#0891b2", linewidth=0.8) +
geom_point(aes(color=flag), size=3) +
annotate("text", x=28, y=ucl+0.02, label="UCL", color="#64748b", size=3) +
annotate("text", x=28, y=center+0.02, label="Center", color="#94a3b8", size=3) +
scale_color_manual(values=c("#0891b2","#e63946")) +
geom_vline(xintercept=18.5, linetype=3, color="#f59e0b") +
annotate("text", x=19.5, y=1.45, label="Drift\nbegins", color="#f59e0b", size=3) +
labs(title="O/E ratio SPC chart: control limits from in-control period, signal = 3σ breach",
x="Month", y="Observed/Expected mortality ratio") +
theme_di() + theme(legend.position="none")