library(sf) library(ggplot2) library(ggtext) library(dplyr) library(rnaturalearth) library(rnaturalearthhires) library(showtext) library(viridis) library(shadowtext) library(ggnewscale) # Variablen hintergrundfarbe <- "#f2f2f2" # Automatisches Laden von Schriftarten und Fira Sans aktivieren showtext_auto() font_add(family = "Fira Sans", regular = "FiraSans-Regular.ttf") # Geodaten für Deutschland laden germany_states <- ne_states(country = "Germany", returnclass = "sf") # CSV-Daten einlesen inf_qual <- read.csv2("~/Informatik-Monitor/Ländervergleich/BL_Informatik_Qualifikationsphase.csv", stringsAsFactors = FALSE) # Daten bereinigen : "n.a." zu NA und Spalten in numerisch umwandeln inf_qual_cl <- inf_qual %>% mutate( GK_Stunden_min = na_if(GK_Stunden_min, "n.a."), LK_Stunden_min = na_if(LK_Stunden_min, "n.a."), Wahl = na_if(Wahl, "n.a.") ) %>% mutate( GK_Stunden_min = as.numeric(GK_Stunden_min), LK_Stunden_min = as.numeric(LK_Stunden_min), Wahl = as.numeric(Wahl) ) # Zeilen mit NA in GK_Stunden_min filtern inf_qual_gefiltert <- inf_qual_cl %>% filter(!is.na(GK_Stunden_min)) # Gruppieren und zusammenfassen inf_qual_aggregiert <- inf_qual_gefiltert %>% group_by(Bundesland) %>% summarise( GK_Stunden_min = min(GK_Stunden_min, na.rm = TRUE), LK_Stunden_min = ifelse(any(is.na(LK_Stunden_min)), "n.a.", as.character(min(LK_Stunden_min, na.rm = TRUE))), Wahl = ifelse(any(is.na(Wahl)), "n.a.", as.character(min(Wahl, na.rm = TRUE))) ) # Spalte hinzufügen für Kategorisierung inf_qual_aggregiert <- inf_qual_aggregiert %>% mutate( Niveau = case_when( LK_Stunden_min != "n.a." ~ "e", LK_Stunden_min == "n.a." & !is.na(GK_Stunden_min) ~ "g", TRUE ~ NA_character_ # optional, falls beides nicht zutrifft ) ) # Spalten in States reduzieren germany_states_min <- germany_states %>% select(Bundesland = name, postal, geometry) # ACHTUNG: postal-Kürzel korrigieren: Brandenburg → "BB" germany_states_min <- germany_states_min %>% mutate(postal = ifelse(Bundesland == "Brandenburg", "BB", postal)) # Vereinigung von Daten und Geometrie inf_qual_karte <- germany_states_min %>% left_join(inf_qual_aggregiert, by = "Bundesland") # Nur die Grenzen extrahieren (Linien) karte_grenzen <- inf_qual_karte %>% st_geometry() %>% st_cast("MULTIPOLYGON") %>% st_boundary() %>% st_sf() # Mittelpunkte der BL-Flächenberechnen und Verschiebung für Positionierung der Labels bundesland_labels <- inf_qual_karte %>% mutate(centroid = st_centroid(geometry)) %>% mutate( x = st_coordinates(centroid)[, 1], y = st_coordinates(centroid)[, 2] ) %>% mutate( x = ifelse(Bundesland == "Brandenburg", x + 0.5, x), # nach Osten y = ifelse(Bundesland == "Brandenburg", y - 0.4, y) # nach Süden ) %>% mutate( x = ifelse(Bundesland == "Berlin", x + 0.12, x), # nach Osten y = ifelse(Bundesland == "Berlin", y + 0.12, y) # nach Norden ) %>% mutate( x = ifelse(Bundesland == "Bremen", x + 0.2, x), # nach Osten y = ifelse(Bundesland == "Bremen", y + 0.04, y) # nach Norden ) %>% mutate( x = ifelse(Bundesland == "Hamburg", x - 0.05, x), # nach Westen y = ifelse(Bundesland == "Hamburg", y - 0.15, y) # nach Süden ) # Karte erzeugen karte <- ggplot(inf_qual_karte) + # Flächen ohne Grenzen geom_sf(data = inf_qual_karte, aes(fill = Niveau), color = NA) + # Innengrenzen separat: weiß, dick geom_sf(data = karte_grenzen, fill = NA, color = hintergrundfarbe, size = 0.3) + coord_sf(expand = FALSE) + geom_shadowtext( data = bundesland_labels, aes(x = x, y = y, label = postal), family = "Fira Sans", # optional size = 3, # anpassbar color = hintergrundfarbe, # evtl. Kontrastfarbe bg.color = "black", bg.r = 0.05, check_overlap = TRUE # verhindert Überlappung ) + scale_fill_manual( values = c("g" = "#3b528b", "e" = "#5ec962"), # "G8/G9" = "#21918c"), name = "Informatik", labels = c( "g" = "grundlegendes Anforderungsniveau", "e" = "grundlegendes und erhöhtes Anforderungsniveau" ), limits = c("g", "e") # ← Reihenfolge der Anzeige ) + labs( title = "Informatikunterricht in der Qualifikationsphase", subtitle = "Informatik in der gymnasialen Oberstufe an allgemeinbildenden Schulen, 2025", caption = "Datenquelle: Informatik-Monitor" ) + theme_minimal() + theme( text = element_text(family = "Fira Sans"), plot.title = element_text(face = "bold", size = 16), plot.subtitle = ggtext::element_markdown(size = 12, lineheight = 1.2), # Hintergrundfarbe überall auf #E9E9E9 setzen plot.background = element_rect(fill = hintergrundfarbe, color = NA), panel.background = element_rect(fill = hintergrundfarbe, color = NA), legend.background = element_rect(fill = hintergrundfarbe, color = NA), legend.key = element_rect(fill = hintergrundfarbe, color = NA), # Rest wie gehabt panel.grid = element_blank(), axis.text = element_blank(), axis.ticks = element_blank(), axis.title = element_blank(), # Rand #plot.margin = margin(0.5, 0.5, 0.5, 0.5, unit = "cm"), #Position Legende legend.position = "bottom", legend.direction = "horizontal", # nebeneinander statt untereinander # legend.justification = c(1, 0), # rechtsbündig legend.box.just = "right", # Box am rechten Rand ausrichten legend.title = element_blank(), plot.margin = margin(1, 1, 1, 1, unit = "cm"), # mehr Platz rechts plot.caption = element_text(margin = margin(t = 15)) ) # Karte anzeigen print(karte) # Karte speichern ggsave( filename = "BL_Oberstufe_IU_Qual_Art.svg", plot = karte, path = "~/Informatik-Monitor/Ländervergleich", width = 18, height = 27, unit = "cm", device = "svg" )