Skip to content
Snippets Groups Projects
Commit 58dc5374 authored by untergeekDE's avatar untergeekDE
Browse files

Leicht angepasst nach Kassel und Darmstadt

parent a5da5fe7
Branches
No related tags found
No related merge requests found
# Auswertung nach Stadtteilen vs. Kommunalwahlergebnis 2021
# Parteienliste
parteien_df <- read.xlsx("index/obwahl_da_2023/parteien-kommunalwahl.xlsx")
# Kommunaldaten: Stadtverordnetenwahl
kommunal_url <- "https://votemanager-da.ekom21cdn.de/2021-03-14/06411000/praesentation/Open-Data-06411000-Stadtverordnetenwahl-Wahlbezirk.csv?ts=1679256774922"
k_stimm_df <- lies_stimmbezirke(kommunal_url) %>%
# Die Spalten D1-D14 enthalten die Gesamtergebnisse der Parteien.
# Unzählige weitere Spalten enthalten die Ergebnisse für jeden Kandidaten
# auf den sehr, sehr langen Wahllisten.
select(zeitstempel,
nr,
name,
meldungen_anz,
meldungen_max,
wahlberechtigt,
waehler_regulaer,
waehler_wahlschein,
waehler_nv,
stimmen,
stimmen_wahlschein,
ungueltig,
gueltig,
matches("D[0-9]+$")) %>%
mutate(nr = as.integer(str_extract(nr,"[0-9]+")))
k_stadtteile_df <- k_stimm_df %>%
left_join(stimmbezirke_df %>% select(nr,ortsteilnr,stadtteil),
by="nr") %>%
group_by(ortsteilnr) %>%
# Fasse alle Spalten von meldungen_anz bis Ende der Tabelle zusammen -
# mit der sum()-Funktion (NA wird wie null behandelt)
summarize(zeitstempel = last(zeitstempel),
nr = first(ortsteilnr),
meldungen_anz = sum(meldungen_anz,na.rm =T),
meldungen_max = sum(meldungen_max,na.rm = T),
wahlberechtigt = sum(wahlberechtigt, na.rm = T),
waehler_regulaer = sum(waehler_regulaer, na.rm = T),
waehler_wahlschein = sum(waehler_wahlschein, na.rm = T),
waehler_nv = sum(waehler_nv, na.rm = T),
stimmen = sum(stimmen, na.rm = T),
stimmen_wahlschein = sum(stimmen_wahlschein, na.rm = T),
ungueltig = sum(ungueltig, na.rm = T),
gueltig = sum(gueltig, na.rm = T),
across(starts_with("D"), ~ sum(.,na.rm = T))) %>%
mutate(across(where(is.numeric), ~ifelse(is.na(.), 0, .))) %>%
# Stadtteilnamen, Geokoordinaten dazuholen
left_join(stadtteile_df, by="nr") %>%
# Wichtige Daten für bessere Lesbarkeit nach vorn
relocate(zeitstempel,nr,name,lon,lat)
# Sicherheitscheck: Warnen, wenn nicht alle Ortsteile zugeordnet
if (nrow(stadtteildaten_df) != nrow(stadtteile_df)) teams_warnung("Nicht alle Stadtteile zugeordnet")
if (nrow(stimmbezirke_df) != length(unique(stimmbezirke_df$nr))) teams_warnung("Nicht alle Stimmbezirke zugeordnet")
tmp_long_df <- k_stadtteile_df %>%
pivot_longer(cols = starts_with("D"), names_to = "partei_nr", values_to = "partei_stimmen") %>%
mutate(partei_nr = as.integer(str_extract(partei_nr,"[0-9]+"))) %>%
# Ortsteil- bzw. Stimmbezirks-Gruppen, um dort nach Stimmen zu sortieren
group_by(nr,name) %>%
arrange(desc(partei_stimmen)) %>%
mutate(Platz = row_number()) %>%
left_join(parteien_df %>% select(partei_nr = Nummer,
partei = Parteikürzel,
farbe= Farbwert), by="partei_nr") %>%
mutate(prozent = if_else(gueltig != 0,partei_stimmen / gueltig * 100, 0))
k_ergänzt_df <- tmp_long_df %>%
# Ist noch nach Stadtteil (name, nr) sortiert
arrange(partei_nr) %>%
# Alles weg, was verhindert, was individuell auf den Kand ist - außer
# kand und Prozentwert
select(-partei_stimmen, -partei_nr, -Platz, -farbe) %>%
# Kandidatennamen in die Spalten zurückverteilen
pivot_wider(names_from = partei, values_from = prozent) %>%
ungroup() %>%
# und die zweite Hälfte dazu:
left_join(
tst <- tmp_long_df %>%
# Brauchen nur die Kand-Ergebnisse - und den (Stadtteil-)name
select(name, Platz, partei,prozent,farbe) %>%
# Nur die ersten (top) Plätze
filter(Platz <= (3)) %>%
#The Big Pivot: Breite die ersten (3) aus.
pivot_wider(names_from = Platz,
values_from = c(partei,prozent,farbe),
names_glue = "{.value}{Platz}") %>%
ungroup() %>%
select(-nr),
by="name") %>%
# Jetzt auswählen und umbenennen
select(nr, # ortsteilnr
k_wahlberechtigt = wahlberechtigt,
k_stimmen = stimmen,
k_stimmen_wahlschein = stimmen_wahlschein,
k_gueltig = gueltig,
ungueltig:partei3) %>%
rename(k_ungueltig = ungueltig)
ergänzt3_df <- berechne_ergänzt(stadtteildaten_df,3)
vergleichstabelle_df <- ergänzt3_df %>%
left_join(k_ergänzt_df,by="nr") %>%
select(-zeitstempel,
-ortsteilnr,
-meldungen_anz,
-meldungen_max,
-waehler_regulaer,
-waehler_wahlschein,
-waehler_nv)
# Gesamt-Ergebnisse ergänzen
write.xlsx(vergleichstabelle_df,"daten/obwahl_da_2023/vergleichstabelle2021.xlsx", overwrite=T)
# Briefwahlergebnis
urnenwahl_df <- stimmbezirksdaten_df %>%
# Achtung: Prüfen, ob die Benennung der Briefwahllokale hierzu passt.
filter(nr < 9999) %>%
summarize(gueltig = sum(gueltig),
across(starts_with("D"),~ sum(.))) %>%
pivot_longer(cols = starts_with("D"), names_to = "kand_nr",
values_to = "kand_stimmen") %>%
mutate(kand_nr = as.integer(str_extract(kand_nr,"[0-9]+"))) %>%
left_join(kandidaten_df %>% select(kand_nr=Nummer,
Parteikürzel,
kand_name=Name),by="kand_nr") %>%
mutate(`Kandidat/in` = paste0(kand_name," (",Parteikürzel,")")) %>%
mutate(Prozent = kand_stimmen / gueltig *100) %>%
select(`Kandidat/in`, Urnenwahl = Prozent)
briefwahl_df <- stimmbezirksdaten_df %>%
filter(nr > 9999) %>%
summarize(gueltig = sum(gueltig),
across(starts_with("D"),~ sum(.))) %>%
pivot_longer(cols = starts_with("D"), names_to = "kand_nr",
values_to = "kand_stimmen") %>%
mutate(kand_nr = as.integer(str_extract(kand_nr,"[0-9]+"))) %>%
left_join(kandidaten_df %>% select(kand_nr=Nummer,
Parteikürzel,
kand_name=Name),by="kand_nr") %>%
mutate(`Kandidat/in` = paste0(kand_name," (",Parteikürzel,")")) %>%
mutate(Prozent = kand_stimmen / gueltig *100) %>%
select(`Kandidat/in`, Briefwahl = Prozent) %>%
left_join(urnenwahl_df,by = "Kandidat/in")
write.xlsx(briefwahl_df,"daten/briefwahl_ergebnis.xlsx", overwrite = T)
\ No newline at end of file
...@@ -277,6 +277,11 @@ aktualisiere_top <- function(kand_tabelle_df,top=5) { ...@@ -277,6 +277,11 @@ aktualisiere_top <- function(kand_tabelle_df,top=5) {
head(top) head(top)
# Daten pushen # Daten pushen
dw_data_to_chart(daten_df,chart_id = top_id) dw_data_to_chart(daten_df,chart_id = top_id)
# Daten aufs Google Bucket (für CORS-Aktualisierung)
if (SERVER) {
write.csv(daten_df,"daten/top.csv")
system('gsutil -h "Cache-Control:no-cache, max_age=0" cp daten/top.csv gs://d.data.gcp.cloud.hr.de/obwahl_top.csv')
}
# Intro_Text nicht anpassen. # Intro_Text nicht anpassen.
# Balken reinrendern # Balken reinrendern
balken_text <- generiere_auszählungsbalken(gezaehlt,stimmbezirke_n,ts) balken_text <- generiere_auszählungsbalken(gezaehlt,stimmbezirke_n,ts)
...@@ -297,6 +302,10 @@ aktualisiere_tabelle_alle <- function(kand_tabelle_df) { ...@@ -297,6 +302,10 @@ aktualisiere_tabelle_alle <- function(kand_tabelle_df) {
# Daten und Metadaten hochladen, für die Balkengrafik mit allen # Daten und Metadaten hochladen, für die Balkengrafik mit allen
# Stimmen für alle Kandidaten # Stimmen für alle Kandidaten
dw_data_to_chart(kand_tabelle_df, chart_id = tabelle_alle_id) dw_data_to_chart(kand_tabelle_df, chart_id = tabelle_alle_id)
if (SERVER) {
write.csv(kand_tabelle_df,"daten/kand_tabelle.csv")
system('gsutil -h "Cache-Control:no-cache, max_age=0" cp daten/kand_tabelle.csv gs://d.data.gcp.cloud.hr.de/obwahl_kand_tabelle.csv')
}
balken_text <- generiere_auszählung_nurtext(gezaehlt,stimmbezirke_n,ts) balken_text <- generiere_auszählung_nurtext(gezaehlt,stimmbezirke_n,ts)
# Metadaten anpassen: Farbcodes für Parteien # Metadaten anpassen: Farbcodes für Parteien
metadata_chart <- dw_retrieve_chart_metadata(tabelle_alle_id) metadata_chart <- dw_retrieve_chart_metadata(tabelle_alle_id)
...@@ -320,7 +329,12 @@ aktualisiere_karten <- function(ergänzt_df) { ...@@ -320,7 +329,12 @@ aktualisiere_karten <- function(ergänzt_df) {
ergänzt_f_df <- ergänzt_df %>% filter(meldungen_anz > 0) ergänzt_f_df <- ergänzt_df %>% filter(meldungen_anz > 0)
balken_text = generiere_auszählungsbalken(gezaehlt,stimmbezirke_n,ts) balken_text = generiere_auszählungsbalken(gezaehlt,stimmbezirke_n,ts)
dw_edit_chart(chart_id = karte_sieger_id, annotate = balken_text) dw_edit_chart(chart_id = karte_sieger_id, annotate = balken_text)
# Daten pushen
dw_data_to_chart(ergänzt_f_df,chart_id = karte_sieger_id) dw_data_to_chart(ergänzt_f_df,chart_id = karte_sieger_id)
if (SERVER) {
write.csv(ergänzt_f_df,"daten/ergaenzt.csv")
system('gsutil -h "Cache-Control:no-cache, max_age=0" cp daten/ergaenzt.csv gs://d.data.gcp.cloud.hr.de/obwahl_ergaenzt.csv')
}
dw <- dw_publish_chart(karte_sieger_id) dw <- dw_publish_chart(karte_sieger_id)
# Jetzt die Choropleth-Karten für alle Kandidierenden # Jetzt die Choropleth-Karten für alle Kandidierenden
for (i in 1:nrow(switcher_df)) { for (i in 1:nrow(switcher_df)) {
...@@ -333,7 +347,12 @@ aktualisiere_karten <- function(ergänzt_df) { ...@@ -333,7 +347,12 @@ aktualisiere_karten <- function(ergänzt_df) {
aktualisiere_hochburgen <- function(hochburgen_df) { aktualisiere_hochburgen <- function(hochburgen_df) {
# Das ist ziemlich geradeheraus. # Das ist ziemlich geradeheraus.
# Pushe Daten.
dw_data_to_chart(hochburgen_df, chart_id = hochburgen_id) dw_data_to_chart(hochburgen_df, chart_id = hochburgen_id)
if (SERVER) {
write.csv(hochburgen_df,"daten/hochburgen.csv")
system('gsutil -h "Cache-Control:no-cache, max_age=0" cp daten/hochburgen.csv gs://d.data.gcp.cloud.hr.de/obwahl_hochburgen.csv')
}
balken_text <- generiere_auszählung_nurtext(gezaehlt,stimmbezirke_n,ts) balken_text <- generiere_auszählung_nurtext(gezaehlt,stimmbezirke_n,ts)
# Metadaten anpassen: Farbcodes für Parteien # Metadaten anpassen: Farbcodes für Parteien
metadata_chart <- dw_retrieve_chart_metadata(hochburgen_id) metadata_chart <- dw_retrieve_chart_metadata(hochburgen_id)
...@@ -430,7 +449,12 @@ aktualisiere_ergebnistabelle <- function(stadtteildaten_df) { ...@@ -430,7 +449,12 @@ aktualisiere_ergebnistabelle <- function(stadtteildaten_df) {
ungroup() %>% ungroup() %>%
arrange(sort) %>% arrange(sort) %>%
select(-name,-sort) select(-name,-sort)
# Daten pushen
dw_data_to_chart(ergebnistabelle_df %>% select(-nr), chart_id = tabelle_stadtteile_id) dw_data_to_chart(ergebnistabelle_df %>% select(-nr), chart_id = tabelle_stadtteile_id)
if (SERVER) {
write.csv(ergebnistabelle_df,"daten/stadtteile.csv")
system('gsutil -h "Cache-Control:no-cache, max_age=0" cp daten/stadtteile.csv gs://d.data.gcp.cloud.hr.de/obwahl_stadtteile.csv')
}
# Trendergebnis? Schreibe "Trend" oder "Endergebnis" in den Titel # Trendergebnis? Schreibe "Trend" oder "Endergebnis" in den Titel
gezählt <- e_tmp_df %>% pull(meldungen_anz) %>% sum(.) gezählt <- e_tmp_df %>% pull(meldungen_anz) %>% sum(.)
stimmbezirke_n <- e_tmp_df %>% pull(meldungen_max) %>% sum(.) stimmbezirke_n <- e_tmp_df %>% pull(meldungen_max) %>% sum(.)
......
...@@ -85,7 +85,7 @@ check_for_timestamp <- function(my_url) { ...@@ -85,7 +85,7 @@ check_for_timestamp <- function(my_url) {
# } else { # } else {
# t <- tmp[stringr::str_detect(tmp,"last-modified")] %>% # t <- tmp[stringr::str_detect(tmp,"last-modified")] %>%
# stringr::str_replace("last-modified: ","") %>% # stringr::str_replace("last-modified: ","") %>%
# parse_date_time("%a, %d %m %Y %H:%M:%S",tz = "CET") + hours(1) # parse_date_time("%a, %d %m %Y %H:%M:%S",tz = "CET")
# } # }
} else { # lokale Datei } else { # lokale Datei
t = file.info(my_url)$mtime %>% as_datetime t = file.info(my_url)$mtime %>% as_datetime
...@@ -102,7 +102,8 @@ lies_stimmbezirke <- function(stand_url = stimmbezirke_url) { ...@@ -102,7 +102,8 @@ lies_stimmbezirke <- function(stand_url = stimmbezirke_url) {
#' Schreibt eine Meldung ins Logfile - zugleich ein Lesezeichen #' Schreibt eine Meldung ins Logfile - zugleich ein Lesezeichen
cat(as.character(now())," - Neue Daten lesen\n") # Touch logfile cat(as.character(now())," - Neue Daten lesen\n") # Touch logfile
check = tryCatch( check = tryCatch(
{ stand_df <- read_delim(stand_url, {
stand_df <- read_delim(stand_url,
delim = ";", escape_double = FALSE, delim = ";", escape_double = FALSE,
locale = locale(date_names = "de", locale = locale(date_names = "de",
decimal_mark = ",", decimal_mark = ",",
...@@ -129,7 +130,9 @@ lies_stimmbezirke <- function(stand_url = stimmbezirke_url) { ...@@ -129,7 +130,9 @@ lies_stimmbezirke <- function(stand_url = stimmbezirke_url) {
ungueltig = C, ungueltig = C,
gueltig = D, gueltig = D,
# neu: alle Zeilen mit Stimmen (D1..Dn) # neu: alle Zeilen mit Stimmen (D1..Dn)
starts_with("D")) starts_with("D")) %>%
# Zusatz für Frankfurt, das die Stimmbezirksnummern als character überträgt
mutate(nr = as.integer(nr))
}, },
warning = function(w) {teams_warning(w,title="OB-Wahl: Datenakquise")}, warning = function(w) {teams_warning(w,title="OB-Wahl: Datenakquise")},
...@@ -166,8 +169,8 @@ aggregiere_stadtteildaten <- function(stimmbezirksdaten_df = stimmbezirksdaten_d ...@@ -166,8 +169,8 @@ aggregiere_stadtteildaten <- function(stimmbezirksdaten_df = stimmbezirksdaten_d
relocate(zeitstempel,nr,name,lon,lat) relocate(zeitstempel,nr,name,lon,lat)
# Sicherheitscheck: Warnen, wenn nicht alle Ortsteile zugeordnet # Sicherheitscheck: Warnen, wenn nicht alle Ortsteile zugeordnet
if (nrow(stadtteildaten_df) != nrow(stadtteile_df)) teams_warnung("Nicht alle Stadtteile zugeordnet") if (nrow(stadtteildaten_df) != nrow(stadtteile_df)) teams_warning("Nicht alle Stadtteile zugeordnet")
if (nrow(stimmbezirke_df) != length(unique(stimmbezirke_df$nr))) teams_warnung("Nicht alle Stimmbezirke zugeordnet") if (nrow(stimmbezirke_df) != length(unique(stimmbezirke_df$nr))) teams_warning("Nicht alle Stimmbezirke zugeordnet")
cat("Stadtteildaten aggregiert.\n") cat("Stadtteildaten aggregiert.\n")
return(stadtteildaten_df) return(stadtteildaten_df)
} }
...@@ -237,7 +240,9 @@ berechne_kand_tabelle <- function(stimmbezirksdaten_df = stimmbezirksdaten_df) { ...@@ -237,7 +240,9 @@ berechne_kand_tabelle <- function(stimmbezirksdaten_df = stimmbezirksdaten_df) {
left_join(kandidaten_df %>% select(Nummer, Name, Parteikürzel, Farbwert), left_join(kandidaten_df %>% select(Nummer, Name, Parteikürzel, Farbwert),
by="Nummer") %>% by="Nummer") %>%
mutate(name = paste0(Name," (",Parteikürzel,")")) %>% mutate(name = paste0(Name," (",Parteikürzel,")")) %>%
mutate(Prozent = Stimmen / gueltig * 100) %>% mutate(Prozent = ifelse(gueltig > 0,
Stimmen / gueltig * 100,
0)) %>%
select(Nummer, `Kandidat/in` = name, Parteikürzel, Stimmen, Prozent) select(Nummer, `Kandidat/in` = name, Parteikürzel, Stimmen, Prozent)
cat("Gesamttabelle alle Kandidaten berechnet.\n") cat("Gesamttabelle alle Kandidaten berechnet.\n")
return(kand_tabelle_df) return(kand_tabelle_df)
...@@ -355,8 +360,10 @@ hole_wahldaten <- function() { ...@@ -355,8 +360,10 @@ hole_wahldaten <- function() {
} }
# Stadtteil neu ausgezählt? # Stadtteil neu ausgezählt?
} }
if (!exists("NO_SOCIAL")) {
meldung_s <- paste0(meldung_s,"<br><br>", meldung_s <- paste0(meldung_s,"<br><br>",
generiere_socialmedia()) generiere_socialmedia())
}
teams_meldung(meldung_s,title=wahl_name) teams_meldung(meldung_s,title=wahl_name)
check = tryCatch( check = tryCatch(
......
...@@ -25,10 +25,20 @@ ...@@ -25,10 +25,20 @@
# - wahlberechtigt - Zahl der Wahlberechtigen (kommt Sonntag) # - wahlberechtigt - Zahl der Wahlberechtigen (kommt Sonntag)
# - briefwahl - Zahl der Briefwahlstimmen (kommt Sonntag) # - briefwahl - Zahl der Briefwahlstimmen (kommt Sonntag)
# Falls der Parameter wahl_name noch nicht definiert ist,
# setze ihn erst mal auf das derzeitige Verzeichnis.
if (exists("wahl_name")) {
index_pfad = paste0("index/",wahl_name,"/")
} else {
index_pfad = paste0("index/")
}
# Lies die Indexdatei aus dem Verzeichnis wahl_name.
# Falls keines angegeben: aus dem aktuellen Verzeichnis
if (TEST) { if (TEST) {
config_df <- read_csv("index/config_test.csv") config_df <- read_csv(paste0(index_pfad,"config_test.csv"))
} else { } else {
config_df <- read_csv("index/config.csv") config_df <- read_csv(paste0(index_pfad,"config.csv"))
} }
for (i in c(1:nrow(config_df))) { for (i in c(1:nrow(config_df))) {
# Erzeuge neue Variablen mit den Namen und Werten aus der CSV # Erzeuge neue Variablen mit den Namen und Werten aus der CSV
......
...@@ -16,7 +16,7 @@ p_load(R.utils) ...@@ -16,7 +16,7 @@ p_load(R.utils)
rm(list=ls()) rm(list=ls())
TEST = FALSE TEST = FALSE
DO_PREPARE_MAPS = TRUE DO_PREPARE_MAPS = FALSE
...@@ -85,7 +85,7 @@ if (DO_PREPARE_MAPS) { ...@@ -85,7 +85,7 @@ if (DO_PREPARE_MAPS) {
while (gezaehlt < stimmbezirke_n) { while (gezaehlt < stimmbezirke_n) {
check = tryCatch( check = tryCatch(
{ # Zeitstempel der Daten holen { # Zeitstempel der Daten holen
ts_daten <- check_for_timestamp(stimmbezirke_url) ts_daten <- check_for_timestamp(stimmbezirke_url) + hours(1)
}, },
warning = function(w) {teams_warning(w,title=paste0(wahl_name,": CURL-Polling"))}, warning = function(w) {teams_warning(w,title=paste0(wahl_name,": CURL-Polling"))},
error = function(e) {teams_warning(e,title=paste0(wahl_name,": CURL-Polling"))} error = function(e) {teams_warning(e,title=paste0(wahl_name,": CURL-Polling"))}
...@@ -107,6 +107,7 @@ dw_publish_chart(top_id) ...@@ -107,6 +107,7 @@ dw_publish_chart(top_id)
# Logging beenden # Logging beenden
if (!TEST) { if (!TEST) {
cat("OK: FERTIG - alle Stimmbezirke ausgezählt: ",as.character(ts),"\n")
sink() sink()
sink(type="message") sink(type="message")
file.rename("obwahl.log","obwahl_success.log") file.rename("obwahl.log","obwahl_success.log")
......
...@@ -11,19 +11,41 @@ p_load(DatawRappr) ...@@ -11,19 +11,41 @@ p_load(DatawRappr)
p_load(curl) p_load(curl)
p_load(magick) p_load(magick)
p_load(openxlsx) p_load(openxlsx)
p_load(R.utils)
rm(list=ls()) rm(list=ls())
TEST = TRUE
DO_PREPARE_MAPS = FALSE
# Aktuelles Verzeichnis als workdir # Aktuelles Verzeichnis als workdir
setwd(this.path::this.dir()) setwd(this.path::this.dir())
# Aus dem R-Verzeichnis eine Ebene rauf # Aus dem R-Verzeichnis eine Ebene rauf
setwd("..") setwd("..")
# Lies Kommandozeilen-Parameter:
# (Erweiterte Funktion aus dem R.utils-Paket)
args = R.utils::commandArgs(asValues = TRUE)
if (length(args)!=0) {
if (any(c("h","help","HELP") %in% names(args))) {
cat("Parameter: \n",
"--TEST schaltet Testbetrieb ein\n",
"--DO_PREPARE_MAPS schaltet Generierung der Switcher ein\n",
"wahl_name=<name> holt Index-Dateien aus dem Verzeichnis ./index/<name>\n\n")
}
TEST <- "TEST" %in% names(args)
DO_PREPARE_MAPS <- "DO_PREPARE_MAPS" %in% names(args)
if ("wahl_name" %in% names(args)) {
wahl_name <- args[["wahl_name"]]
if (!dir.exists(paste0("index/",wahl_name))) stop("Kein Index-Verzeichnis für ",wahl_name)
}
}
# Defaults
if (!exists("wahl_name")) wahl_name = "obwahl_ffm_stichwahl_2023"
if (!exists("TEST")) TEST = FALSE
if (!exists("DO_PREPARE_MAPS")) DO_PREPARE_MAPS = FALSE
NO_SOCIAL = TRUE
# Logfile anlegen, wenn kein Test # Logfile anlegen, wenn kein Test
# if (!TEST) { # if (!TEST) {
# logfile = file("obwahl.log") # logfile = file("obwahl.log")
......
...@@ -22,6 +22,7 @@ if (Sys.getenv("WEBHOOK_OBWAHL") == "") { ...@@ -22,6 +22,7 @@ if (Sys.getenv("WEBHOOK_OBWAHL") == "") {
teams_meldung <- function(...,title="OB-Wahl-Update") { teams_meldung <- function(...,title="OB-Wahl-Update") {
cc <- teamr::connector_card$new(hookurl = t_txt) cc <- teamr::connector_card$new(hookurl = t_txt)
if (TEST) {title <- paste0("TEST: ",title) }
cc$title(paste0(title," - ",lubridate::with_tz(lubridate::now(), cc$title(paste0(title," - ",lubridate::with_tz(lubridate::now(),
"Europe/Berlin"))) "Europe/Berlin")))
alert_str <- paste0(...) alert_str <- paste0(...)
...@@ -32,13 +33,13 @@ teams_meldung <- function(...,title="OB-Wahl-Update") { ...@@ -32,13 +33,13 @@ teams_meldung <- function(...,title="OB-Wahl-Update") {
teams_error <- function(...) { teams_error <- function(...) {
alert_str <- paste0(...) alert_str <- paste0(...)
teams_meldung(title="OB-Wahl: FEHLER: ", ...) teams_meldung("***FEHLER: ",...)
stop(alert_str) stop(alert_str)
} }
teams_warning <- function(...) { teams_warning <- function(...) {
alert_str <- paste0(...) alert_str <- paste0(...)
teams_meldung("OB-Wahl: WARNUNG: ",...) teams_meldung("***WARNUNG: ",...)
warning(alert_str) warning(alert_str)
} }
...@@ -33,6 +33,18 @@ Grafiken: ...@@ -33,6 +33,18 @@ Grafiken:
* Tabelle nach Kandidaten (3 beste, 3 schlechteste Stadtteile) * Tabelle nach Kandidaten (3 beste, 3 schlechteste Stadtteile)
* Tabelle alle Ergebnisse nach Stadtteil * Tabelle alle Ergebnisse nach Stadtteil
### Aktualisierung via CORS/GBucket
Der normale Weg, eine Datawrapper-Grafik anzuzeigen, ist: pushe die Daten auf den Datawrapper-Server - mit dw_data_to_chart() - und aktualisiere.
Alternativ kann die Grafik aus live bereitgestellten Daten in einem Google Bucket bestückt werden. Die Adressen der Dateien, die an die Grafiken übergeben werden müssen, sind:
- https://d.data.gcp.cloud.hr.de/obwahl_top.csv
- https://d.data.gcp.cloud.hr.de/obwahl_kand_tabelle.csv
- https://d.data.gcp.cloud.hr.de/obwahl_ergaenzt.csv
- https://d.data.gcp.cloud.hr.de/obwahl_hochburgen.csv
- https://d.data.gcp.cloud.hr.de/obwahl_stadtteile.csv
### Konfiguration ### Konfiguration
Das Programm holt sich seine Daten aus einer Konfigurationsdatei - entweder für den Live- oder den Testbetrieb, was über die Variable TEST im Progammcode umgestellt wird. Die Indizes für die jeweile Wahl - Kandidatinnen und Kandidaten, Stadtteile und Wahllokal-Zuordnungen - liegen in einem Unterordner mit dem Namen der Wahl, als CSV oder XLSX. Das Programm holt sich seine Daten aus einer Konfigurationsdatei - entweder für den Live- oder den Testbetrieb, was über die Variable TEST im Progammcode umgestellt wird. Die Indizes für die jeweile Wahl - Kandidatinnen und Kandidaten, Stadtteile und Wahllokal-Zuordnungen - liegen in einem Unterordner mit dem Namen der Wahl, als CSV oder XLSX.
...@@ -86,7 +98,7 @@ Spalte | Wert ...@@ -86,7 +98,7 @@ Spalte | Wert
---- | ---- ---- | ----
nr | ID des Stimmbezirks nr | ID des Stimmbezirks
ortsteilnr | ID des Stadtteils ortsteilnr | ID des Stadtteils
ortsteil Name des Stadtteils ortsteil | Name des Stadtteils
Nicht benötigte Spalten können in der Tabelle bleiben, sollten aber möglichst nicht "name" oder so heißen. Nicht benötigte Spalten können in der Tabelle bleiben, sollten aber möglichst nicht "name" oder so heißen.
...@@ -107,11 +119,28 @@ Aggregation auf Stadtebene ...@@ -107,11 +119,28 @@ Aggregation auf Stadtebene
(siehe ["Sitemap"](./sitemap.md) für den Code) (siehe ["Sitemap"](./sitemap.md) für den Code)
## Vorbereitung einer Wahl
- Shapefile für die Stadt besorgen; Stimmbezirksebene; Stadtteile
- Stadtteile aggregieren, GEOJSON generieren
- Ordner für die Wahl im Index-Ordner; Datei Kandidaten, Stadtteile (mit Geokoordinaten für die Zentrumspunkte), Stimmbezirke (mit Zuordnung Stadtteil)
- Kopien für die vier Grafiken anlegen: Top, alle Stimmen, Hochburgen, Stadtteile. Link zum Wahlamt nicht vergessen.
- Leerdatei Ergebnisse nach Stadtteil vorbereiten
- Kopie der Sieger-Karte mit GEOJSON anlegen; GEOJSON hochladen, Leerdatei hochladen. Link zum Wahlamt korrigieren.
- Eine erste Kopie der Choropleth-Karten nach Kandidat: Wahlamt-Link ändern und Karte und Leerdatei hochladen, dann kopieren.
- Kopien für alle Kandidierenden anlegen. Jeweils die Werte-Spalte des jeweiligen Kandidaten auswählen; benennen, um sie zuordnen zu können. (Farben und Namen werden automatisch nachgetragen.)
- Indexdatei vorbereiten: Wahlname, Anzahl TOP, Dateinahmen der Index-Dateien, Datawrapper-IDs für die Karten und Diagramme
## TODO
- Analyse: Weshalb hängt das Polling manchmal hinterher?
- Aufruf mit Parametern ermöglichen ("main.R obwahl_ffm_2023")
- Oneshot-Variante für Kassel
- Auswertung Briefwahldaten
## Nice-To-Have ## Nice-To-Have
- Vergleich letzte Kommunalwahl
- Zusatzfeature: Briefwahlprognostik - wieviele Stimmen fehlen vermutlich noch? - Zusatzfeature: Briefwahlprognostik - wieviele Stimmen fehlen vermutlich noch?
- Shapefiles KS, DA verbessern - Shapefiles KS, DA verbessern
- Datensparsamere Alternativ-CURL-Poll-Datei (zB mit dem Gesamtergebnis) - Vergleich letzte Kommunalwahl regulär
- Mehr Licht in den Choropleth-Karten farbabhängig \ No newline at end of file
...@@ -8,6 +8,8 @@ Dazu Rechtsklick auf den Layer; Koordinatensystem WGS84, exportieren ...@@ -8,6 +8,8 @@ Dazu Rechtsklick auf den Layer; Koordinatensystem WGS84, exportieren
3. Stadtteile generieren 3. Stadtteile generieren
Menü "Vektor", "Geometrieverarbeitungswerkzeuge", "Auflösen" - und dann in der Dialogbox auswählen "Felder auflösen [optional]", und dann die Attribute hinzufügen, nach denen zusammengeführt werden soll. Menü "Vektor", "Geometrieverarbeitungswerkzeuge", "Auflösen" - und dann in der Dialogbox auswählen "Felder auflösen [optional]", und dann die Attribute hinzufügen, nach denen zusammengeführt werden soll.
Nach den Attributen schauen - die Ortsteilnr. ist ein String, kein Integer! Rechtsklick auf den neuen Layer; Eigenschaften..., dann den "Felder..."-Editor, da oben auf das kleine Abakus-Symbol klicken, Namen für das neue Feld in Ausgabefeldname (z.B. "nr"), dann in Feld Ausdruck eintragen"to_int(Ortsbezirk)" - und OK klicken. Neues Feld wird angelegt. Dann das alte Feld löschen (auswählen, oben Klick auf Löschen-Feld).
- Rechtsklick auf den Layer; Exportieren als GEOJSON - nicht vergessen, das Bezugssystem auf WGS84 umzustellen! - Rechtsklick auf den Layer; Exportieren als GEOJSON - nicht vergessen, das Bezugssystem auf WGS84 umzustellen!
- Rechtsklick auf den Layer; Export als XLSX - ggf. Geo-Attribute abschalten - Rechtsklick auf den Layer; Export als XLSX - ggf. Geo-Attribute abschalten
...@@ -23,3 +25,11 @@ Dann noch Geokoordinaten der Zentroidpunkte: Rechte Seite die Toolbox, dort "Vek ...@@ -23,3 +25,11 @@ Dann noch Geokoordinaten der Zentroidpunkte: Rechte Seite die Toolbox, dort "Vek
- Brauchen eine Stadtteil-Datei mit nr,name,lon,lat (erzeugt aus den Zentroiden) - Brauchen eine Stadtteil-Datei mit nr,name,lon,lat (erzeugt aus den Zentroiden)
- Brauchen einen Wahlbezirks-Zuordnung - Brauchen einen Wahlbezirks-Zuordnung
6. Reparatur der Darmstadt-Karte
- Laden (falsche Geometrie - das erst zum Schluss fixen!)
- Vereinfachen: Fläche
- Auflösen
- Löcher löschen
\ No newline at end of file
name,value,comment
wahl_name,obwahl_ffm_2023,Welche Wahl?
stimmbezirke_url,https://votemanager-ffm.ekom21cdn.de/2023-03-05/06412000/daten/opendata/Open-Data-06412000-OB-Wahl-Wahlbezirk.csv?ts=1677904123448,URL Daten-CSV Stimmbezirke
wahlberechtigt,508182,Anzahl Wahlberechtigte lt. Wahlamt (kommt Sonntag)
briefwahl,250000,Anzahl Briefwahlstimmen lt. Wahlamt (kommt Sonntag)
kandidaten_fname,kandidaten.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
datawrapper_fname,datawrapper.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
zuordnung_fname,zuordnung_wahllokale.csv,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
stadtteile_fname,stadtteile.csv,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
startdatum,2023-03-05 16:00:00,Beginn der Auszählung
top5_id,2DYBQ,
karte_sieger_id,ANKmx,
karte_kand1_id,RcvQp,Rottmann (Grüne)
karte_kand2_id,jrm2v,Becker (CDU)
karte_kand3_id,bKR8r,Josef (SPD)
karte_kand4_id,etN3J,Mehler-Würzbach (Linke)
karte_kand5_id,3mydT,Pürsün (FDP)
karte_kand6_id,K3aCw,Lobenstein (AfD)
karte_kand7_id,vtG4Y,Pfeiffer (BFF)
karte_kand8_id,tRHeI,Tanczos (PARTEI)
karte_kand9_id,v4Y5m,Schwichtenberg (Gartenpartei)
karte_kand10_id,g3iBN,Wirth (unabh.)
karte_kand11_id,4LxcN,Camara (FPF)
karte_kand12_id,RZDF7,Pauli (unabh.)
karte_kand13_id,F86gf,Junghans (unabh.)
karte_kand14_id,bLPXL,Xu (unabh.)
karte_kand15_id,Ktufa,Wolff (unabh.)
karte_kand16_id,MO41j,Akhtar (Todenhöfer)
karte_kand17_id,ccrfL,Großenbach (Basis)
karte_kand18_id,q2S6m,Pawelski (unabh.)
karte_kand19_id,697CL,Schulte (unabh.)
karte_kand20_id,3lMmu,Eulig (unabh.)
tabelle_alle_id,7kRPR,
hochburgen_id,oB3KH,
tabelle_stadtteile_id,LiXnz,
social1_id,2DYBQ,5 stärkste
social2_id,S9BbQ,Alle Stimmen angepasst
name,value,comment
wahl_name,obwahl_ffm_2023,Welche Wahl?
stimmbezirke_url,testdaten/dummy.csv,URL Daten-CSV Stimmbezirke
wahlberechtigt,508182,Anzahl Wahlberechtigte lt. Wahlamt (kommt Sonntag)
briefwahl,250000,Anzahl Briefwahlstimmen lt. Wahlamt (kommt Sonntag)
kandidaten_fname,kandidaten.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
datawrapper_fname,datawrapper.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
zuordnung_fname,zuordnung_wahllokale.csv,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
stadtteile_fname,stadtteile.csv,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
startdatum,2023-01-01 18:00:00 CET,Beginn der Auszählung
top5_id,028Fp,
karte_sieger_id,7gscI,
karte_kand1_id,hM9SE,Rottmann (Grüne)
karte_kand2_id,hM9SE,Becker (CDU)
karte_kand3_id,07CR4,Josef (SPD)
karte_kand4_id,07CR4,Mehler-Würzbach (Linke)
karte_kand5_id,07CR4,Pürsün (FDP)
karte_kand6_id,07CR4,Lobenstein (AfD)
karte_kand7_id,07CR4,Pfeiffer (BFF)
karte_kand8_id,07CR4,Tanczos (PARTEI)
karte_kand9_id,07CR4,Schwichtenberg (Gartenpartei)
karte_kand10_id,07CR4,Wirth (unabh.)
karte_kand11_id,07CR4,Camara (FPF)
karte_kand12_id,07CR4,Pauli (unabh.)
karte_kand13_id,07CR4,Junghans (unabh.)
karte_kand14_id,07CR4,Xu (unabh.)
karte_kand15_id,07CR4,Wolff (unabh.)
karte_kand16_id,07CR4,Akhtar (Todenhöfer)
karte_kand17_id,07CR4,Großenbach (Basis)
karte_kand18_id,07CR4,Pawelski (unabh.)
karte_kand19_id,07CR4,Schulte (unabh.)
karte_kand20_id,07CR4,Eulig (unabh.)
tabelle_alle_id,PLwHI,
hochburgen_id,Im2PX,
tabelle_stadtteile_id,BM8kD,
social1_id,028Fp,5 stärkste
social2_id,S9BbQ,Alle Stimmen angepasst
name,value,comment
wahl_name,obwahl_ks_2023,Welche Wahl?
stimmbezirke_url,https://votemanager-ks.ekom21cdn.de/2023-03-12/06611000/daten/opendata/Open-Data-06611000-Direktwahl-zur-Oberbuergermeisterin-zum-Oberbuergermeister-Wahlbezirk.csv?ts=1678486050153,URL Daten-CSV Stimmbezirke
wahlberechtigt,147463,Anzahl Wahlberechtigte lt. Wahlamt (kommt Sonntag)
briefwahl,39092,Anzahl Briefwahlstimmen lt. Wahlamt (kommt Sonntag)
top,6,Anzahl der Top-Kandidaten in den Darstellungen
kandidaten_fname,kandidaten.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
zuordnung_fname,wahlbezirke.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
stadtteile_fname,ks-stadtteile.csv,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
startdatum,2023-03-12 16:00:00,Beginn der Auszählung
top_id,Ts1oS,
karte_sieger_id,O9wPT,
karte_kand1_id,hM9SE,Schöller
karte_kand2_id,07CR4,Carqueville
karte_kand3_id,whgzp,Kühne-Hörmann
karte_kand4_id,5CpYu,Bock
karte_kand5_id,pc6vH,Käufler
karte_kand6_id,sEJhl,Geselle
tabelle_alle_id,EQ4dd,
hochburgen_id,GMTSJ,
tabelle_stadtteile_id,gJNPD,
social1_id,Ts1oS,5 stärkste
social2_id,S9BbQ,Alle Stimmen angepasst
name,value,comment
wahl_name,obwahl_ks_2023,Welche Wahl?
stimmbezirke_url,https://www.eggers-elektronik.de/files/test.csv,URL Daten-CSV Stimmbezirke
wahlberechtigt,147463,Anzahl Wahlberechtigte lt. Wahlamt (kommt Sonntag)
briefwahl,39092,Anzahl Briefwahlstimmen lt. Wahlamt (kommt Sonntag)
kandidaten_fname,kandidaten.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
zuordnung_fname,wahlbezirke.xlsx,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
stadtteile_fname,ks-stadtteile.csv,"XLSX oder CSV, wird im Ordner <wahl_name> erwartet"
startdatum,2023-01-01 18:00:00 CET,Beginn der Auszählung
top,6,
top_id,028Fp,
karte_sieger_id,7gscI,
karte_kand1_id,hM9SE,Schöller
karte_kand2_id,07CR4,Carqueville
karte_kand3_id,whgzp,Kühne-Hörmann
karte_kand4_id,5CpYu,Bock
karte_kand5_id,pc6vH,Käufler
karte_kand6_id,sEJhl,Geselle
tabelle_alle_id,PLwHI,
hochburgen_id,Im2PX,
tabelle_stadtteile_id,BM8kD,
social1_id,028Fp,5 stärkste
social2_id,S9BbQ,Alle Stimmen angepasst
No preview for this file type
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment