#######################################################
## Open Data Kooperation: univie & Parlament ##########
## Showcase 11: Der Bundesrat in EU-Angelegenheiten ###
## code by Laurenz Ennser-Jedenastik & Daniel Bliem ###
### Kontakt: laurenz.ennser@univie.ac.at ##############
#######################################################
# Leeren der Arbeitsumgebung
rm(list = ls())
# Installieren und Laden der erforderlichen Pakete.
necessary.packages <- c(
"httr",
"jsonlite",
"RJSONIO",
"RCurl",
"httr2",
"purrr",
"tibble",
"rjson",
"tidyverse",
"gridExtra",
"stringr",
"showtext",
"ggpattern",
"plyr")
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)
### 1. Dataframe: 1. Datensatz: EU-betreffende Materialen des Bundesrats
# Definieren des Verzeichnisses zum Abspeichern der JSON Files
setwd("Pfad/zu/Ihrem/Speicherort")
# Definition von API-URI und Body des API-Calls
req <- request("https://www.parlament.gv.at/Filter/api/filter/data/101?js=eval&showAll=true&export=true")
t1 <-
req %>%
req_body_raw('{
"NRBR": [
"BR"
],
"GP_CODE": [
"XXVII",
"XXVI",
"XXV",
"XXIV"
],
"VHG": [
"EU"
],
"VHG2": [
"SB-BR",
"MT-BR",
"S-BR"
]
}') %>%
req_perform()
# Die Antwort in einen Dataframe laden
df1 <- t1 %>% resp_body_json()
# Loop zur Umwandlung von relativen Links aus den Ergebnislisten des API-Calls zu absoluten Links
nrows1 <- length(df1$rows)
vorne <- "https://www.parlament.gv.at"
hinten <- "?json=true"
all.urls <- rep(NA, nrows1)
all.types <- rep(NA, nrows1)
all.numbers <- rep(NA, nrows1)
all.GPs <- rep(NA, nrows1)
# Iterieren durch die Reihen, um aus den Links herunterladbare URLs zu machen
for (i in 1:nrows1) {
all.types[i] <- df1[["rows"]][[i]][[2]]
all.numbers[i] <- df1[["rows"]][[i]][[3]]
all.GPs[i] <- df1[["rows"]][[i]][[1]]
all.urls[i] <- paste0(vorne, df1[["rows"]][[i]][[15]], hinten)
}
for (i in 1:nrows1){
download.file(all.urls[i], destfile = paste0(all.GPs[i], "_", all.types[i], "_", all.numbers[i], ".json"))
}
### 2. Datensatz: EU-betreffende Materialen des Nationalrats
# Definition von API-URI und Body des API-Calls
req2 <- request("https://www.parlament.gv.at/Filter/api/filter/data/101?js=eval&showAll=true&export=true")
t2 <-
req2 %>%
req_body_raw('{
"NRBR": [
"NR"
],
"GP_CODE": [
"XXVII",
"XXVI",
"XXV",
"XXIV"
],
"VHG": [
"EU"
],
"VHG2": [
"MTEU",
"S",
"SEU"
]
}') %>%
req_perform()
# Die Antwort in einen Dataframe laden
df2 <- t2 %>% resp_body_json()
# Loop zur Umwandlung von relativen Links aus den Ergebnislisten des API-Calls zu absoluten Links
nrows2 <- length(df2$rows)
all.urls2 <- rep(NA, nrows2)
all.types2 <- rep(NA, nrows2)
all.numbers2 <- rep(NA, nrows2)
all.GPs2 <- rep(NA, nrows2)
# Iterieren durch die Reihen, um aus den Links herunterladbare URLs zu machen
for (i in 1:nrows2) {
all.types2[i] <- df2[["rows"]][[i]][[2]]
all.numbers2[i] <- df2[["rows"]][[i]][[3]]
all.GPs2[i] <- df2[["rows"]][[i]][[1]]
all.urls2[i] <- paste0(vorne, df2[["rows"]][[i]][[15]], hinten)
}
for (i in 1:nrows2){
download.file(all.urls2[i], destfile = paste0(all.GPs2[i], "_", all.types2[i], "_", all.numbers2[i], ".json"))
}
# Erstellen der leeren Variablen für den Dataframe
files.in.dir <- list.files(path = "Pfad/zu/Ihrem/Speicherort", pattern = "*.json", full.names = TRUE)
count.files <- length(files.in.dir)
df01 <- data.frame()
# Iterieren durch alle Dateien im Verzeichnis und extrahieren relevanter Informationen in den Dataframe
for (i in 1:count.files) {
getfile <- fromJSON(file = files.in.dir[i])
print(files.in.dir[i])
name <- getfile[["content"]][["title"]]
nr <- getfile[["content"]][["inr"]]
typ <- getfile[["content"]][["ityp"]]
einlangen <- getfile[["content"]][["stages"]][[1]][["date"]]
gp <- getfile[["content"]][["nr_gp_code"]]
# Anzahl der Referenzen überprüfen
ref_list <- getfile[["content"]][["reference"]]
if (length(ref_list) > 0) {
ref <- ref_list[[1]][["zitation"]]
} else {
ref <- NA
}
if (length(ref_list) > 1) {
ref_2 <- ref_list[[2]][["zitation"]]
} else {
ref_2 <- NA
}
if (length(ref_list) > 2) {
ref_3 <- ref_list[[3]][["zitation"]]
} else {
ref_3 <- NA
}
# Daten dem Dataframe hinzufügen
df01 <- rbind(df01, data.frame(name = name,
nr = nr,
typ = typ,
einlangen = einlangen,
gp = gp,
ref = ref,
ref_2 = ref_2,
ref_3 = ref_3,
ref_4 = ref_4,
stringsAsFactors = FALSE))
}
# Hinzufügen einer zusätzliche Jahresvariable, indem das Jahr aus dem "einlangen"-Datum extrahiert wird
df01$year <- format(as.Date(df01$einlangen, format = "%d.%m.%Y"), "%Y")
df01$year <- as.numeric(df01$year)
# Hinzufügen einer Variable, die die Parlamentskammer anzeigt
df01 <- df01 %>%
mutate(NRBR = ifelse(typ %in% c("S", "SEU", "MTEU"), "NR",
ifelse(typ %in% c("MT-BR", "S-BR", "SB-BR"), "BR", NA)))
# Speichern des Dataframes
save(df01, file = "Ihr_Dateiname.RData")
### 2. Dataframe: EU-Ausschüsse
# Neuen Speicherort für die Dateien festlegen
setwd("Pfad/zu/Ihrem/neuen/Speicherort")
# Liste der URLs (aufgrund der geringen Anzahl schneller als API-Call)
urls_to_download <- c(
"https://www.parlament.gv.at/ausschuss/BR/A-EU-BR/1/00037?json=true",
"https://www.parlament.gv.at/ausschuss/XXVII/A-HA/1/00868?json=true",
"https://www.parlament.gv.at/ausschuss/XXVII/SA-EU/1/00870?json=true",
"https://www.parlament.gv.at/ausschuss/XXVI/A-HA/1/00823?json=true",
"https://www.parlament.gv.at/ausschuss/XXVI/SA-EU/1/00828?json=true",
"https://www.parlament.gv.at/ausschuss/XXV/A-HA/1/00344?json=true",
"https://www.parlament.gv.at/ausschuss/XXV/SA-EU/1/00351?json=true",
"https://www.parlament.gv.at/ausschuss/XXIV/A-HA/1/00277?json=true",
"https://www.parlament.gv.at/ausschuss/XXIV/SA-EU/1/00279?json=true"
)
# Iterieren über jede URL in der Liste
for (url in urls_to_download) {
tryCatch({
response <- request(url) %>% req_perform()
detailed_json <- response %>% resp_body_json()
file_name <- sub(".*ausschuss/([^?]+).*", "\\1", url)
file_name <- gsub("[^a-zA-Z0-9_]", "_", file_name)
file_name <- paste0(file_name, ".json")
writeLines(jsonlite::toJSON(detailed_json, pretty = TRUE), con = file_name)
cat("Heruntergeladen und gespeichert:", file_name, "\n")
})
}
# Erstellen der leeren Variablen für den Dataframe
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)
df02 <- 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])
gp <- getfile[["content"]][["gp_code"]]
ausschuss <- getfile[["content"]][["type"]]
NRBR <- ifelse(gp == "BR", "BR", "NR")
sitzungen <- list()
stages <- getfile[["content"]][["phase"]][[1]][["stages"]]
for (j in seq_along(stages)) {
sitzungen[[paste0("sitzung_", j, "_text")]] <- stages[[j]][["text"]]
sitzungen[[paste0("sitzung_", j, "_date")]] <- stages[[j]][["date"]]
sitzungen[[paste0("sitzung_", j, "_id")]] <- stages[[j]][["sitzung_id"]]
}
new_row <- data.frame(gp = gp,
ausschuss = ausschuss,
NRBR = NRBR,
stringsAsFactors = FALSE)
new_row <- cbind(new_row, as.data.frame(sitzungen, stringsAsFactors = FALSE))
df02 <- rbind.fill(df02, new_row)
}
# Dataframe von Wide zu Long transformieren
df02_long <- df02 %>%
pivot_longer(
cols = starts_with("sitzung_"),
names_to = c("sitzung_nr", ".value"),
names_pattern = "sitzung_(\\d+)_(.*)"
) %>%
filter(!(is.na(text) & is.na(date)))
# Untersuchungszeitraum filtern (ab Inkraftreten des Vertrags von Lissabon)
df02_long <- df02_long %>%
mutate(date = as.Date(date, format = "%d.%m.%Y")) %>%
filter(date >= as.Date("2009-12-01"))
# Speichern der Daten
save(df02_long, file = "Ihr_Dateiname.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: Jährliche EU-Beschlüsse nach Kammer
# Gruppieren nach Jahr und Kammer
df01_summary <- df01 %>%
group_by(year, NRBR) %>%
dplyr::summarise(count = n()) %>%
ungroup()
# Sicherstellen, dass jedes Jahr für beide Kammern einen Eintrag hat, auch wenn dieser 0 ist
df01_summary <- df01_summary %>%
complete(year, NRBR, fill = list(count = 0))
# Grafik erstellen
grafik1 <- ggplot(df01_summary, aes(x = factor(year), y = count, fill = NRBR)) +
geom_bar(stat = "identity", position = "dodge", width = 0.8) +
labs(title = "Beschlüsse der Ausschüsse mit EU-Bezug im Bundesrat und Nationalrat",
subtitle = "Dez. 2009 - Okt. 2024", x = "", y = "", caption = "Quelle: parlament.gv.at") +
scale_fill_manual(values = c("NR" = "#132843", "BR" = "#b8a552"),
labels = c("NR" = "Nationalrat", "BR" = "Bundesrat")) +
scale_y_continuous(breaks = seq(0, max(16), by = 2), expand = c(0, 0)) +
scale_x_discrete(expand = c(0, 0)) +
custom_theme() +
theme(legend.position = "bottom",
legend.title = element_blank())
ggsave("SC11_Grafik01.jpg", grafik1, width = 10, height = 7.5, units = "in", dpi = 300)
### 2. Grafik: Anzahl der Sitzungen der EU-Ausschüsse
# Sitzungen rausfiltern: Sitzungen, die sich nicht auf EU beziehen; abgesagte Sitzungen, u.ä.
df02_filtered <- df02_long %>%
filter(!(grepl("Aussendung", text, ignore.case = TRUE) |
(ausschuss == "Hauptausschuss" & !grepl("mit EU-Angelegenheiten", text, ignore.case = TRUE)) |
(grepl("Bericht", text, ignore.case = TRUE) |
(grepl("Festsetzung", text, ignore.case = TRUE)) |
(grepl("<leer>", text, ignore.case = TRUE)))))
# Gruppieren und Labels anpassen
df02_counts <- df02_filtered %>%
group_by(NRBR, ausschuss) %>%
dplyr::summarise(count = n()) %>%
mutate(ausschuss = case_when(
ausschuss == "Ständiger Unterausschuss in Angelegenheiten der EU" ~ "Ständiger Unterausschuss des Hauptausschusses\nin Angelegenheiten der EU",
ausschuss == "Hauptausschuss" ~ "Hauptausschuss\nin Angelegenheiten der EU", TRUE ~ ausschuss))
# Grafik erstellen
grafik2 <- ggplot(df02_counts, aes(x = factor(NRBR, levels = c("NR", "BR")), y = count, fill = ausschuss)) +
geom_bar(stat = "identity", width = 0.3) +
geom_text(aes(label = ausschuss),
position = position_stack(vjust = 0.5),
color = ifelse(df02_counts$NRBR == "BR", "black", "white"), size = 12, lineheight = 0.4) +
labs(title = "Sitzungen der Ausschüsse mit EU-Bezug",
subtitle = "Dez. 2009 – Okt. 2024",
x = "", y = "", caption = "Quelle: parlament.gv.at") +
custom_theme() +
scale_fill_manual(values = c("#b8a552", "#415972", "#132843")) +
scale_x_discrete(labels = c("Nationalrat", "Bundesrat")) +
theme(legend.position = "") +
coord_flip()
ggsave("SC11_Grafik02.jpg", grafik2, width = 10, height = 7.5, units = "in", dpi = 300)
### 3. Grafik: Überschneidungen zwischen den Kammern
# Daten nach NR und BR aufteilen
df01_nr <- df01 %>% filter(NRBR == "NR")
df01_br <- df01 %>% filter(NRBR == "BR")
# Alle Werte der Variablen ref, ref_2 und ref_3 (Referenz, worauf sich der Gegenstand bezieht) in den NR- und BR-Gruppen extrahieren und NA Werte entfernen
nr_refs <- unique(c(df01_nr$ref, df01_nr$ref_2, df01_nr$ref_3))
br_refs <- unique(c(df01_br$ref, df01_br$ref_2, df01_br$ref_3))
nr_refs <- nr_refs[!is.na(nr_refs)]
br_refs <- br_refs[!is.na(br_refs)]
# Finden der Überschneidungen zwischen Nationalrat und Bundesrat
overlap_refs <- intersect(nr_refs, br_refs)
# Anzahl der Gegenstände für jede Kategorie berechnen
count_nr <- length(nr_refs)
count_br <- length(br_refs)
count_overlap <- length(overlap_refs)
# Erstellen eines Dataframes mit den Ergebnissen für die Darstellung
df01_overlap <- data.frame(
Category = c("Bundesrat", "Bundesrat", "Nationalrat", "Nationalrat"),
Type = factor(c("Bundesrat", "Überschneidung", "Überschneidung", "Nationalrat"),
levels = c("Bundesrat", "Überschneidung", "Nationalrat")),
Count = c(count_br - count_overlap / 2, count_overlap / 2, count_overlap / 2, count_nr - count_overlap / 2))
# Überschneidungen durch 2 teilen, damit sie nicht doppelt gezählt werden
df01_overlap <- df01_overlap %>%
mutate(Count = if_else(Type == "Überschneidung", Count / 2, Count))
# Reihenfolge der Kammern in der Grafik festlegen
df01_overlap <- df01_overlap %>%
mutate(Type = factor(Type, levels = c("Nationalrat", "Überschneidung", "Bundesrat")))
# Gruppieren der Daten für die Beschriftung in der Grafik
label_data <- df01_overlap %>%
group_by(Type) %>%
dplyr::summarise(Total_Count = sum(Count)) %>%
mutate(Type = factor(Type, levels = c("Bundesrat", "Überschneidung", "Nationalrat"))) %>%
arrange(Type)
# Grafik erstellen
grafik3 <- ggplot(df01_overlap, aes(x = "", y = Count, fill = Category, pattern = Type)) +
geom_col_pattern(
position = "stack", width = 0.3,
pattern_fill = "#132843",
fill = c("#b8a552", "#b8a552", "#b8a552", "#132843"),
pattern_spacing = 0.03, pattern_density = 0.5, pattern_angle = 45
) +
geom_text(data = label_data, aes(label = Total_Count, x = "", y = Total_Count),
position = position_stack(vjust = 0.5),
color = ifelse(label_data$Type == "Bundesrat", "black", "white"), size = 14, inherit.aes = FALSE
) +
scale_fill_manual(
values = c("Nationalrat" = "#132843", "Bundesrat" = "#b8a552"),
labels = c("Nationalrat", "Bundesrat")
) +
scale_pattern_manual(
values = c("Bundesrat" = "none", "Überschneidung" = "stripe", "Nationalrat" = "none"),
labels = c("Bundesrat" = "Bundesrat", "Überschneidung" = "Überschneidung", "Nationalrat" = "Nationalrat"),
guide = guide_legend(
override.aes = list(
fill = c("#b8a552", "#b8a552", "#132843"),
pattern_fill = c(NA, "#132843", NA), pattern_density = c(0, 0.5, 0), pattern_angle = c(0, 45, 0), pattern_spacing = c(0, 0.03, 0)),
reverse = TRUE)) +
labs(
title = "Überschneidungen in der Tätigkeit der Ausschüsse mit EU-Bezug",
subtitle = "Dez. 2009 – Okt. 2024",
x = "", y = "", caption = "Quelle: parlament.gv.at"
) +
custom_theme() +
theme(
legend.position = "bottom",
legend.title = element_blank()) +
coord_flip()
ggsave("SC11_Grafik03.jpg", grafik3, width = 10, height = 7.5, units = "in", dpi = 300)