################################################################
## Open Data Kooperation: univie & Parlament ###################
## Showcase 13: Redner und Rednerinnen-Karrieren im Nationalrat#
## code by Laurenz Ennser-Jedenastik & Daniel Bliem ############
### Kontakt: laurenz.ennser@univie.ac.at #######################
################################################################
# Arbeitsumgebung leeren
rm(list = ls())
# Installieren und Laden der erforderlichen Pakete.
necessary.packages <- c(
"httr",
"jsonlite",
"RJSONIO",
"RCurl",
"httr2",
"purrr",
"tibble",
"rjson",
"tidyverse",
"stringi",
"tidyr",
"haven",
"gridExtra",
"stringr",
"showtext",
"ggrepel",
"ggforce",
"grid")
new.packages <- necessary.packages[!(necessary.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages)
lapply(necessary.packages, library, character.only = TRUE)
# Speicherort für die JSON Files festlegen
setwd("Pfad/zu/Ihrem/Speicherort")
### 1. Datensatz: Plenarsitzungen
# Definition der GP-Werte, für die Daten abgerufen werden sollen
gp_values <- c("XX", "XXI", "XXII","XXIII", "XXIV", "XXV", "XXVI", "XXVII")
# Gemeinsamer Teil des API-Requests
req <- request("https://www.parlament.gv.at/Filter/api/json/post?jsMode=EVAL&FBEZ=WFP_007&listeId=11070&showAll=true")
# Loop über alle Gesetzgebungsperioden zum Download der jeweiligen JSON Files
for (gp in gp_values) {
t1 <- req %>%
req_body_raw(paste0('{"MODUS":["PLENAR"],"NRBRBV":["NR"], "GP":["', gp, '"]}')) %>%
req_perform()
df1 <- t1 %>% resp_body_json()
nrows1 <- length(df1$rows)
vorne <- "https://www.parlament.gv.at"
hinten <- "?json=true"
all.urls <- rep(NA, nrows1)
all.GPs <- rep(NA, nrows1)
all.numbers <- rep(NA, nrows1)
all.VHG <- rep(NA, nrows1)
# Schleife zur Generierung der URLs und Extraktion der Metadaten
for (i in 1:nrows1) {
all.urls[i] <- paste0(vorne, df1[["rows"]][[i]][[9]], hinten)
all.GPs[i] <- df1[["rows"]][[i]][[4]]
all.numbers[i] <- df1[["rows"]][[i]][[6]]
all.VHG[i] <- df1[["rows"]][[i]][[5]]
}
# Herunterladen der JSON-Dateien
for (i in 1:nrows1) {
download.file(all.urls[i], destfile = paste0(all.VHG[i], "_", all.GPs[i], "_", all.numbers[i], ".json"))
}
}
# Liste aller Files im Arbeitsverzeichnis erstellen
files.in.dir <- list.files(path = "Pfad/zu/Ihrem/Speicherort", pattern = "*.json", full.names = TRUE)
count.files <- length(files.in.dir)
df.reden <- data.frame()
# Iterieren über die JSON Files zum herauslesen aller relevanter Informationen. Speichern dieser Informationen in einem Dataframe
for (h in 1:count.files) {
print(paste("Verarbeite Datei:", files.in.dir[h]))
file <- fromJSON(file = files.in.dir[h]) # JSON-File einlesen
for (i in 1:length(file$content[[2]]$past_debates)) {
if (length(file$content[[2]]$past_debates[[i]]$speeches) == 0) {
next
}
df.debatte <- data.frame(gp = rep(file$content[[1]]$gp_code, length(file$content[[2]]$past_debates[[i]]$speeches)))
df.debatte$titel <- rep(file$content[[2]]$past_debates[[i]]$text, length(file$content[[2]]$past_debates[[i]]$speeches))
df.debatte$sitzungsnr <- rep(file$content[[1]]$inr, length(file$content[[2]]$past_debates[[i]]$speeches))
df.debatte$deb.id <- rep(file$content[[2]]$past_debates[[i]]$id, length(file$content[[2]]$past_debates[[i]]$speeches))
df.debatte$deb.typ <- rep(file$content[[2]]$past_debates[[i]]$type, length(file$content[[2]]$past_debates[[i]]$speeches))
if(!is.null(file$content[[2]]$past_debates[[i]]$top) && !is.na(file$content[[2]]$past_debates[[i]]$top)){
df.debatte$deb.top <- rep(substr(file$content[[2]]$past_debates[[i]]$top, 5,30), length(file$content[[2]]$past_debates[[i]]$speeches))
if(str_detect(file$content[[2]]$past_debates[[i]]$top, "-")){
df.debatte$deb.top2 <- rep(strsplit(file$content[[2]]$past_debates[[i]]$top, "-")[[1]][1], length(file$content[[2]]$past_debates[[i]]$speeches))
}
else df.debatte$deb.top2 <- rep(file$content[[2]]$past_debates[[i]]$top, length(file$content[[2]]$past_debates[[i]]$speeches))
}
if(!is.null(file$content[[2]]$past_debates[[i]]$agenda[1]) &&
!is.null(file$content[[2]]$past_debates[[i]]$agenda[1][1]) &&
length(file$content[[2]]$past_debates[[i]]$agenda) >= 1 &&
!is.null(file$content[[2]]$past_debates[[i]]$agenda[[1]]["nr"][1])){
if(!is.null(file$content[[2]]$past_debates[[i]]$agenda[1]["wm_type"])){
df.debatte$berichterstatter <- rep(file$content[[2]]$past_debates[[i]]$agenda[[1]]["wm_name"][[1]], length(file$content[[2]]$past_debates[[i]]$speeches))
df.debatte$bericht_frak <- rep(file$content[[2]]$past_debates[[i]]$agenda[[1]]["wm_frac_id"][[1]], length(file$content[[2]]$past_debates[[i]]$speeches))
}
print(df.debatte$sitzungsnr)
print(i)
}
if(nrow(df.debatte) > 0){
for(l in 1:nrow(df.debatte)){
if(!is.null(file[["content"]][[1]]) &&
!is.null(file[["content"]][[1]][["resolutions"]])){
for(k in 1:length(file[["content"]][[1]][["resolutions"]])){
if(!is.null(file[["content"]][[1]][["resolutions"]]) &&
!is.null(file[["content"]][[1]][["resolutions"]][[k]]) &&
!is.null(file[["content"]][[1]][["resolutions"]][[k]][["url"]]) &&
!is.null(file[["content"]][[1]][["resolutions"]][[k]][["top"]]) &&
!is.null(df.debatte$deb.top2[l])){
if(file[["content"]][[1]][["resolutions"]][[k]][["top"]] == df.debatte$deb.top2[l]){
print("TRUE")
df.debatte$urlgegenstand <- rep(file[["content"]][[1]][["resolutions"]][[k]][["url"]][[1]], length(file$content[[2]]$past_debates[[i]]$speeches))
}
}
else {}
}
}
else{}
}
}
# Typ der Debatte (z.B. Dringliche Anfrage, Kurzdebatte, Normaldebatte etc.)
if (nrow(df.debatte) > 0) {
for (j in 1:nrow(df.debatte)) {
df.debatte$redenr[j] <- file$content[[2]]$past_debates[[i]]$speeches[[j]][1][[1]]
df.debatte$parlid[j] <- file$content[[2]]$past_debates[[i]]$speeches[[j]][4][[1]]
df.debatte$name[j] <- file$content[[2]]$past_debates[[i]]$speeches[[j]][3][[1]]
df.debatte$rolle[j] <- file$content[[2]]$past_debates[[i]]$speeches[[j]][6][[1]]
df.debatte$startzeit[j] <- file$content[[2]]$past_debates[[i]]$starttime
if (!is.null(file$content[[2]]$past_debates[[i]]$speeches[[j]][8][[1]])) {
m <- file$content[[2]]$past_debates[[i]]$speeches[[j]][8][[1]]
} else {
m <- "00:00"
}
df.debatte$redezeit[j] <- (as.numeric(strsplit(m, ":")[[1]])[1]*60 + as.numeric(strsplit(m, ":")[[1]])[2]) / 60
}
df.reden <- bind_rows(df.reden, df.debatte)
}
}
}
# Erzeugen von Fraktions-, GP/Sitzungs- und Datumsvariable
df.reden$fraktion <- str_sub(df.reden$name, -2, -2)
df.reden$gp_sitzung <- paste(df.reden$gp, df.reden$sitzungsnr, sep="_")
df.reden$datum <- as.Date(substr(df.reden$startzeit, 1, 10), "%Y-%m-%d")
# Speichern des Dataframes
save(df.reden, file = "Ihr_Dateiname.RData")
### 2. Datensatz: Parlamentarier und Parlamentarierinnen ab 1918
# Definieren des neuen Speicherorts für die Personendaten
setwd("Pfad/zu/Ihrem/neuen/Speicherort")
# Definieren der API-URI und Body des API-Calls
req_2 <- request("https://www.parlament.gv.at/Filter/api/filter/data/409?1=1&showAll=true&export=true")
t2 <-
req_2 %>%
req_body_raw('{
"ATTR_JSON.mandate_detail.gremium_name": [
"Nationalrat"
]
}') %>%
req_perform()
df2 <- t2 %>% resp_body_json()
# Loop zur Umwandlung von relativen Links aus den Ergebnislisten des API-Calls (Filter) zu absoluten Links
nrows2 <- length(df2$rows)
all.urls.2 <- rep("", nrows2)
all.pads.2 <- rep(NA, nrows2)
for (i in 1:nrows2) {
all.urls.2[i] <- paste0(vorne, df2[["rows"]][[i]][[10]], hinten)
all.pads.2[i] <- gsub("/person/", "", df2[["rows"]][[i]][[10]])
}
for (i in 1:nrows2){
download.file(all.urls.2[i], destfile = paste0(all.pads.2[i], ".json")) }
# Liste aller Files im Arbeitsverzeichnis erstellen
files.in.dir.2 <- list.files(path = "Pfad/zu/Ihrem/neuen/Speicherort", pattern = "*.json", full.names = TRUE)
count.files.2 <- length(files.in.dir.2)
df.abg <- data.frame()
# Iterieren durch alle Dateien im Verzeichnis und extrahieren relevanter Informationen in den Dataframe
for (i in 1:count.files.2) {
getfile <- fromJSON(file = files.in.dir.2[i])
print(files.in.dir.2[i])
name <- getfile[["meta"]][["description"]]
id <- getfile[["content"]][["personInfo"]][["pad_intern"]]
mandate <- getfile[["content"]][["biografie"]][["mandatefunktionen"]][["mandate"]]
if (!is.null(mandate)) {
for (j in seq_along(mandate)) {
mandat_kammer <- mandate[[j]][["funktion_text"]]
mandat_von <- mandate[[j]][["funktion_von"]]
mandat_bis <- mandate[[j]][["funktion_bis"]]
mandat_klub <- ifelse(!is.null(mandate[[j]][["klub"]]), mandate[[j]][["klub"]], NA)
# Daten zum Dataframe hinzufügen
new_row <- data.frame(
name = name,
id = id,
mandat_kammer = mandat_kammer,
mandat_von = mandat_von,
mandat_bis = mandat_bis,
mandat_klub = mandat_klub,
stringsAsFactors = FALSE
)
df.abg <- rbind(df.abg, new_row)
}
}
}
# Datumsvariablen umwandeln
df.abg$mandat_von <- as.Date(df.abg$mandat_von, format = "%d.%m.%Y")
df.abg$mandat_bis <- as.Date(df.abg$mandat_bis, format = "%d.%m.%Y")
### Untersuchungszeitraum filtern: Abgeordnete seit XX. GP, bis Ende XXVII. GP
# IDs von Personen, die vor dem 15.01.1996 ein Mandat hatten, filtern, und alle Mandate dieser Personen entfernen
personen_vor_1996 <- df.abg %>%
filter(as.Date(mandat_von) < as.Date("1996-01-15")) %>%
pull(id)
df.abg <- df.abg %>%
filter(!(id %in% personen_vor_1996))
# Ende des Untersuchungszeitraums filtern
df.abg$mandat_bis[is.na(df.abg$mandat_bis)] <- as.Date("2024-10-24")
df.abg <- df.abg %>%
filter(as.Date(mandat_von) <= as.Date("2024-10-23"))
### Untersuchungsobjekte filtern: Nur einfache Abgeordnete, die währenddessen keine andere Rolle hatten
# Filtern der Rollen, die nicht mit dem Nationalrat in Verbindung stehen können
df.abg <- df.abg %>%
filter(grepl("^Abgeordnete", mandat_kammer) | grepl("Bundesminister", mandat_kammer) |
grepl("kanzler", mandat_kammer) | grepl("Staatssekr", mandat_kammer))
# IDs von Personen, die nicht nur einfache Abgeordnete Waren
minister_ids <- df.abg %>%
filter(!grepl("^Abgeordnete", mandat_kammer)) %>%
distinct(id) %>%
pull(id)
# Zeiträume der anderen Rollen extrahieren
minister_times <- df.abg %>%
filter(id %in% minister_ids, !grepl("^Abgeordnete", mandat_kammer)) %>%
select(id, mandat_von, mandat_bis)
# Funktion zur Anpassung der Zeiträume: Keine Überschneidungen zwischen einfachen Mandaten und anderen Rollen
adjust_dates <- function(id, mandat_von, mandat_bis) {
andere_mandate <- minister_times %>% filter(id == !!id)
for (i in seq_len(nrow(andere_mandate))) {
start_other <- andere_mandate$mandat_von[i]
end_other <- andere_mandate$mandat_bis[i]
if (mandat_bis >= start_other & mandat_von <= end_other) {
# Bei kompletter Überschneidung: Entfernen
if (mandat_von >= start_other & mandat_bis <= end_other) {
return(c(NA, NA))
}
# Bei teilweiser Überschneidung vorderen oder hinteren Teil anpassen
if (mandat_bis >= start_other & mandat_von < start_other) {
mandat_bis <- start_other - days(1)
}
if (mandat_von <= end_other & mandat_bis > end_other) {
mandat_von <- end_other + days(1)
}
}
}
return(c(mandat_von, mandat_bis))
}
# Anwenden der Funktion auf die Daten: Anpassen der Abgeordneten-Zeiträume und herausfiltern der restlichen Rollen
df.abg <- df.abg %>%
filter(grepl("^Abgeordnete", mandat_kammer)) %>%
mutate(adj_dates = map2(id, mandat_von, ~ adjust_dates(.x, .y, df.abg$mandat_bis[df.abg$id == .x & df.abg$mandat_von == .y])),
mandat_von = as.Date(map_dbl(adj_dates, 1)),
mandat_bis = as.Date(map_dbl(adj_dates, 2))) %>%
filter(!is.na(mandat_von) & !is.na(mandat_bis)) %>%
select(-adj_dates)
# Zusammenfassen und vereinheitlichen der Klubs
df.abg <- df.abg %>%
mutate(mandat_klub = case_when(
mandat_klub == "Die Sozialdemokratische Parlamentsfraktion - Klub der sozialdemokratischen Abgeordneten zum Nationalrat, Bundesrat und Europäischen Parlament" ~ "S",
mandat_klub == "Parlamentsklub der Österreichischen Volkspartei" ~ "V",
mandat_klub %in% c("Klub der Freiheitlichen Partei Österreichs", "Klub der Freiheitlichen", "Freiheitlicher Parlamentsklub") ~ "F",
mandat_klub %in% c("Der Grüne Klub", "Der Grüne Klub im Parlament - Klub der Grünen Abgeordneten zum Nationalrat, Bundesrat und Europäischen Parlament") ~ "G",
mandat_klub %in% c("NEOS Parlamentsklub", "Klub von NEOS", "Klub von NEOS und LIF") ~ "N",
mandat_klub %in% c("Freiheitlicher Parlamentsklub - BZÖ", "Parlamentsklub des BZÖ") ~ "B",
mandat_klub %in% c("Parlamentsklub des Liberalen Forums", "Parlamentsklub Liberales Forum") ~ "L",
mandat_klub == "Parlamentsklub Team Stronach" ~ "T", mandat_klub == "Parlamentsklub JETZT" ~ "J", mandat_klub == "Liste Pilz" ~ "P", mandat_klub == "ohne Klubzugehörigkeit" ~ "A",
))
# Eintagesmandate herausfiltern
df.abg <- df.abg %>%
filter(mandat_von != mandat_bis)
# Geschlechtsvariable hinzufügen
df.abg <- df.abg %>%
mutate(sex = case_when(
str_starts(mandat_kammer, "Abgeordnete ") ~ "W",
str_starts(mandat_kammer, "Abgeordneter") ~ "M"
))
# Mandate zusammenfassen, die nur einen Tag auseinander liegen (beziehen sich auf dasselbe Mandat)
df.abg <- df.abg %>%
arrange(id, mandat_klub, mandat_von, sex) %>%
group_by(id, mandat_klub, sex) %>%
mutate(
group = cumsum(coalesce(as.numeric(mandat_von - lag(mandat_bis)) > 1, TRUE))
) %>%
group_by(id, mandat_klub, group, sex) %>%
summarise(
name = first(name),
mandat_von = mandat_von[which.min(mandat_von)],
mandat_bis = mandat_bis[which.max(mandat_bis)],
.groups = 'drop'
)
# Speichern des Dataframes
save(df.abg, file = "Ihr_Dateiname2.RData")
### Zusammenfassen der Dataframes: Überprüfen, dass nur Reden von einfachen Abgeordneten gezählt werden
# Neue Spalten in df.reden erstellen
df.reden$nrabg <- "Nein"
df.reden$sex <- NA
# Loop über df.reden, um zu überprüfen, ob Person zum Zeitpunkt der Rede ein NR-Mandat hatte, abgleichen der Klubs und hinzufügen von Geschlecht
for (i in 1:nrow(df.reden)) {
person <- df.reden$parlid[i]
datum <- df.reden$datum[i]
if (person %in% df.abg$id) {
mandatszeiten <- df.abg %>%
filter(id == person) %>%
filter(mandat_von <= datum & mandat_bis >= datum)
# Falls mindestens ein Mandat gefunden wurde, "Ja" setzen
if (nrow(mandatszeiten) > 0) {
df.reden$nrabg[i] <- "Ja"
# Überprüfen, ob der Klub der gleiche ist
mandats_klub <- mandatszeiten %>%
filter(mandat_von <= datum & mandat_bis >= datum) %>%
select(mandat_klub) %>%
pull()
fraktion <- df.reden$fraktion[i]
if (fraktion != mandats_klub) {
df.reden$fraktion[i] <- paste(fraktion, mandats_klub, sep = ", ")
}
df.reden$sex[i] <- mandatszeiten$sex[1]
}
}
if (i %% 100 == 0) {print(paste("Fortschritt:", i, "von", nrow(df.reden), "Reden verarbeitet"))
}
}
### Hinzufügen von Variable, die Zeit im Nationalrat am Redezeitpunkt anzeigt
# Neue Spalte in df.reden für die Gesamtzahl der Tage im Mandat
df.reden$tage_im_mandat <- 0
# Loop, der die Tage, seit dem die Abgeordnete zum Redezeitpunkt ein Nationalratsmandat innehatte, berechnet
for (i in 1:nrow(df.reden)) {
person <- df.reden$parlid[i]
datum <- df.reden$datum[i]
if (person %in% df.abg$id) {
mandatszeiten <- df.abg %>%
filter(id == person) %>%
arrange(mandat_von)
# Das aktuelle Mandat zum Zeitpunkt der Rede finden
aktuelles_mandat <- mandatszeiten %>%
filter(mandat_von <= datum & mandat_bis >= datum)
if (nrow(aktuelles_mandat) > 0) {
tage_seit_beginn <- as.numeric(difftime(datum, aktuelles_mandat$mandat_von[1], units = "days")) + 1
vergangene_mandate <- mandatszeiten %>%
filter(mandat_bis < aktuelles_mandat$mandat_von[1])
tage_aus_vergangenen_mandaten <- sum(as.numeric(difftime(vergangene_mandate$mandat_bis, vergangene_mandate$mandat_von, units = "days"))) + nrow(vergangene_mandate)
# Gesamtzahl der Tage berechnen
df.reden$tage_im_mandat[i] <- tage_seit_beginn + tage_aus_vergangenen_mandaten
}
}
if (i %% 100 == 0) {print(paste("Fortschritt:", i, "von", nrow(df.reden), "Reden verarbeitet"))
}
}
# Finalen Dataframe mit nur Nationalratsabgeordneten erstellen
df01 <- df.reden %>%
filter(nrabg == "Ja")
# Korrigieren von Fraktionsbezeichnungen
df01 <- df01 %>%
mutate(fraktion = case_when(
fraktion == "A, T" ~ "T", fraktion == "F, B" ~ "B", TRUE ~ fraktion
))
### Bereinigen der Namensvariable
# Entfernen der Fraktionsbezeichnung
df01 <- df01 %>%
mutate(name = str_remove(name, " \\([A-Z]\\)$"))
# Zusammenfassen von Personen-IDs, die verschiedene Namensbezeichungnen haben (wegen Titeln, etc.)
df01 <- df01 %>%
mutate(name = case_when(
parlid == "16234" ~ "Johann Höfinger", parlid == "2334" ~ "Verena Nussbaum", parlid == "65219" ~ "Lukas Hammer", parlid == "5685" ~ "Martina von Künsberg Sarre",
parlid == "5643" ~ "Petra Oberrauner", parlid == "5630" ~ "Joachim Schnabel", TRUE ~ name
))
# Dataframe speichern
save(df01, file = "Ihr_Dateiname3.RData")
# Benutzerdefinierte Schriftart hinzufügen und aktivieren
font_add("Lato",
regular = "Pfad/zu/Ihrer/Schriftart.ttf",
bold = "Pfad/zu/Ihrer/Schriftart.ttf")
showtext_auto()
# Erstellen eines eigenen Themes für die Grafiken
custom_theme <- function() {
theme_minimal() +
theme(
plot.background = element_rect(fill = "white", color = NA),
panel.grid.major = element_line(color = alpha("gray", 0.25)),
panel.grid.minor = element_line(color = "white"),
panel.border = element_blank(),
plot.title = element_text(color = "#132843", size = 55, face = "bold", family = "Lato", hjust = 0),
plot.subtitle = element_text(color = "#132843", size = 38, family = "Lato", margin = margin(b = 20), hjust = 0),
axis.title.x = element_text(face = "bold", family = "Lato", size = 35, margin = margin(t = 15)),
axis.title.y = element_text(face = "bold", family = "Lato", size = 35, margin = margin(r = 15)),
axis.text = element_text(family = "Lato", size = 30),
legend.text = element_text(family = "Lato", face = "bold", size = 35),
plot.margin = margin(1.2, 0.7, 0.7, 0.7, "cm"),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(size = 27)
)
}
# Speicherort für die Grafiken festlegen
setwd("Pfad/zu/Ihrem/Speicherort")
### 1. Grafik: Zeit bis zur ersten Rede im Plenum
# Filtern der Daten nach den ersten Reden pro Person
df01_first <- df01 %>%
group_by(parlid) %>%
filter(tage_im_mandat == min(tage_im_mandat)) %>%
slice(1) %>%
ungroup()
# Herausfiltern des Ausreißers Sobotka
df01_first <- df01_first %>%
filter(parlid != "88386")
# ECDF-Funktion und Daten für die Fläche unter der Funktion erstellen
tage_sorted <- sort(df01_first$tage_im_mandat)
ecdf_values <- ecdf(tage_sorted)(tage_sorted)
df_ecdf <- data.frame(
tage_im_mandat = c(0, tage_sorted),
ecdf_value = c(0, ecdf_values))
# Werte für die vertikalen Linien in der Grafik bestimmen
tage_g1 <- c(50, 100, 150)
prozentwerte_g1 <- ecdf(tage_sorted)(tage_g1)
df_lines <- data.frame(
x = tage_g1, xend = tage_g1,
y = 0, yend = prozentwerte_g1)
# Grafik erstellen
grafik1 <- ggplot() +
geom_ribbon(data = df_ecdf, aes(x = tage_im_mandat, ymin = 0, ymax = ecdf_value), fill = "#132843", alpha = 0.3) +
geom_step(data = df_ecdf, aes(x = tage_im_mandat, y = ecdf_value), color = "#132843", size = 1) +
geom_segment(data = df_lines, aes(x = x, xend = xend, y = y, yend = yend),
color = "#5d5e5c", linetype = "dashed", size = 1) +
annotate("text", x = tage_g1 - 70, y = prozentwerte_g1 + 0.03,
label = paste0(tage_g1, " Tage: ", round(prozentwerte_g1 * 100), "% der Abgeordneten\nhaben ihre erste Rede gehalten"),
color = "black", size = 11, hjust = 0, lineheight = 0.35) +
labs(title = "Dauer bis zur ersten Rede im Nationalrat",
subtitle = "Abgeordnete mit Eintrittsdatum Jän. 1996 – Okt. 2024",
x = "Tage seit Eintritt", y = "Anteil an Abgeordneten, die bereits ihre erste Rede gehalten haben",
caption = "Quelle: parlament.gv.at") +
scale_x_continuous(breaks = seq(0, 250, by = 50)) +
scale_y_continuous(labels = scales::percent_format()) +
custom_theme()
ggsave("SC13_Grafik01.jpg", grafik1, width = 10, height = 7.5, units = "in", dpi = 300)
### 2. Grafik: Anzahl an Reden pro Jahr im Parlament
# Neue Variable für Jahre seit Eintritt erstellen - für Kategorisierung in Grafik
df01 <- df01 %>%
mutate(year = floor(tage_im_mandat / 365.25) + 1)
# Reden pro Jahr und Abgeordneter zählen
df01_year <- df01 %>%
group_by(parlid, year, name) %>%
summarise(anzahl_reden = n(), .groups = "drop")
# Ausreißer, die beschriftet werden sollen, bestimmen
highlighted_cases <- data.frame(
name = c("Rupert Doppler", "Rupert Doppler", "Leopold Steinbichler", "Christoph Hagen", "Dr. Dagmar Belakowitsch", "Mag. Gerald Loacker"),
year = c(8, 9, 4, 5, 15, 11))
# Ausreißer in einen Dataframe zusammenfassen und Namen anpassen für Beschriftung in der Grafik
df_outliers <- df01_year %>%
semi_join(highlighted_cases, by = c("name", "year")) %>%
mutate(name = recode(name,
"Rupert Doppler" = "Rupert Doppler (Fraktionslos)", "Leopold Steinbichler" = "Leopold Steinbichler (STRONACH)", "Christoph Hagen" = "Christoph Hagen (STRONACH)",
"Dr. Dagmar Belakowitsch" = "Dagmar Belakowitsch (FPÖ)", "Mag. Gerald Loacker" = "Gerald Loacker (NEOS)"))
# Mittelpunkt der Ausreißer von Doppler finden, für die Markierung mit Kreis in der Grafik
doppler_center <- df_outliers %>%
filter(name == "Rupert Doppler (Fraktionslos)") %>%
summarise(name = first(name), year = mean(year), anzahl_reden = mean(anzahl_reden))
# Grafik erstellen
plot2 <- ggplot(df01_year, aes(x = year, y = anzahl_reden)) +
geom_jitter(width = 0.2, alpha = 0.6, size = 1.5, color = "#b8a552") +
geom_ellipse(data = doppler_center, aes(x0 = year - 0.1, y0 = anzahl_reden,
a = 0.95, b = 3, angle = 0),
color = "black", linewidth = 0.5, fill = NA) +
annotate("segment", x = doppler_center$year + 0.6, y = doppler_center$anzahl_reden - 2,
xend = doppler_center$year + 1.2, yend = doppler_center$anzahl_reden - 4,
color = "black", linewidth = 0.5) +
annotate("text", x = doppler_center$year + 3, y = doppler_center$anzahl_reden - 5,
label = doppler_center$name, size = 11, color = "black") + # Beschriftung für Rupert Doppler
geom_text_repel(data = df_outliers %>% filter(name != "Rupert Doppler (Fraktionslos)"),
aes(x = year + 1.2, y = anzahl_reden, label = name),
size = 11, color = "black", box.padding = 0.3, point.padding = 0.1, force = 2) + # Beschriftung für alle anderen Ausreißer
stat_summary(fun = median, geom = "crossbar", width = 0.7, color = "#132843", size = 0.3) +
scale_x_continuous(breaks = seq(1, max(df01_year$year), by = 1),
labels = function(x) paste0(x), limits = c(0.6, 25.4)) +
scale_y_continuous(breaks = seq(0, 100, by = 25)) +
labs(title = "Anzahl der Reden seit Mandatsbeginn", subtitle = "Abgeordnete mit Eintrittsdatum Jän. 1996 – Okt. 2024; pro Jahr im Nationalrat",
x = "Jahre seit Eintritt", y = "Anzahl der Reden",
caption = "Quelle: parlament.gv.at") +
custom_theme()
# Median Beschriftung hinzufügen
grafik2 <- plot2 +
annotation_custom(
grob = textGrob("Median", x = unit(0, "npc"), y = unit(0.128, "npc"), just = "left", gp = gpar(fontsize = 27)),
xmin = -Inf, xmax = -Inf, ymin = -Inf, ymax = Inf)
# Grafik speichern
ggsave("SC13_Grafik02.jpg", grafik2, width = 10, height = 7.5, units = "in", dpi = 300)
### 3. Grafik: Anzahl an Reden nach Jahr im Parlament - kumuliert
# Berechnen der kumulierten Reden pro Jahr seit Mandatsbeginn
df01_year_cum <- df01_year %>%
group_by(parlid) %>%
mutate(kumulierte_reden = cumsum(anzahl_reden)) %>%
ungroup()
# Zeile für Jahr 0 hinzufügen
df01_year_zero <- df01_year %>%
distinct(parlid) %>%
mutate(year = 0, kumulierte_reden = 0)
df01_year_cum <- bind_rows(df01_year_zero, df01_year_cum)
# Zeilen für Jahre 2021-24/2014 für Sobotka/Prammer hinzufügen (keine Reden in diesen Jahren und danach, also nicht automatisch berücksichtigt)
df01_year_extra <- data.frame(
parlid = as.double(c("88386", "88386", "88386", "88386", "4476")),
year = c(4, 5, 6, 7, 15),
anzahl_reden = c(0, 0, 0, 0, 0),
kumulierte_reden = c(2, 2, 2, 2, 79),
name = c("Mag. Wolfgang Sobotka", "Mag. Wolfgang Sobotka", "Mag. Wolfgang Sobotka", "Mag. Wolfgang Sobotka", "Mag. Barbara Prammer"))
df01_year_final <- bind_rows(df01_year_extra, df01_year_cum)
# Abgeordnete auswählen, die hervorgehoben werden sollen
highlight_parlids <- c("83121", "8242", "35468", "51558", "4476", "4395", "35520", "14795", "83122", "14842", "88386")
# Labels der ausgewählten Abgeordneten anpassen
df01_year_final <- df01_year_final %>%
mutate(highlight = ifelse(parlid %in% highlight_parlids, "highlight", "other")) %>%
mutate(name = recode(name,
"Rupert Doppler" = "Rupert Doppler\n(FPÖ/Fraktionslos)", "Leopold Steinbichler" = "Leopold Stein-\nbichler (STRONACH)", "Mag. Beate Meinl-Reisinger, MES" = "Beate Meinl-\nReisinger (NEOS)",
"Dr. Dagmar Belakowitsch" = "Dagmar Belakowitsch (FPÖ)", "Mag. Gerald Loacker" = "Gerald Loacker (NEOS)", "Herbert Kickl" = "Herbert Kickl (FPÖ)",
"Mag. Werner Kogler" = "Werner Kogler (GRÜNE)", "Kai Jan Krainer" = "Kai Jan Krainer (SPÖ)", "August Wöginger" = "August Wöginger (ÖVP)",
"Mag. Barbara Prammer" = "Barbara Prammer (SPÖ)", "Mag. Wolfgang Sobotka" = "Wolfgang Sobotka (ÖVP)"))
# Farben für die hervorgehobenen Linien festlegen (Parteifarben)
party_colors_lines <- c("83121" = "#e3257b", "8242" = "#69b12e", "35468" = "#0052fb", "51558" = "#0052fb", "4476" = "#ff0000",
"4395" = "#f8e924", "35520" = "#0052fb", "14795" = "#62c3d0", "83122" = "#e3257b", "14842" = "#ff0000", "88386" = "#62c3d0")
# Farben zu den Daten hinzufügen
df01_year_final <- df01_year_final %>%
mutate(color = party_colors_lines[as.character(parlid)])
df01_year_final <- df01_year_final %>% mutate(parlid = as.character(parlid))
# Labels für die hervorgehobenen Linien festlegen
df01_labels <- df01_year_final %>%
filter(parlid %in% highlight_parlids) %>%
group_by(parlid) %>%
filter(year == max(year))
# Durchschnittliche Reden pro Jahr berechnen (Für die Durchschnittslinie)
df_avg <- df01_year_final %>%
group_by(year) %>%
summarise(durchschnitt_reden = mean(anzahl_reden, na.rm = TRUE), .groups = "drop") %>%
filter(!(year == 0)) # Entfernt Jahr 0 mit NA
# Durchschnittliche Reden kumulieren
df_avg <- bind_rows(
tibble(year = 0, durchschnitt_reden = 0), df_avg) %>%
arrange(year) %>%
mutate(kumuliert = cumsum(durchschnitt_reden))
# Label für den Durchschnittswert
df_avg_label <- df_avg %>%
filter(year == max(year)) %>%
mutate(name = "Durchschnitt")
# Grafik erstellen
grafik3 <- ggplot() +
# Restliche Abgeordnete
geom_line(data = df01_year_final %>% filter(highlight == "other"),
aes(x = year, y = kumulierte_reden, group = parlid),
color = "grey70", alpha = 0.6, size = 0.8) +
# Hervorgehobene Abgeordnete
geom_line(data = df01_year_final %>% filter(highlight == "highlight"),
aes(x = year, y = kumulierte_reden, group = parlid, color = parlid),
size = 1) +
# Durchschnittlinie
geom_line(data = df_avg,
aes(x = year, y = kumuliert),
color = "#132843", linetype = "dashed", size = 1) +
scale_color_manual(values = party_colors_lines) +
scale_x_continuous(breaks = seq(0, max(df01_year_final$year), by = 1),
labels = function(x) paste0(x), limits = c(0, 28)) +
labs(title = "Anzahl der Reden seit Mandatsbeginn",
subtitle = "Abgeordnete mit Eintrittsdatum Jän. 1996 – Okt. 2024; kumuliert pro Jahr im Nationalrat",
x = "Jahre seit Eintritt", y = "Anzahl der Reden", caption = "Quelle: parlament.gv.at") +
custom_theme() +
theme(legend.position = "") +
geom_text_repel(data = df01_labels,
aes(x = year, y = kumulierte_reden, label = name),
color = "#132842", size = 11, lineheight = 0.35,
nudge_x = ifelse(df01_labels$parlid == "4395", -0.5,
ifelse(df01_labels$parlid == "83122", -0.8,
ifelse(df01_labels$parlid %in% c("51558", "83121"), 0.5, 0.5))),
nudge_y = ifelse(df01_labels$parlid == "4395", 5,
ifelse(df01_labels$parlid == "83122", 10,
ifelse(df01_labels$parlid %in% c("51558", "83121"), 5, 0))),
segment.color = "#132842") +
geom_text_repel(data = df_avg_label,
aes(x = year, y = kumuliert, label = name),
color = "#132842", size = 11, segment.color = "#132842",
nudge_x = 1.5)
ggsave("SC13_Grafik03.jpg", grafik3, width = 10, height = 7.5, units = "in", dpi = 300)