Files
party2d/validation/plot_scale_examples.R

156 lines
5.0 KiB
R

#!/usr/bin/env Rscript
options(stringsAsFactors = FALSE)
if (!requireNamespace("ggplot2", quietly = TRUE)) {
stop("Required package not installed: ggplot2")
}
library(ggplot2)
script_args <- commandArgs(trailingOnly = FALSE)
file_arg <- script_args[grepl("^--file=", script_args)][1]
if (length(file_arg) && !is.na(file_arg)) {
script_path <- normalizePath(sub("^--file=", "", file_arg))
repo_root <- normalizePath(file.path(dirname(script_path), ".."))
} else if (!exists("repo_root")) {
repo_root <- normalizePath(".")
}
setwd(repo_root)
panel_file <- file.path("data", "releases", "party_2d_election_year_panel_v0.csv.gz")
output_dir <- file.path("validation", "outputs")
figure_dir <- file.path("validation", "figures")
if (!file.exists(panel_file)) stop("Required input not found: ", panel_file)
dir.create(output_dir, recursive = TRUE, showWarnings = FALSE)
dir.create(figure_dir, recursive = TRUE, showWarnings = FALSE)
panel <- read.csv(panel_file, check.names = FALSE)
trajectory_spec <- data.frame(
party_id = c(1691, 432, 1375),
series = c("Fidesz", "US Democrats", "CDU"),
start_year = c(1990, 1988, 2002),
end_year = c(2022, 2020, 2025)
)
trajectory_rows <- lapply(seq_len(nrow(trajectory_spec)), function(i) {
spec <- trajectory_spec[i, ]
d <- panel[
panel$party_id == spec$party_id &
panel$year >= spec$start_year & panel$year <= spec$end_year,
]
if (!nrow(d)) stop("No trajectory rows found for PartyFacts ", spec$party_id)
d$series <- spec$series
d$display_role <- "trajectory"
d$is_labelled <- d$year %in% c(spec$start_year, spec$end_year)
d$label <- ifelse(d$is_labelled, paste(spec$series, d$year), "")
d[order(d$year), ]
})
trajectories <- do.call(rbind, trajectory_rows)
trajectory_levels <- trajectory_spec$series
trajectories$series <- factor(trajectories$series, levels = trajectory_levels)
plot_columns <- c(
"party_id", "party_name_english", "country", "year", "series",
"display_role", "is_labelled", "label", "economic_lr",
"economic_lr_q025", "economic_lr_q975", "galtan", "galtan_q025",
"galtan_q975", "source_support_class"
)
plot_data <- trajectories[plot_columns]
write.csv(
plot_data,
file.path(output_dir, "party_scale_example_plot_data.csv"),
row.names = FALSE,
na = ""
)
labelled <- plot_data[plot_data$is_labelled, ]
label_positions <- data.frame(
label = c(
"Fidesz 1990", "Fidesz 2022",
"US Democrats 1988", "US Democrats 2020",
"CDU 2002", "CDU 2025"
),
plot_label = c(
"Fidesz\n1990", "Fidesz\n2022",
"US Democrats\n1988", "US Democrats\n2020",
"CDU\n2002", "CDU\n2025"
),
label_x = c(.84, .36, .48, .35, .53, .72),
label_y = c(.36, .93, .47, .27, .66, .57)
)
labelled <- merge(labelled, label_positions, by = "label", all.x = TRUE, sort = FALSE)
if (anyNA(labelled$label_x) || anyNA(labelled$label_y)) {
stop("Missing manual label position for a displayed scale example")
}
p <- ggplot() +
geom_path(
data = trajectories,
aes(x = economic_lr, y = galtan, group = series, colour = series, linetype = series),
linewidth = .85,
arrow = grid::arrow(type = "closed", length = grid::unit(.065, "inches"))
) +
geom_errorbar(
data = labelled,
aes(x = economic_lr, ymin = galtan_q025, ymax = galtan_q975, colour = series),
width = 0, alpha = .75
) +
geom_errorbar(
data = labelled,
aes(y = galtan, xmin = economic_lr_q025, xmax = economic_lr_q975, colour = series),
orientation = "y", width = 0, alpha = .75
) +
geom_point(
data = labelled,
aes(x = economic_lr, y = galtan, colour = series, shape = series),
size = 2.4
) +
geom_segment(
data = labelled,
aes(x = economic_lr, y = galtan, xend = label_x, yend = label_y, colour = series),
linewidth = .3, show.legend = FALSE
) +
geom_text(
data = labelled,
aes(x = label_x, y = label_y, label = plot_label),
size = 2.6, lineheight = .9
) +
scale_linetype_manual(
values = c("Fidesz" = "solid", "US Democrats" = "dotdash", "CDU" = "dashed"),
breaks = trajectory_levels
) +
scale_colour_manual(
values = c("Fidesz" = "#D55E00", "US Democrats" = "#0072B2", "CDU" = "#009E73"),
breaks = trajectory_levels
) +
scale_shape_manual(
values = c("Fidesz" = 16, "US Democrats" = 15, "CDU" = 17),
breaks = trajectory_levels
) +
scale_x_continuous(limits = c(0, 1), breaks = c(0, .25, .5, .75, 1)) +
scale_y_continuous(limits = c(0, 1), breaks = c(0, .25, .5, .75, 1)) +
labs(
x = "Economic: left (0) to right (1)",
y = "Cultural: cosmopolitan (0) to traditionalist (1)",
colour = "Election-year path",
linetype = "Election-year path",
shape = "Election-year path"
) +
theme_minimal(base_size = 9) +
theme(
panel.grid.minor = element_blank(),
legend.position = "bottom",
legend.title = element_text(face = "bold"),
plot.margin = margin(7, 12, 7, 7)
)
ggsave(
file.path(figure_dir, "party_scale_examples.pdf"),
p, width = 8.8, height = 6.0, device = cairo_pdf
)
message("Wrote validation/outputs/party_scale_example_plot_data.csv")
message("Wrote validation/figures/party_scale_examples.pdf")