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

(Dummy-Dateien, noch nicht angepasst)

parent 62b662c8
No related branches found
No related tags found
No related merge requests found
#' aktualisiere_karten.R
aktualisiere_karten <- function(wl_url = stimmbezirke_url) {
# Lies Ortsteil-Daten ein und vergleiche
neue_orts_df <- lies_gebiet(wl_url) %>%
aggregiere_stadtteile() %>%
mutate(quorum = ifelse(wahlberechtigt == 0,
0,
ja / wahlberechtigt * 100)) %>%
mutate(status = ifelse(meldungen_anz == 0,
"KEINE DATEN",
paste0(ifelse(meldungen_anz < meldungen_max,
"TREND ",""),
ifelse(ja < nein,
"NEIN",
ifelse(quorum < 30,
"JA",
"JA QUORUM")))
))
alte_orts_df <- hole_letztes_df("daten/ortsteile")
# Datenstand identisch? Dann brich ab.
if(vergleiche_stand(alte_orts_df,neue_orts_df)) {
return(FALSE)
} else {
# Zeitstempel holen
archiviere(neue_orts_df,"daten/ortsteile")
ts <- neue_orts_df %>% pull(zeitstempel) %>% last()
# Datentabelle übertragen
dw_data_to_chart(neue_orts_df,choropleth_id)
dw_data_to_chart(neue_orts_df,symbol_id)
dw_data_to_chart(neue_orts_df,tabelle_id)
# Anmerkungen aktualisieren
wahlberechtigt <- neue_orts_df %>% pull(wahlberechtigt) %>% sum()
# Prozentsatz ausgezählte Stimmen: abgerundet auf ganze Prozent
ausgezählt <- floor(wahlberechtigt / ffm_waehler *100)
annotate_str <- generiere_auszählungsbalken(ausgezählt,
anz = neue_orts_df %>% pull(meldungen_anz) %>% sum(),
max = neue_orts_df %>% pull(meldungen_max) %>% sum(),
ts = ts)
dw_edit_chart(symbol_id,annotate=annotate_str)
dw_edit_chart(choropleth_id,annotate=annotate_str)
dw_edit_chart(tabelle_id,annotate=annotate_str)
dw_publish_chart(symbol_id)
dw_publish_chart(choropleth_id)
dw_publish_chart(tabelle_id)
return(TRUE)
}
}
\ No newline at end of file
#' generiere_testdaten.R
#'
#' Macht aus den Templates für Ortsteil- und Wahllokal-Ergebnisse
#' jeweils eine Serie von fiktiven Livedaten, um das Befüllen der
#' Grafiken testen zu können.
#'
require(tidyr)
require(dplyr)
require(readr)
# Alles weg, was noch im Speicher rumliegt
rm(list=ls())
source("R/lies_aktuellen_stand.R")
#---- Funktion zum Testdaten-Löschen ----
lösche_testdaten <- function(){
q <- tolower(readline(prompt = "Testdaten löschen - sicher? "))
if (!(q %in% c("j","y","ja"))) { return() }
# Datenarchiv weg
if (file.exists("daten/fom_df.rds")){
file.remove("daten/fom_df.rds")
}
# Testdaten
testdaten_files <- list.files("testdaten", full.names=TRUE)
for (f in testdaten_files) {
# Grausam, I know.
if (str_detect(f,"ortsteile[0-9]+\\.csv") |
str_detect(f,"wahllokale[0-9]+\\.csv")) {
file.remove(f)
}
}
}
# Vorlagen laden
vorlage_wahllokale_df <- read_delim("testdaten/Open-Data-06412000-Buergerentscheid-zur-Abwahl-des-Oberbuergermeisters-der-Stadt-Frankfurt-am-Main_-Herrn-Peter-Feldmann-Stimmbezirk.csv",
delim = ";", escape_double = FALSE,
locale = locale(date_names = "de",
decimal_mark = ",",
grouping_mark = "."),
trim_ws = TRUE)
wahllokale_max <- sum(vorlage_wahllokale_df$`max-schnellmeldungen`)
# Konstanten für die Simulation - werden jeweils um bis zu +/-25% variiert
c_wahlberechtigt = 510000 / wahllokale_max # Gleich große Wahlbezirke
c_wahlbeteiligung = 0.3 # Wahlbeteiligung um 30%, wird im Lauf der "Wahl" erhöht (kleinere WL sind schneller ausgezählt)
c_wahlschein = 0.25 # 25% Briefwähler
c_nv = 0.05 # 0,5% wählen "spontan" und sind nicht verzeichnet (nv) im Wählerverzeichnis
c_ungültig = 0.01 # 1% Ungültige
c_nein = 0.15 # unter den gültigen: 85% Ja-Stimmen (Varianz also von ca 81-89%)
variiere <- function(x = 1) {
# Variiert den übergebenen Wert zufällig um -25% bis +25%:
# Zufallswerte zwischen 0,75 und 1,25 erstellen und multiplizieren
#
# Die Length-Funktion ist wichtig - sonst erstellt runif() nur einen
# Zufallswert, mit dem alle Werte von x multipliziert werden.
return(floor(x * (runif(length(x),0.75,1.25))))
}
i = 1
# Schleife für die Wahllokale: Solange noch nicht alle "ausgezählt" sind...
while(sum(vorlage_wahllokale_df$`anz-schnellmeldungen`) < wahllokale_max) {
# ...splitte das df in die gemeldeten (meldungen_anz == 1) und nicht gemeldeten Zeilen
tmp_gemeldet_df <- vorlage_wahllokale_df %>% filter(`anz-schnellmeldungen` == 1)
# Die Variable rand wird als Anteil von 20 Meldungen an debn noch offenen Wahllokale berechnet
rand <- 20 / (nrow(vorlage_wahllokale_df) - nrow(tmp_gemeldet_df))
tmp_sample_df <- vorlage_wahllokale_df %>%
filter(`anz-schnellmeldungen` == 0) %>%
# Bei den noch nicht ausgefüllten "Meldungen" mit einer Wahrscheinlichkeit
# von rand in die Gruppe sortieren, die neu "gemeldet" wird
mutate(sample = (runif(nrow(.)) < rand))
tmp_offen_df <- tmp_sample_df %>%
filter(sample == 0) %>%
# sample-Variable wieder raus
select(-sample)
tmp_neu_df <- tmp_sample_df %>%
filter(sample == 1) %>%
select(-sample) %>%
# Alle als gemeldet markieren
mutate(`anz-schnellmeldungen` = 1) %>%
# Und jetzt der Reihe nach (weil die Werte z.T. aufeinander aufbauen)
# Wahlberechtigte
mutate(A = floor(c_wahlberechtigt * runif(nrow(.),0.75,1.25))) %>%
# Wahlschein
mutate(A2 = floor(A * c_wahlschein * runif(nrow(.),0.75,1.25))) %>%
# Nicht verzeichnet
mutate(A3 = floor(A * c_nv * runif(nrow(.),0.75,1.25))) %>%
# Regulär Wahlberechtigte (ohne Wahlschein oder nv)
mutate(A1 = A - A2 - A3) %>%
# Abgegebene Stimmen
mutate(B = floor(A * c_wahlbeteiligung * runif(nrow(.),0.75,1.25))) %>%
# davon mit Wahlschein
mutate(B1 = floor(B * c_wahlschein * runif(nrow(.),0.75,1.25))) %>%
# davon ungültig
mutate(C = floor(B * c_ungültig * runif(nrow(.),0.75,1.25))) %>%
# gültig
mutate(D = B - C) %>%
# davon ja
mutate(D2 = floor(D * c_nein *runif(nrow(.),0.75,1.25))) %>%
mutate(D1 = D - D2)
# Kurze Statusmeldung
cat("Neu gemeldet:",nrow(tmp_neu_df),"noch offen:",nrow(tmp_offen_df))
# Phew. Aktualisierte Testdatei zusammenführen und anlegen.
vorlage_wahllokale_df <- tmp_gemeldet_df %>%
bind_rows(tmp_neu_df) %>%
bind_rows(tmp_offen_df) %>%
# wieder in die Reihenfolge nach Wahllokal-Nummer
arrange(`gebiet-nr`)
write_csv2(vorlage_wahllokale_df,
paste0("testdaten/wahllokale",
sprintf("%02i",i),
".csv"),
escape = "backslash")
# Generiere die passende Ortsteil-Meldung
# Geht aus irgeneindem Grund nicht, aber wir brauchens ja auch nicht.
# ortsteile_df <- zuordnung_wahllokale_df %>%
# select(`gebiet-name` = name,ortsteilnr) %>%
# left_join(vorlage_wahllokale_df,by="gebiet-name") %>%
# # Zuordnung der Wahllokale
# group_by(ortsteilnr) %>%
# # Das crasht - WTF???
# summarize(across(7:18, ~ sum(.,na.rm = T))) %>%
# left_join(stadtteile_df %>% select(ortsteilnr = nr,name),by="ortsteilnr") %>%
# rename(`gebiet-nr` = ortsteilnr) %>%
# mutate(`gebiet-name` = name) %>%
# select(-ortsteilnr)
i <- i+1
# Wahlbeteiligung schrittweise ein wenig anheben - um zu simulieren,
# dass "kleinere" Wahllokale zuerst ausgezählt werden
c_wahlbeteiligung <- c_wahlbeteiligung + 0.002
}
library(readr)
library(lubridate)
library(tidyr)
library(stringr)
library(dplyr)
# lies_aktuellen_stand.R
#
# Enthält die Funktion zum Lesen der aktuellen Daten.
#---- Vorbereitung ----
# Statische Daten einlesen
# (das später durch ein schnelleres .rda ersetzen)
# Enthält drei Datensätze:
# - opendata_wahllokale_df mit der Liste aller Stimmwahlbezirke nach Wahllokal
# - statteile_df: Stadtteil mit Namen und laufender Nummer, Geokoordinaten, Ergebnissen 2018
# - zuordnung_stimmbezirke: Stimmbezirk-Nummer (als int und String) -> Stadtteilnr.
load ("index/index.rda")
# Konfiguration auslesen und in Variablen schreiben
config_df <- read_csv("index/config.csv")
for (i in c(1:nrow(config_df))) {
# Erzeuge neue Variablen mit den Namen und Werten aus der CSV
assign(config_df$name[i],
# Kann man den Wert auch als Zahl lesen?
# Fieses Regex sucht nach reiner Zahl oder Kommawerten.
# Keine Exponentialschreibweise!
ifelse(grepl("^[0-9]*\\.*[0-9]+$",config_df$value[i]),
# Ist eine Zahl - wandle um
as.numeric(config_df$value[i]),
# Keine Zahl - behalte den String
config_df$value[i]))
}
#---- Daten ins Archiv schreiben oder daraus lesen
archiviere <- function(df,a_directory = "daten/stimmbezirke") {
if (!dir.exists(a_directory)) {
dir.create(a_directory)
}
write_csv(df,
paste0(a_directory,"/",
# Zeitstempel isolieren und alle Doppelpunkte
# durch Bindestriche ersetzen
str_replace_all(df %>% pull(zeitstempel) %>% last(),
"\\:","_"),
".csv"))
}
hole_letztes_df <- function(a_directory = "daten/stimmbezirke") {
if (!dir.exists(a_directory)) return(tibble())
neuester_file <- list.files(a_directory, full.names=TRUE) %>%
file.info() %>%
# Legt eine Spalte namens path an
tibble::rownames_to_column(var = "path") %>%
arrange(desc(ctime)) %>%
head(1) %>%
# Pfad wieder rausziehen
pull(path)
if (length(neuester_file)==0) {
# Falls keine Daten archiviert, gibt leeres df zurück
return(tibble())
} else {
return(read_csv(neuester_file))
}
}
#---- Lese-Funktionen ----
lies_gebiet <- function(stand_url = stimmbezirke_url) {
ts <- now()
# Versuch Daten zu lesen - und gib ggf. Warnung oder Fehler zurück
check = tryCatch(
{ stand_df <- read_delim(stand_url,
delim = ";", escape_double = FALSE,
locale = locale(date_names = "de",
decimal_mark = ",",
grouping_mark = "."),
trim_ws = TRUE) %>%
# Spalten umbenennen, Zeitstempel-Spalte einfügen
mutate(zeitstempel=ts) %>%
select(zeitstempel,
nr = `gebiet-nr`,
name = `gebiet-name`,
meldungen_anz = `anz-schnellmeldungen`,
meldungen_max = `max-schnellmeldungen`,
# Ergebniszellen
wahlberechtigt = A,
# Mehr zum Wahlschein hier: https://www.bundeswahlleiter.de/service/glossar/w/wahlscheinvermerk.html
waehler_regulaer = A1,
waehler_wahlschein = A2,
waehler_nv = A3,
stimmen = B,
stimmen_wahlschein = B1,
ungueltig = C,
gueltig = D,
ja = D1,
nein = D2)
},
warning = function(w) {teams_warning(w,title="Feldmann: Datenakquise")},
error = function(e) {teams_warning(e,title="Feldmann: Datenakquise")})
# Spalten umbenennen,
return(stand_df)
}
# Sind die beiden df abgesehen vom Zeitstempel identisch?
# Funktion vergleicht die numerischen Werte - Spalte für Spalte.
vergleiche_stand <- function(alt_df, neu_df) {
neu_sum_df <- alt_df %>% summarize_if(is.numeric,sum,na.rm=T)
alt_sum_df <- neu_df %>% summarize_if(is.numeric,sum,na.rm=T)
# Unterschiedliche Spaltenzahlen? Dann können sie keine von Finns Männern sein.
if (length(neu_sum_df) != length(alt_sum_df)) return(FALSE)
# Differenzen? Dann können sie keine von Finns Männern sein.
return(sum(abs(neu_sum_df - alt_sum_df))==0)
}
#' Liest Stimmbezirke, gibt nach Ortsteil aggregierte Daten zurück
#' (hier: kein Sicherheitscheck)
aggregiere_stadtteile <- function(stimmbezirke_df) {
ortsteile_df <- stimmbezirke_df %>%
left_join(zuordnung_stimmbezirke_df,by=c("nr","name")) %>%
group_by(ortsteilnr) %>%
summarize(zeitstempel = last(zeitstempel),
across(meldungen_anz:nein, ~ sum(.,na.rm = T))) %>%
rename(nr = ortsteilnr) %>%
# Stadtteilnamen, 2018er Ergebnisse, Geokoordinaten dazuholen
left_join(stadtteile_df, by="nr") %>%
# Nach Ortsteil sortieren
arrange(nr) %>%
# Wichtige Daten für bessere Lesbarkeit nach vorn
relocate(zeitstempel,nr,name,lon,lat)
# Sicherheitscheck: Warnen, wenn nicht alle Ortsteile zugeordnet
if (nrow(ortsteile_df) != nrow(stadtteile_df)) teams_warnung("Nicht alle Ortsteile zugeordnet")
if (nrow(zuordnung_stimmbezirke_df) != length(unique(stimmbezirke_df$nr))) teams_warnung("Nicht alle Stimmbezirke zugeordnet")
return(ortsteile_df)
}
lies_stadtteil_direkt <- function(stand_url = ortsteile_url) {
neu_df <- lies_gebiet(stand_url) %>%
# nr bei Ortsteil-Daten leer/ignorieren
select(!nr) %>%
# Stadtteilnr., Geodaten und Feldmann-2018-Daten reinholen:
left_join(stadtteile_df, by=c("name")) %>%
mutate(trend = (meldungen_anz < meldungen_max),
quorum_erreicht = (ja >= (wahlberechtigt * 0.3)))
return(neu_df)
}
library(readr)
library(lubridate)
library(tidyr)
library(stringr)
library(dplyr)
library(teamr)
#' messaging.R
#'
#' Kommunikation mit Teams
#'
#' Webhook wird als URL im Environment gespeichert. Wenn nicht dort, dann
# Webhook schon im Environment?
if (Sys.getenv("WEBHOOK_REFERENDUM") == "") {
t_txt <- read_file("../key/webhook_referendum.key")
Sys.setenv(WEBHOOK_REFERENDUM = t_txt)
}
teams_meldung <- function(...,title="Feldmann-Update") {
cc <- teamr::connector_card$new(hookurl = t_txt)
cc$title(paste0(title," - ",lubridate::with_tz(lubridate::now(),
"Europe/Berlin")))
alert_str <- paste0(...)
cc$text(alert_str)
cc$print()
cc$send()
}
teams_error <- function(...) {
alert_str <- paste0(...)
teams_meldung(title="Feldmann: FEHLER: ", ...)
stop(alert_str)
}
teams_warning <- function(...) {
alert_str <- paste0(...)
teams_meldung("Feldmann: WARNUNG: ",...)
warning(alert_str)
}
library(pacman)
# Laden und ggf. installieren
p_load(this.path)
p_load(readr)
p_load(lubridate)
p_load(tidyr)
p_load(stringr)
p_load(dplyr)
p_load(DatawRappr)
rm(list=ls())
# Aktuelles Verzeichnis als workdir
setwd(this.path::this.dir())
# Aus dem R-Verzeichnis eine Ebene rauf
setwd("..")
source("R/messaging.R")
source("R/lies_aktuellen_stand.R")
source("R/aktualisiere_karten.R")
source("R/generiere_balken.R")
#----aktualisiere_fom() ----
# fom ist das "Feldmann-o-meter", die zentrale Grafik mit dem Stand der Auszählung.
aktualisiere_fom <- function(wl_url = stimmbezirke_url) {
# Einlesen: Feldmann-o-meter-Daten so far.
# Wenn die Daten noch nicht existieren, generiere ein leeres df.
if(file.exists("daten/fom_df.rds")) {
fom_df <- readRDS("daten/fom_df.rds")
} else {
# Leeres df mit einer Zeile
fom_df <- tibble(zeitstempel = as_datetime(startdatum),
meldungen_anz = 0,
meldungen_max = 575,
# Ergebniszellen
wahlberechtigt = 0,
# Mehr zum Wahlschein hier: https://www.bundeswahlleiter.de/service/glossar/w/wahlscheinvermerk.html
waehler_regulaer = 0,
waehler_wahlschein = 0,
waehler_nv = 0,
stimmen = 0,
stimmen_wahlschein = 0,
ungueltig = 0,
gueltig = 0,
ja = 0,
nein = 0)
# SAVE kann man sich schenken; df ist schneller neu erzeugt
# save(feldmann_df,"daten/feldmann_df.rda")
}
# Daten zur Sicherheit sortieren, dann die letzte Zeile rausziehen
letzte_fom_df <- fom_df %>%
arrange(zeitstempel) %>%
tail(1)
# Neue Daten holen (mit Fehlerbehandlung)
stimmbezirke_df <- lies_gebiet(wl_url)
neue_fom_df <- stimmbezirke_df %>%
# Namen raus
select(-name,-nr) %>%
# Daten aufsummieren
summarize(zeitstempel = last(zeitstempel),
across(2:ncol(.), ~ sum(.,na.rm=T)))
# Alte und neue Daten identisch? Dann brich ab.
if (vergleiche_stand(letzte_fom_df,neue_fom_df)) {
return(FALSE)
} else {
# Archiviere die Rohdaten
archiviere(stimmbezirke_df,"daten/stimmbezirke/")
# Ergänze das fom_df um die neuen Daten und sichere es
fom_df <- fom_df %>% bind_rows(neue_fom_df)
saveRDS(fom_df,"daten/fom_df.rds")
# Bilde das Dataframe
# Sende die Daten an Datawrapper und aktualisiere
fom_dw_df <- fom_df %>%
mutate(ausgezählt = meldungen_anz / meldungen_max *100) %>%
mutate(prozent30 = NA) %>%
mutate(quorum = ja / wahlberechtigt * 100) %>%
select(ausgezählt, wahlberechtigt, ungueltig, ja, nein, quorum, prozent30) %>%
# Noch den Endpunkt der 30-Prozent-Linie
bind_rows(tibble(ausgezählt = 100, prozent30 = ffm_waehler * 0.3))
dw_data_to_chart(fom_dw_df,fom_id)
# Parameter setzen
alles_ausgezählt <- (neue_fom_df$meldungen_max == neue_fom_df$meldungen_anz)
if (neue_fom_df$meldungen_anz == 0) {
quorum = 0
feldmann_str <- "Es liegen noch keine Auszählungsdaten des Bürgerentscheids vor."
} else {
quorum <- (neue_fom_df$ja / neue_fom_df$wahlberechtigt * 100)
if (quorum >= 30) {
if (alles_ausgezählt ) {
feldmann_str <- "Peter Feldmann ist als OB abgewählt."
} else {
feldmann_str <- "Nach dem derzeitigen Auszählungsstand wäre Peter Feldmann als OB abgewählt."
}
} else {
if (alles_ausgezählt ) {
feldmann_str <- "Peter Feldmann bleibt OB von Frankfurt."
} else {
feldmann_str <- "Nach dem derzeitigen Auszählungsstand bliebe Peter Feldmann OB von Frankfurt."
}
}
}
# Breite des Balkens: Wenn das Quorum erreicht ist, hat er die volle Breite,
# wenn nicht, einen Anteil von 30%, um die Entfernung von der Markierung zu zeigen
# Jetzt die Beschreibungstexte mit den Fake-Balkengrafiken generieren
beschreibung_str <- paste0(
"Die Abwahl ist beschlossen, wenn mindestens 30 Prozent aller Wahlberechtigten mit &quot;Ja&quot; stimmen.<br/><br>",
"<b style='font-weight:700;font-size:120%;'>",
# Erste dynamisch angepasste Textstelle: Bleibt Feldmann?
feldmann_str,
"</b><br/><br>",
generiere_balken(wb = neue_fom_df$wahlberechtigt,
ja = neue_fom_df$ja,
nein = neue_fom_df$nein,
auszählung_beendet = alles_ausgezählt))
annotate_str <- generiere_auszählungsbalken(
ausgezählt = floor(neue_fom_df$wahlberechtigt / ffm_waehler * 100),
anz = neue_fom_df$meldungen_anz,
max = neue_fom_df$meldungen_max,
ts = neue_fom_df$zeitstempel)
briefwahl_anz <- stimmbezirke_df %>% filter(str_detect(nr,"^9")) %>%
pull(meldungen_anz) %>% sum()
briefwahl_max <- stimmbezirke_df %>% filter(str_detect(nr,"^9")) %>%
nrow()
annotate_str <- paste0("<strong>Derzeit sind ",
briefwahl_anz,
" von ",
briefwahl_max,
" Briefwahl-Stimmbezirken ausgezählt.</strong><br/><br/>",
annotate_str)
dw_edit_chart(fom_id,intro = beschreibung_str,annotate = annotate_str)
dw_publish_chart(fom_id)
return(TRUE)
}
}
#---- MAIN ----
# Ruft aktualisiere_fom() auf
# (die dann wieder aktualisiere_karten() aufruft)
check = tryCatch(
{
neue_daten <- aktualisiere_fom(stimmbezirke_url)
},
warning = function(w) {teams_warning(w,title="Feldmann: fom")},
error = function(e) {teams_warning(e,title="Feldmann: fom")})
# Neue Daten? Dann aktualisiere die Karten
if (neue_daten) {
check = tryCatch(
{
neue_daten <- aktualisiere_karten(stimmbezirke_url)
},
warning = function(w) {teams_warning(w,title="Feldmann: Karten")},
error = function(e) {teams_warning(e,title="Feldmann: Karten")})
if (neue_daten) {
# Alles OK, letzte Daten nochmal holen und ausgeben
fom_df <- readRDS("daten/fom_df.rds") %>%
arrange(zeitstempel) %>%
tail(1)
if(fom_df$meldungen_anz > 0) {
stimmbezirke_df <- lies_gebiet(stimmbezirke_url)
briefwahl_anz <- stimmbezirke_df %>% filter(str_detect(nr,"^9")) %>%
pull(meldungen_anz) %>% sum()
briefwahl_max <- stimmbezirke_df %>% filter(str_detect(nr,"^9")) %>%
nrow()
fom_update_str <- paste0(
"<strong>Update OK</strong><br/><br/>",
fom_df$meldungen_anz,
" von ",
fom_df$meldungen_max," Stimmbezirke ausgezählt.<br> ",
"Derzeit sind ",
briefwahl_anz,
" von ",
briefwahl_max,
" Briefwahl-Stimmbezirken ausgezählt.<br/>",
"<ul><li><strong>Quorum zur Abwahl ist derzeit",
ifelse(fom_df$ja / fom_df$wahlberechtigt < 0.3, " nicht ", " "),
"erreicht</strong></li>",
"<li><strong>Anteil der Ja-Stimmen an den Wahlberechtigten: ",
format(fom_df$ja / fom_df$wahlberechtigt * 100,decimal.mark=",",big.mark=".",nsmall=1, digits=3),"%",
"</li><li>Ja-Stimmen: ",
format(fom_df$ja,decimal.mark=",",big.mark="."),
"</li><li>Nein-Stimmen: ",
format(fom_df$nein,decimal.mark=",",big.mark="."),
"</li><li>Verhältnis Ja:Nein: ",
format(fom_df$ja / (fom_df$ja + fom_df$nein) * 100,decimal.mark=",",big.mark=".",nsmall=1, digits=3),"% : ",
format(fom_df$nein / (fom_df$ja + fom_df$nein) *100,decimal.mark=",",big.mark=".",nsmall=1, digits=3),"%</li></ul>"
)
teams_meldung(fom_update_str,title="Feldmann-Referendum")
}
} else {
teams_warning("Neue Stimmbezirk-Daten, aber keine neuen Ortsdaten?")
}
}
# Auch hier TRUE zurückbekommen;; alles OK?
\ No newline at end of file
# obwahlen
Code, um die Ergebnisse hessischer Bürgermeisterwahlen abzubilden
# obwahlen PRE
**DIES IST IM AUGENBLICK NUR EINE NOCH NICHT ANGEPASSTE KOPIE DES REFERENDUMS-CODES** - bitte nicht nutzen und wundern! Anpassung spätestens zur [1. Runde der OB-Wahl in Frankfurt am 5. März 2023](https://frankfurt.de/aktuelle-meldung/meldungen/direktwahl-oberbuergermeisterin-oberbuergermeister-frankfurt/).
R-Code, um den Auszählungsstand hessischer Bürgermeisterwahlen in Echtzeit abzurufen und mit Datawrapper darzustellen
## Ordnerstruktur
- **R** enthält den Code
- **index** enthält Index-, Konfigurations-, und Template-Dateien
- **daten** wird vom Code beschrieben und enthält den aktuellen Datenstand.
## Daten aufarbeiten
### Ziele
Folgende Grafiken wären denkbar:
* Balkengrafik Ergebnis nach derzeitigem Auszählungsstand mit "Fortschrittsbalken"
* Choropleth Stadtteil-Sieger
* Choropleth Ergebnis nach Kandidat
* Choropleth Wahlbeteiligung
* Choropleth Briefwahl
* Tabelle nach Stadtteil
* Tabelle nach Kandidaten (Erste drei? fünf?)
### Konfiguration
- Konfigurationsdatei ```index/config.csv``` mit Link, Starttermin, Datawrapper-Zielen; Anzahl der eingegangenen Briefwahlstimmen
- ```index/index.rda``` mit Tabellen Zuordnung Stimmbezirk->Wahllokal und Stadtteilen
### Aufarbeitung
- Daten nach Stimmbezirk abfragen
- Zuordnung Stimmen zu Kandidaten, Umrechnung Prozente gültige Stimmen
Aggregation auf Stadtteilebene
- Zuordnung Stimmbezirk->Stadtteil
- Prozentanteile je Kandidat, Wahlbeteiligung
Aggregation auf Stadtebene
- Prozentanteile je Kandidat, Gewinner
- Fortschrittsbalken ausgezählte Wahllokale
- Fortschrittsbalken ausgezählte Stimmen (mit akt. Briefwahlstimmendaten)
## Struktur des Codes
### Hauptroutinen
- **update_all.R** ist das Skript für den CRON-Job. Es pollt nach Daten, ruft die Abruf-, Aggregations- und Auswertungsfunktionen auf und gibt Meldungen aus.
- **lies_aktuellen_stand.R** enthält Funktionen, die die Daten lesen, aggregieren und archivieren
- **aktualisiere_karten.R** enthält die Funktionen zur Datenausgabe
- **messaging.R** enthält Funktionen, die Teams-Updates und -Fehlermeldungen generieren
### Hilfsfunktionen
- **generiere_testdaten.R** ist ein Skript, das zufällige, aber plausible CSV-Daten auf Stimmbezirks-Ebene zum Testen generiert
name,value,comment
stimmbezirke_url,https://votemanager-ffm.ekom21cdn.de/2022-11-06/06412000/praesentation/Open-Data-06412000-Buergerentscheid-zur-Abwahl-des-Oberbuergermeisters-der-Stadt-Frankfurt-am-Main_-Herrn-Peter-Feldmann-Stimmbezirk.csv?ts=1667662273015,URL Daten-CSV Stimmbezirke
ffm_waehler,508182,Wahlamt
fom_id,bIm87,Datawrapper-ID Feldmann-o-meter
choropleth_id,UwKOO,Datawrapper-ID Stadtteile Choropleth-Karte
symbol_id,RWqrf,Datawrapper-ID Stadtteile Symbole (absolute Stimmen)
tabelle_id,hLqMi,Datawrapper-ID Tabelle Stadtteile
startdatum,2022-11-06 18:00:00 CET,Beginn der Auszählung
nr,name,lon,lat,wahlberechtigt_2018,waehler_2018,gueltig_2018,feldmann_2018
1,Altstadt,8.682385346400634,50.11059669873516,2772,1035,1030,427
2,Innenstadt,8.682664888207869,50.113790989177375,4343,1074,1066,435
4,Westend-Süd,8.6594393465439925,50.11682467903111,13376,5835,5814,1814
5,Westend-Nord,8.666488952498467,50.128769620533795,6887,2761,2751,1064
6,Nordend-West,8.684596043386934,50.13022858244322,22988,10779,10743,4368
7,Nordend-Ost,8.69761974358955,50.127318654892264,17390,7852,7817,3578
8,Ostend,8.719218276147204,50.11554639352114,20946,8411,8358,3873
9,Bornheim,8.712407551447747,50.13090801018288,22232,9682,9633,4954
10,Gutleut- und Bahnhofsviertel,8.652137942960298,50.099479845695974,6802,2113,2103,831
11,Gallus,8.636377745265355,50.10300477630784,23958,6529,6488,2926
12,Bockenheim,8.632922516089874,50.12128753657858,27090,10377,10332,4546
13,Sachsenhausen-Nord,8.684579993638577,50.10051804775371,23441,9940,9897,4128
14,Sachsenhausen-Süd und Flughafen,8.629663957345496,50.0607635296547,20710,8739,8700,3702
16,Oberrad,8.727138168461476,50.09922899999497,9206,3109,3093,1491
17,Niederrad,8.636199605275262,50.081631798202295,16799,5412,5366,2712
18,Schwanheim,8.572652070944704,50.081760019105545,13936,5261,5217,2524
19,Griesheim,8.600109548586545,50.09781734654457,14910,3670,3632,1921
20,Rödelheim,8.603076601631098,50.127692431637506,12446,4518,4487,2108
21,Hausen,8.626134516198546,50.13524298077671,4518,1814,1796,889
22,Praunheim,8.61444644716483,50.14547905112678,11093,4365,4337,2109
24,Heddernheim,8.64020132453368,50.158128239125205,11867,4579,4546,2385
25,Niederursel,8.616911198776547,50.16683966510584,10458,3843,3818,1797
26,Ginnheim,8.648134546192246,50.14388748058928,11185,4310,4285,2101
27,Dornbusch,8.670541998003081,50.14434313041997,13527,6140,6102,2671
28,Eschersheim,8.659950213724542,50.16002839395001,11166,5005,4982,2159
29,Eckenheim,8.683795236784233,50.148564823086005,9638,3457,3425,1764
30,Preungesheim,8.697198159142667,50.15544843144313,10222,3983,3965,2025
31,Bonames,8.665887880254154,50.18258113675648,4467,1566,1549,862
32,Berkersheim,8.702941786636124,50.17015956481773,2607,1137,1129,515
33,Riederwald,8.73274589886058,50.12667040584185,3209,1070,1063,669
34,Seckbach,8.726644066440096,50.147246840458955,7419,2926,2909,1381
35,Fechenheim,8.762275115113775,50.12551773891441,10381,2571,2551,1475
36,Höchst,8.539657322936813,50.098523172532,9859,2527,2506,1251
37,Nied,8.57676379509509,50.103479453362766,12659,3730,3708,1975
38,Sindlingen,8.51273746688725,50.07800492013246,5763,1768,1748,1011
39,Zeilsheim,8.495768400332896,50.097784690964886,8012,2328,2299,1199
40,Unterliederbach,8.525490184772172,50.10992510336304,10485,3201,3176,1533
41,Sossenheim,8.574019745075416,50.12010605434964,10126,2684,2652,1270
42,Nieder-Erlenbach,8.709219115856458,50.20871646737095,3544,1808,1796,665
43,Kalbach-Riedberg,8.639008245521376,50.1846309062546,12409,5359,5333,2349
44,Harheim,8.689844680792895,50.18583895746724,3548,1846,1836,601
45,Nieder-Eschbach,8.668094243977997,50.20106152063871,8041,2979,2950,1204
46,Bergen-Enkheim,8.766772308170399,50.15913246211432,13431,5774,5742,2583
47,Frankfurter Berg,8.673427563622,50.169778678198924,5409,2049,2030,978
"nr","name","ortsteilnr"
"01001","010-01",1
"01002","010-02",1
"04001","040-01",2
"07001","070-01",2
"08001","080-01",2
"09001","090-01",10
"10001","100-01",4
"10002","100-02",4
"11001","110-01",4
"11002","110-02",4
"12001","120-01",6
"12002","120-02",6
"12003","120-03",6
"12004","120-04",6
"13001","130-01",7
"13002","130-02",7
"13003","130-03",7
"14001","140-01",8
"14002","140-02",8
"14003","140-03",8
"14004","140-04",8
"14005","140-05",8
"15101","151-01",10
"15102","151-02",10
"15103","151-03",10
"15104","151-04",10
"15301","153-01",11
"15302","153-02",11
"15401","154-01",11
"15402","154-02",11
"16101","161-01",11
"16102","161-02",11
"16103","161-03",11
"16104","161-04",11
"16201","162-01",11
"16202","162-02",11
"16203","162-03",11
"16204","162-04",11
"16205","162-05",11
"16301","163-01",12
"16302","163-02",12
"16303","163-03",12
"16401","164-01",11
"16501","165-01",11
"16502","165-02",11
"16503","165-03",11
"16504","165-04",11
"17001","170-01",4
"17002","170-02",4
"17003","170-03",4
"18001","180-01",4
"18002","180-02",4
"18003","180-03",4
"19101","191-01",5
"19102","191-02",5
"19103","191-03",5
"19201","192-01",5
"19202","192-02",5
"20101","201-01",6
"20102","201-02",6
"20201","202-01",6
"20202","202-02",6
"20301","203-01",6
"20302","203-02",6
"20303","203-03",6
"20304","203-04",6
"21101","211-01",6
"21102","211-02",6
"21103","211-03",6
"21201","212-01",6
"21202","212-02",6
"21203","212-03",6
"21301","213-01",6
"22101","221-01",7
"22102","221-02",7
"22103","221-03",7
"22201","222-01",7
"22202","222-02",7
"22203","222-03",7
"22204","222-04",7
"23001","230-01",7
"23002","230-02",7
"23003","230-03",7
"24001","240-01",9
"24002","240-02",9
"25101","251-01",8
"25102","251-02",8
"25103","251-03",8
"25104","251-04",8
"25201","252-01",8
"25202","252-02",8
"25203","252-03",8
"25204","252-04",8
"25205","252-05",8
"26101","261-01",8
"26102","261-02",8
"26103","261-03",8
"26201","262-01",33
"26202","262-02",33
"27101","271-01",9
"27102","271-02",9
"27201","272-01",9
"27202","272-02",9
"27203","272-03",9
"27204","272-04",9
"27205","272-05",9
"28101","281-01",9
"28102","281-02",9
"28103","281-03",9
"28201","282-01",9
"28202","282-02",9
"28203","282-03",9
"29001","290-01",9
"29002","290-02",9
"30001","300-01",13
"30002","300-02",13
"32101","321-01",13
"32102","321-02",13
"32103","321-03",13
"32201","322-01",13
"32202","322-02",13
"32203","322-03",13
"32204","322-04",13
"32205","322-05",13
"32301","323-01",14
"32302","323-02",14
"32303","323-03",14
"32304","323-04",14
"32305","323-05",14
"32306","323-06",14
"32401","324-01",13
"32402","324-02",13
"32403","324-03",13
"32404","324-04",13
"32601","326-01",14
"32602","326-02",14
"32603","326-03",14
"33101","331-01",13
"33102","331-02",13
"33103","331-03",13
"33201","332-01",14
"33202","332-02",14
"33203","332-03",14
"33204","332-04",14
"33205","332-05",14
"33206","332-06",14
"34101","341-01",12
"34102","341-02",12
"34103","341-03",12
"34201","342-01",12
"34202","342-02",12
"34301","343-01",12
"34401","344-01",12
"35001","350-01",12
"35002","350-02",12
"35003","350-03",12
"35004","350-04",12
"36101","361-01",12
"36102","361-02",12
"36103","361-03",12
"36201","362-01",12
"36202","362-02",12
"36203","362-03",12
"36204","362-04",12
"37101","371-01",17
"37102","371-02",17
"37103","371-03",17
"37104","371-04",17
"37105","371-05",17
"37106","371-06",17
"37201","372-01",17
"37202","372-02",17
"37203","372-03",17
"37204","372-04",17
"37205","372-05",17
"37206","372-06",17
"38001","380-01",16
"38002","380-02",16
"38003","380-03",16
"38004","380-04",16
"38005","380-05",16
"38006","380-06",16
"39001","390-01",34
"39002","390-02",34
"39003","390-03",34
"39004","390-04",34
"39005","390-05",34
"39006","390-06",34
"39007","390-07",34
"40101","401-01",20
"40102","401-02",20
"40103","401-03",20
"40104","401-04",20
"40105","401-05",20
"40201","402-01",20
"40202","402-02",20
"40203","402-03",20
"40204","402-04",20
"41001","410-01",21
"41002","410-02",21
"41003","410-03",21
"42201","422-01",22
"42202","422-02",22
"42203","422-03",22
"42301","423-01",22
"42302","423-02",22
"42401","424-01",22
"42501","425-01",22
"42601","426-01",22
"42602","426-02",22
"43101","431-01",24
"43102","431-02",24
"43103","431-03",24
"43104","431-04",24
"43105","431-05",24
"43201","432-01",24
"43202","432-02",24
"43203","432-03",24
"43204","432-04",24
"44101","441-01",26
"44102","441-02",26
"44103","441-03",26
"44104","441-04",26
"44105","441-05",26
"44106","441-06",26
"44107","441-07",26
"44108","441-08",26
"44201","442-01",27
"44202","442-02",27
"44203","442-03",27
"44204","442-04",27
"45101","451-01",28
"45102","451-02",28
"45103","451-03",28
"45104","451-04",28
"45201","452-01",28
"45202","452-02",28
"45203","452-03",28
"45204","452-04",28
"46101","461-01",29
"46102","461-02",29
"46103","461-03",29
"46104","461-04",29
"46105","461-05",29
"46106","461-06",29
"46107","461-07",29
"46201","462-01",27
"46202","462-02",27
"46203","462-03",27
"46204","462-04",27
"46205","462-05",27
"46206","462-06",27
"46301","463-01",27
"46302","463-02",27
"47001","470-01",30
"47002","470-02",30
"47003","470-03",30
"47004","470-04",30
"47005","470-05",30
"47006","470-06",30
"47007","470-07",30
"48101","481-01",25
"48102","481-02",25
"48103","481-03",25
"48201","482-01",25
"48202","482-02",25
"48203","482-03",25
"48301","483-01",25
"49101","491-01",31
"49102","491-02",31
"49103","491-03",31
"49201","492-01",47
"49202","492-02",47
"49203","492-03",47
"49204","492-04",47
"50001","500-01",32
"50002","500-02",32
"51001","510-01",35
"51002","510-02",35
"51003","510-03",35
"51004","510-04",35
"52001","520-01",35
"52002","520-02",35
"52003","520-03",35
"53101","531-01",18
"53102","531-02",18
"53103","531-03",18
"53104","531-04",18
"53105","531-05",18
"53201","532-01",18
"53202","532-02",18
"53203","532-03",18
"53204","532-04",18
"53205","532-05",18
"53206","532-06",18
"54101","541-01",19
"54102","541-02",19
"54201","542-01",19
"54202","542-02",19
"54203","542-03",19
"55101","551-01",19
"55102","551-02",19
"55201","552-01",19
"55202","552-02",19
"55203","552-03",19
"56101","561-01",37
"56102","561-02",37
"56103","561-03",37
"56104","561-04",37
"56105","561-05",37
"56201","562-01",37
"56202","562-02",37
"56203","562-03",37
"56204","562-04",37
"57001","570-01",36
"57002","570-02",36
"57003","570-03",36
"58001","580-01",36
"58002","580-02",36
"59101","591-01",36
"59102","591-02",36
"60101","601-01",38
"60102","601-02",38
"60201","602-01",38
"60202","602-02",38
"60401","604-01",39
"61101","611-01",39
"61102","611-02",39
"61201","612-01",39
"61202","612-02",39
"62101","621-01",40
"62102","621-02",40
"62103","621-03",40
"62104","621-04",40
"62201","622-01",40
"62202","622-02",40
"62203","622-03",40
"63101","631-01",41
"63102","631-02",41
"63103","631-03",41
"63104","631-04",41
"63201","632-01",41
"63202","632-02",41
"63203","632-03",41
"64001","640-01",42
"64002","640-02",42
"64003","640-03",42
"65001","650-01",43
"65002","650-02",43
"65003","650-03",43
"65101","651-01",43
"65102","651-02",43
"65103","651-03",43
"65104","651-04",43
"65105","651-05",43
"65106","651-06",43
"65107","651-07",43
"66001","660-01",44
"66002","660-02",44
"66003","660-03",44
"67001","670-01",45
"67002","670-02",45
"67003","670-03",45
"67004","670-04",45
"67005","670-05",45
"67006","670-06",45
"68001","680-01",46
"68002","680-02",46
"68003","680-03",46
"68004","680-04",46
"68005","680-05",46
"68006","680-06",46
"68007","680-07",46
"68008","680-08",46
"68009","680-09",46
"68010","680-10",46
90101,"901-01",1
90201,"902-01",2
90202,"902-02",2
90401,"904-01",4
90402,"904-02",4
90403,"904-03",4
90404,"904-04",4
90405,"904-05",4
90501,"905-01",5
90502,"905-02",5
90503,"905-03",5
90601,"906-01",6
90602,"906-02",6
90603,"906-03",6
90604,"906-04",6
90605,"906-05",6
90606,"906-06",6
90607,"906-07",6
90608,"906-08",6
90609,"906-09",6
90701,"907-01",7
90702,"907-02",7
90703,"907-03",7
90704,"907-04",7
90705,"907-05",7
90706,"907-06",7
90707,"907-07",7
90801,"908-01",8
90802,"908-02",8
90803,"908-03",8
90804,"908-04",8
90805,"908-05",8
90806,"908-06",8
90807,"908-07",8
90808,"908-08",8
90809,"908-09",8
90901,"909-01",9
90902,"909-02",9
90903,"909-03",9
90904,"909-04",9
90905,"909-05",9
90906,"909-06",9
90907,"909-07",9
90908,"909-08",9
90909,"909-09",9
91001,"910-01",10
91002,"910-02",10
91003,"910-03",10
91101,"911-01",11
91102,"911-02",11
91103,"911-03",11
91104,"911-04",11
91105,"911-05",11
91106,"911-06",11
91107,"911-07",11
91108,"911-08",11
91201,"912-01",12
91202,"912-02",12
91203,"912-03",12
91204,"912-04",12
91205,"912-05",12
91206,"912-06",12
91207,"912-07",12
91208,"912-08",12
91209,"912-09",12
91210,"912-10",12
91211,"912-11",12
91301,"913-01",13
91302,"913-02",13
91303,"913-03",13
91304,"913-04",13
91305,"913-05",13
91306,"913-06",13
91307,"913-07",13
91308,"913-08",13
91309,"913-09",13
91310,"913-10",13
91401,"914-01",14
91402,"914-02",14
91403,"914-03",14
91404,"914-04",14
91405,"914-05",14
91406,"914-06",14
91407,"914-07",14
91408,"914-08",14
91409,"914-09",14
91601,"916-01",16
91602,"916-02",16
91603,"916-03",16
91701,"917-01",17
91702,"917-02",17
91703,"917-03",17
91704,"917-04",17
91705,"917-05",17
91706,"917-06",17
91801,"918-01",18
91802,"918-02",18
91803,"918-03",18
91804,"918-04",18
91805,"918-05",18
91806,"918-06",18
91901,"919-01",19
91902,"919-02",19
91903,"919-03",19
91904,"919-04",19
91905,"919-05",19
92001,"920-01",20
92002,"920-02",20
92003,"920-03",20
92004,"920-04",20
92005,"920-05",20
92101,"921-01",21
92102,"921-02",21
92201,"922-01",22
92202,"922-02",22
92203,"922-03",22
92204,"922-04",22
92205,"922-05",22
92401,"924-01",24
92402,"924-02",24
92403,"924-03",24
92404,"924-04",24
92405,"924-05",24
92501,"925-01",25
92502,"925-02",25
92503,"925-03",25
92504,"925-04",25
92601,"926-01",26
92602,"926-02",26
92603,"926-03",26
92604,"926-04",26
92701,"927-01",27
92702,"927-02",27
92703,"927-03",27
92704,"927-04",27
92705,"927-05",27
92706,"927-06",27
92801,"928-01",28
92802,"928-02",28
92803,"928-03",28
92804,"928-04",28
92901,"929-01",29
92902,"929-02",29
92903,"929-03",29
92904,"929-04",29
93001,"930-01",30
93002,"930-02",30
93003,"930-03",30
93004,"930-04",30
93101,"931-01",31
93102,"931-02",31
93201,"932-01",32
93301,"933-01",33
93401,"934-01",34
93402,"934-02",34
93403,"934-03",34
93501,"935-01",35
93502,"935-02",35
93503,"935-03",35
93504,"935-04",35
93601,"936-01",36
93602,"936-02",36
93603,"936-03",36
93701,"937-01",37
93702,"937-02",37
93703,"937-03",37
93704,"937-04",37
93801,"938-01",38
93802,"938-02",38
93901,"939-01",39
93902,"939-02",39
93903,"939-03",39
94001,"940-01",40
94002,"940-02",40
94003,"940-03",40
94004,"940-04",40
94101,"941-01",41
94102,"941-02",41
94103,"941-03",41
94104,"941-04",41
94201,"942-01",42
94202,"942-02",42
94301,"943-01",43
94302,"943-02",43
94303,"943-03",43
94304,"943-04",43
94305,"943-05",43
94401,"944-01",44
94402,"944-02",44
94501,"945-01",45
94502,"945-02",45
94503,"945-03",45
94601,"946-01",46
94602,"946-02",46
94603,"946-03",46
94604,"946-04",46
94605,"946-05",46
94701,"947-01",47
94702,"947-02",47
Version: 1.0
RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8
RnwWeave: Sweave
LaTeX: pdfLaTeX
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment