# Per scenario: vier vaste groepsgemiddelden + slope, simulatie rond die centra.
scenarios <- tribble(
~scene, ~titel, ~y_a, ~y_b, ~c_a, ~c_b, ~bw,
1, "1. Identiek", 55, 55, 6, 6, 2.0,
2, "2. Puur effect", 50, 70, 6, 6, 2.0,
3, "3. Suppressie", 65, 55, 4, 8, 2.0,
4, "4. Demping", 50, 65, 4, 8, 2.0,
5, "5. Simpson", 70, 65, 10, 5, 2.0,
6, "6. Confound", 50, 60, 4, 8, 2.5
)
set.seed(303)
maak_data <- function(rij, n = 25) {
ca <- rnorm(n, rij$c_a, 1.2)
cb <- rnorm(n, rij$c_b, 1.2)
ya <- rij$y_a + rij$bw * (ca - rij$c_a) + rnorm(n, 0, 4)
yb <- rij$y_b + rij$bw * (cb - rij$c_b) + rnorm(n, 0, 4)
tibble(
titel = rij$titel,
Y = c(ya, yb),
C = c(ca, cb),
Groep = rep(c("A", "B"), each = n)
)
}
scenes <- bind_rows(lapply(seq_len(nrow(scenarios)),
function(i) maak_data(scenarios[i, ])))
# Per scene: grand mean C, raw groepsmiddens, adjusted means.
markers <- scenarios %>%
mutate(
cm = (c_a + c_b) / 2,
ya_star = y_a - bw * (c_a - cm),
yb_star = y_b - bw * (c_b - cm)
)
raw_means <- bind_rows(
markers %>% transmute(titel, Groep = "A", C = c_a, Y = y_a),
markers %>% transmute(titel, Groep = "B", C = c_b, Y = y_b)
)
adj_means <- bind_rows(
markers %>% transmute(titel, Groep = "A", C = cm, Y = ya_star),
markers %>% transmute(titel, Groep = "B", C = cm, Y = yb_star)
)
vlines <- markers %>% select(titel, cm)
# De gestreepte lijnen: per groep de helling b_w uit het ontwerp, door het ruwe
# groepsgemiddelde, over het stuk C waar die groep zit. Dan staat de gevulde
# driehoek precies op zijn lijn, zoals de vinger-volgt-lijn hieronder belooft.
# Een lm()-lijn per groep zou b_w schatten uit 25 punten met ruis, en komt dan
# overal tussen ongeveer 0.3 en 3.4 uit.
binnen <- scenes %>%
group_by(titel, Groep) %>%
summarise(c_min = min(C), c_max = max(C), .groups = "drop") %>%
left_join(bind_rows(
markers %>% transmute(titel, Groep = "A", cj = c_a, yj = y_a, bw),
markers %>% transmute(titel, Groep = "B", cj = c_b, yj = y_b, bw)
), by = c("titel", "Groep")) %>%
mutate(y_min = yj + bw * (c_min - cj), y_max = yj + bw * (c_max - cj))
ggplot(scenes, aes(C, Y, colour = Groep)) +
geom_point(alpha = 0.4, size = 1.4) +
geom_segment(data = binnen, aes(x = c_min, xend = c_max, y = y_min, yend = y_max),
linetype = "dashed", linewidth = 0.6) +
geom_smooth(aes(group = 1), method = "lm", se = FALSE,
colour = "black", linewidth = 0.6) +
geom_vline(data = vlines, aes(xintercept = cm),
linetype = "dotted", colour = "grey50") +
geom_point(data = raw_means, shape = 5, size = 3.0, stroke = 0.9) +
geom_point(data = adj_means, shape = 17, size = 3.0) +
scale_colour_manual(values = c(A = "#332288", B = "#117733")) +
# Alle zes op dezelfde assen: dan ziet dezelfde helling b_w = 2.0 er in elke
# scene even steil uit, en de b_w = 2.5 van scene 6 ook echt steiler.
facet_wrap(~ titel, ncol = 3) +
labs(x = "C (familie-hulp)", y = "Y (damtevredenheid)") +
theme_minimal(base_size = 10) +
theme(legend.position = "bottom",
strip.text = element_text(face = "bold"))