n_subj <- 60; n_time <- 5
subj_df <- tibble(
id = 1:n_subj,
group = ifelse(1:n_subj <= n_subj/2, "Standard care", "Enhanced protocol"),
intercept = rnorm(n_subj, 30, 8),
slope = rnorm(n_subj, ifelse(1:n_subj <= n_subj/2, -1.5, -3), 1.5)
)
df_long <- expand_grid(id = 1:n_subj, time = 0:4) |>
left_join(subj_df, by="id") |>
mutate(outcome = intercept + slope*time + rnorm(n(), 0, 2))
# Mean trajectories
df_mean <- df_long |>
group_by(group, time) |>
summarise(mean_out=mean(outcome), se=sd(outcome)/sqrt(n()), .groups="drop")
ggplot(df_long, aes(time, outcome, group=id, color=group)) +
geom_line(alpha=0.18, linewidth=0.4) +
geom_line(data=df_mean, aes(time, mean_out, group=group), linewidth=1.8) +
geom_ribbon(data=df_mean, aes(group=group, y=mean_out, ymin=mean_out-1.96*se,
ymax=mean_out+1.96*se, fill=group), alpha=0.18, color=NA) +
scale_color_manual(values=c("#2563eb","#e63946")) +
scale_fill_manual(values=c("#2563eb","#e63946")) +
labs(title="Longitudinal trajectories: individual paths (thin) + mean with 95% CI (thick)",
x="Assessment time point", y="Outcome score",
color=NULL, fill=NULL) +
theme_di()