Eduskuntavaalit 2023: ehdokkaiden kannatus ja puolueiden kannatuksen aikasarjat kuntatasolla

data analysis
R
election
vaalit2023
eduskuntavaalit2023
avoin data
open data
Tekijä
Julkaistu

2. huhtikuuta 2023

Oikeusministeriön vaalien tulospalvelusta oli ladattavissa ehti puolenyön jälkeen jo alustavan laskennan tulokset aikaisempia vuosia vastaavissa datarakenteissa. Tein tähän yhden kuntatason kartan, jossa kunnan väri kertoo suosituimman puolueen ja siirtämällä osoittimen kunnan päälle näet sekä puolueiden kannatuksen vuodesta 2011 että viiden suosituimman ehdokkaan äänimäärät 2023 vaaleissa.

[/kode]
library(tidyverse)
library(leaflet)
library(htmlwidgets)
library(glue)
library(sf)
if (!file.exists("./2023-vaalit-kunta-aikasarja.RData")){
# 2023
flie <- tempfile()
download.file("https://tulospalvelu.vaalit.fi/EKV-2023/ekv-2023_puo_maa.csv.zip", flie)
tmpdir <- tempdir()
unzip(zipfile = flie, exdir = tmpdir)
dat <- read_csv2(glue("{tmpdir}/ekv-2023_tpat_maa.csv"), col_names = FALSE)
dat23 <- dat %>% 
  filter(grepl("\\*", X5),
         !grepl("\\*", X3)) %>% 
    # äänimäärä ja ehdokasnumero kokonaisluvuiksi
  mutate(X3 = as.integer(X3),
         X35 = as.integer(X35),
         X39 = as.integer(X39),
         X40 = as.integer(X40),
         X41 = as.integer(X41)) %>% 
  # vaalipiirit veks
  filter(!is.na(X3)) %>% 
  # Merkistöenkoodaukset
  mutate(
    X17 = iconv(x = X17, from = "Windows-1252", to = "UTF-8"),
    X11 = iconv(x = X11, from = "Windows-1252", to = "UTF-8"),
    X19 = iconv(x = X19, from = "Windows-1252", to = "UTF-8"),
    X18 = iconv(x = X18, from = "Windows-1252", to = "UTF-8"),
    X16 = iconv(x = X16, from = "Windows-1252", to = "UTF-8"),
    X15 = iconv(x = X15, from = "Windows-1252", to = "UTF-8"),
    X14 = iconv(x = X14, from = "Windows-1252", to = "UTF-8"),
    X12 = iconv(x = X12, from = "Windows-1252", to = "UTF-8")
    ) %>% 
  select(X3,X6,X11,X14,X16,X39,X40,X41) %>% 
  # filter(X14 == "Helsinki") %>% 
  group_by(X3,X14) %>% 
  mutate(osuus = round(X41 / sum(X41) * 100,1)) %>% 
  arrange(desc(osuus)) %>% 
  # slice(1:3) %>% 
  mutate(rank = 1:n()) %>% 
  ungroup() %>% 
  select(X14,rank,X16,osuus)
  # filter(X14 == "Honkajoki") %>% arrange(desc(osuus))
  
  # 2019
flie <- tempfile()
download.file("https://tulospalvelu.vaalit.fi/EKV-2019/ekv-2019_puo_maa.csv.zip", flie)
tmpdir <- tempdir()
unzip(zipfile = flie, exdir = tmpdir)
dat <- read_csv2(glue("{tmpdir}/ekv-2019_tpat_maa.csv"), col_names = FALSE)
dat19 <- dat %>% 
  filter(grepl("\\*", X5),
         !grepl("\\*", X3)) %>% 
    # äänimäärä ja ehdokasnumero kokonaisluvuiksi
  mutate(X3 = as.integer(X3),
         X35 = as.integer(X35),
         X39 = as.integer(X39),
         X40 = as.integer(X40),
         X41 = as.integer(X41)) %>% 
  # vaalipiirit veks
  filter(!is.na(X3)) %>% 
  # Merkistöenkoodaukset
  mutate(
    X17 = iconv(x = X17, from = "Windows-1252", to = "UTF-8"),
    X11 = iconv(x = X11, from = "Windows-1252", to = "UTF-8"),
    X19 = iconv(x = X19, from = "Windows-1252", to = "UTF-8"),
    X18 = iconv(x = X18, from = "Windows-1252", to = "UTF-8"),
    X16 = iconv(x = X16, from = "Windows-1252", to = "UTF-8"),
    X15 = iconv(x = X15, from = "Windows-1252", to = "UTF-8"),
    X14 = iconv(x = X14, from = "Windows-1252", to = "UTF-8"),
    X12 = iconv(x = X12, from = "Windows-1252", to = "UTF-8")
    ) %>% 
  select(X3,X6,X11,X14,X16,X39,X40,X41) %>% 
  # filter(X14 == "Helsinki") %>% 
  group_by(X3,X14) %>% 
  mutate(osuus = round(X41 / sum(X41) * 100,1)) %>% 
  arrange(desc(osuus)) %>% 
  # slice(1:3) %>% 
  mutate(rank = 1:n()) %>% 
  ungroup() %>% 
  select(X14,rank,X16,osuus)
  # filter(X14 == "Honkajoki") %>% arrange(desc(osuus))

# 2015
flie <- tempfile()
download.file("https://tulospalvelu.vaalit.fi/E-2015/e-2015_puo_maa.csv.zip", flie)
tmpdir <- tempdir()
unzip(zipfile = flie, exdir = tmpdir)
# list.files(tmpdir)
dat <- read_csv2(glue("{tmpdir}/e-2015_tpat_maa.csv"), col_names = FALSE)
dat15 <- dat %>% 
  filter(grepl("\\*", X5),
         !grepl("\\*", X3)) %>% 
    # äänimäärä ja ehdokasnumero kokonaisluvuiksi
  mutate(X3 = as.integer(X3),
         X35 = as.integer(X35),
         X39 = as.integer(X39),
         X40 = as.integer(X40),
         X41 = as.integer(X41)) %>% 
  # vaalipiirit veks
  filter(!is.na(X3)) %>% 
  # Merkistöenkoodaukset
  mutate(
    X17 = iconv(x = X17, from = "Windows-1252", to = "UTF-8"),
    X11 = iconv(x = X11, from = "Windows-1252", to = "UTF-8"),
    X19 = iconv(x = X19, from = "Windows-1252", to = "UTF-8"),
    X18 = iconv(x = X18, from = "Windows-1252", to = "UTF-8"),
    X16 = iconv(x = X16, from = "Windows-1252", to = "UTF-8"),
    X15 = iconv(x = X15, from = "Windows-1252", to = "UTF-8"),
    X14 = iconv(x = X14, from = "Windows-1252", to = "UTF-8"),
    X12 = iconv(x = X12, from = "Windows-1252", to = "UTF-8")
    ) %>% 
  select(X3,X6,X11,X14,X16,X39,X40,X41) %>% 
  # filter(X14 == "Helsinki") %>% 
  group_by(X3,X14) %>% 
  mutate(osuus = round(X41 / sum(X41) * 100,1)) %>% 
  arrange(desc(osuus)) %>% 
  # slice(1:3) %>% 
  mutate(rank = 1:n()) %>% 
  ungroup() %>%
  select(X14,rank,X16,osuus)
  # filter(X14 == "Honkajoki") %>% arrange(desc(osuus))

  
# 2011
flie <- tempfile()
download.file("https://tulospalvelu.vaalit.fi/EKV-2011/e-2011_puo_maa.csv.zip", flie)
tmpdir <- tempdir()
unzip(zipfile = flie, exdir = tmpdir)
# list.files(tmpdir)
dat <- read_csv2(glue("{tmpdir}/e-2011_tpat_maa.csv"), col_names = FALSE)
dat11 <- dat %>% 
  filter(grepl("\\*", X5),
         !grepl("\\*", X3)) %>% 
    # äänimäärä ja ehdokasnumero kokonaisluvuiksi
  mutate(X3 = as.integer(X3),
         X35 = as.integer(X35),
         X39 = as.integer(X39),
         X40 = as.integer(X40),
         X41 = as.integer(X41)) %>% 
  # vaalipiirit veks
  filter(!is.na(X3)) %>% 
  # Merkistöenkoodaukset
  mutate(
    X17 = iconv(x = X17, from = "Windows-1252", to = "UTF-8"),
    X11 = iconv(x = X11, from = "Windows-1252", to = "UTF-8"),
    X19 = iconv(x = X19, from = "Windows-1252", to = "UTF-8"),
    X18 = iconv(x = X18, from = "Windows-1252", to = "UTF-8"),
    X16 = iconv(x = X16, from = "Windows-1252", to = "UTF-8"),
    X15 = iconv(x = X15, from = "Windows-1252", to = "UTF-8"),
    X14 = iconv(x = X14, from = "Windows-1252", to = "UTF-8"),
    X12 = iconv(x = X12, from = "Windows-1252", to = "UTF-8")
    ) %>% 
  select(X3,X6,X11,X14,X16,X39,X40,X41) %>% 
  # filter(X14 == "Helsinki") %>% 
  group_by(X3,X14) %>% 
  mutate(osuus = round(X41 / sum(X41) * 100,1)) %>% 
  arrange(desc(osuus)) %>% 
  # slice(1:3) %>% 
  mutate(rank = 1:n()) %>% 
  ungroup() %>%
  select(X14,rank,X16,osuus)


names(dat11) <- c("kunta","rank","puolue","osuus")
names(dat15) <- c("kunta","rank","puolue","osuus")
names(dat19) <- c("kunta","rank","puolue","osuus")
names(dat23) <- c("kunta","rank","puolue","osuus")

dat <- bind_rows(dat11 %>% mutate(vuosi = 2011), 
                 dat15 %>% mutate(vuosi = 2015),
                 dat19 %>% mutate(vuosi = 2019),
                 dat23 %>% mutate(vuosi = 2023))

dat_2 <- dat %>% 
  mutate(pl = case_when(
    puolue == "Vihreä liitto" ~ "VIHR",
    puolue == "Vasemmistoliitto" ~ "VAS",
    puolue == "Suomen Sosialidemokraattinen Puolue" ~ "SDP",
    puolue == "Suomen ruotsalainen kansanpuolue" ~ "RKP",
    puolue == "Suomen Kristillisdemokraatit (KD)" ~ "KD",
    puolue == "Suomen Keskusta" ~ "KESK",
    puolue == "Sininen tulevaisuus" ~ "SIN",
    puolue == "Perussuomalaiset" ~ "PS",
    puolue == "Kansallinen Kokoomus" ~ "KOK",
    puolue == "Liike Nyt" ~ "Liike Nyt",
    puolue == "För Åland, gemensam lista" ~ "FÅ",
    # puolue == "Åländsk samling" ~ "Åländsk samling",
    # puolue == "Åländsk samling gemensam lista" ~ "Åländsk samling gemensam lista",
    # puolue == "Alternativ för Åland - gemensam lista" ~ "Alternativ för Åland - gemensam lista",
    # puolue == "Gemensam lista Alliansen för Åland - samarbete för självstyrelse och utveckling" ~ "Gemensam lista Alliansen för Åland - samarbete för självstyrelse och utveckling",
    # grepl("Jessica", puolue) ~ "Jessica Eckerman",
    # puolue == "Liberalerna på Åland" ~ "Liberalerna på Åland",
    # puolue == "Markus Kuotesaho" ~ "Markus Kuotesaho",
    TRUE ~ "muut"
  )) %>% 
  filter(pl != "muut")

dat_2_r1 <- dat_2 %>% filter(vuosi == 2023, rank == 1) %>% 
  rename(municipality_name_fi = kunta)

# tehdään png-kuvat labeleihin
# fs::dir_create("../../images/png_labs_vaalit2023")
kuntanimet <- unique(dat_2$kunta)
for (i in seq(kuntanimet)){
  print(paste0(i,"/",length(kuntanimet)))
  dat_tmp <- dat_2 %>% filter(kunta == kuntanimet[i])
  
  # että värit menee oikein
  if ("RKP" %in% unique(dat_tmp$pl)){
    dat_tmp <- dat_tmp %>% mutate(pl = factor(pl))
  } else {
    dat_tmp <- bind_rows(dat_tmp,
                         tibble(
                           puolue = "Ruotsalainen kansanpuolue",
                           osuus = 0, 
                           kunta = kuntanimet[i],
                           rank = max(dat_tmp$rank, na.rm = TRUE) + 1,
                           pl = "RKP"
                         )) %>% 
      mutate(pl = factor(pl))
  }
  
  
     #%>% 
    # filter(pl != "muut")
p <- ggplot(data = dat_tmp,
       aes(x = vuosi, y = osuus, color = pl, fill = pl)) + 
    geom_line() +
  geom_point(shape = 21, color = "white", size = 2.5, stroke = 2.7) + 
  ggrepel::geom_label_repel(data = dat_tmp %>% 
              filter(vuosi == 2023), 
            aes(label = pl), #color = "white", 
            family = "Space Mono", 
            size = 3.2, nudge_y = 1, color = "black", label.padding = unit(1, "mm")) +
  scale_color_brewer(palette = "Set1") +
  scale_fill_brewer(palette = "Set1") +
    ggrepel::geom_text_repel(data = dat_tmp, 
            aes(label = glue("{osuus} %")), 
            family = "Space Mono", 
            size = 3.2, nudge_y = -1) +
  hrbrthemes::theme_ipsum_rc(base_size = 10, grid = "XY", plot_title_size = 9) +
  scale_x_continuous(breaks = c(2011, 2015, 2019,2023)) +
  theme(legend.position = "none",
        plot.margin = unit(c(1,1,1,1), "mm"), 
        plot.background = element_rect(fill = "transparent", color = NA),
        panel.background = element_rect(fill = "transparent", color = NA)) +
  labs(x = NULL, y = "kannatus (%)")
# p
ggsave(filename = glue("./png_labs/{kuntanimet[i]}.png"), width = 3.8, height = 2.9, dpi = 100)
}

kunnat <- geofi::get_municipalities(year = 2022) %>% mutate(vuosi = 2023)


dat_kartta_voittaja <- left_join(kunnat, dat_2_r1)


save.image(file = "./2023-vaalit-kunta-aikasarja.RData")
}

library(tidyverse)
library(leaflet)
library(htmlwidgets)
library(glue)
library(sf)

load(file = "./2023-vaalit-kunta-aikasarja.RData")

# download.file("https://tulospalvelu.vaalit.fi/EKV-2023/ekv-2023_ehd_maa.csv.zip", "ekv-2023_ehd_maa.csv.zip")
# unzip(zipfile = "ekv-2023_ehd_maa.csv.zip", exdir = "./")
dat <- read_csv2("ekv-2023_aea_maa.csv", col_names = FALSE)
dat_kunnat <- dat %>% 
  filter(grepl("\\*", X5)) %>% #View()
  # äänimäärä ja ehdokasnumero kokonaisluvuiksi
  mutate(X3 = as.integer(X3),
         X35 = as.integer(X35),
         X15 = as.integer(X15)) %>% 
  # vaalipiirit veks
  filter(!is.na(X3)) %>% 
  # Merkistöenkoodaukset
  mutate(X19 = iconv(x = X19, from = "Windows-1252", to = "UTF-8"),
         X18 = iconv(x = X18, from = "Windows-1252", to = "UTF-8"),
         X16 = iconv(x = X16, from = "Windows-1252", to = "UTF-8"),
         X12 = iconv(x = X12, from = "Windows-1252", to = "UTF-8")) %>%
  # filter(X3 == 924) %>% 
  select(X3,X5,X6,X12,X15,X16,X18,X19,X35)


dat_alue <- dat_kunnat %>%   
  # lasketaan kuntakohtaiset summat
  group_by(X3) %>% 
  mutate(X35_summa = sum(X35, na.rm = TRUE)) %>%
  ungroup() %>% 
  # Lasketaan kullekin uurnalla ja ehdokkaalle ääniosuus
  mutate(osuus = round(X35 / X35_summa*100, 1)) %>% 
  group_by(X3,X16) %>% 
  arrange(desc(osuus)) %>% 
  slice(1:5) %>% 
  mutate(rank = 1:n()) %>% 
  ungroup() %>% 
  mutate(nimi = paste(X18,X19)) %>% 
  select(X3,X16,nimi,X12,X35,rank,osuus) %>% 
  arrange(X3,rank)

# puoluekohtaiset kannatukset
dat_puoluekannatus <-dat_2_r1 %>% select(-vuosi)

dat_alue_voittaja <- dat_alue %>% filter(rank == 1)
dat_alue_top3 <- dat_alue %>% 
  mutate(nimi = glue("<tr><td>{rank}</td><td>{nimi}</td><td>{X12}</td><td>{osuus}%</td><td>{X35}</td></tr>")) %>%
  select(-osuus,-X35,-X12) %>% 
  spread(key = rank, value = nimi) %>% 
  setNames(c("X3","X16","t1","t2","t3","t4","t5"))

# äänestysalueet
# kunnat19 <- readRDS(url("https://gitlab.com/muuankarski/kelagis_data/raw/master/rds/sf19.RDS"))
kunnat19 <- geofi::get_municipalities(year = 2022)
# kunnat19 <- st_transform(x = kunnat19, crs = "+proj=longlat +init=epsg:3067")
# st_transform(muni, "EPSG:4326")

kunnat19$NATCODE <- kunnat19$municipality_code
kunnat19$NAMEFIN <- kunnat19$municipality_name_fi
kunnat19 <- st_transform(kunnat19, "EPSG:4326")

dat_kartta_top3 <- left_join(kunnat19, dat_alue_top3, by = c("NATCODE" = "X3"))
dat_kartta_voittaja <- left_join(kunnat19, dat_alue_voittaja, by = c("NATCODE" = "X3"))
dat_kartta_puolue <- left_join(kunnat19, dat_puoluekannatus)

library(tidyverse)
library(leaflet)
library(htmlwidgets)
library(glue)
library(sf)
pal <- leaflet::colorFactor(palette = "Set1", domain = factor(dat_kartta_puolue$pl))

epsg3067 <- leafletCRS(crsClass = "L.Proj.CRS", code = "EPSG:3067",
  proj4def = "+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs",
  resolutions = 2^(13:-1), # 8192 down to 0.5
  origin = c(0, 0)
)

labels <- sprintf(
  '<div class="card" style="width: auto;">
  <div class="card-body">
    <h5 class="card-title">%s</h5>
    <img src ="png_labs/%s.png">
  <table class="table table-sm">
  <thead>
    <tr>
      <th scope="col">sija</th>
      <th scope="col">nimi</th>
      <th scope="col">puolue</th>
      <th scope="col">kannatus</th>
      <th scope="col">äänet</th>
    </tr>
  </thead>
  <tbody>
  %s
  %s
  %s
  %s
  %s
  </tbody>
</table>
  </div>
</div>',
  dat_kartta_top3$NAMEFIN,
dat_kartta_top3$NAMEFIN,
dat_kartta_top3$t1, 
dat_kartta_top3$t2, 
dat_kartta_top3$t3, 
dat_kartta_top3$t4, 
dat_kartta_top3$t5
) %>% lapply(htmltools::HTML)

# labels <- sprintf('
#     <div class="card" style="width: auto;">
#     <div class="card-body">
#     <h5 class="card-title">%s</h5>
#     <img src ="png_labs/%s.png">
#     </div>
#     </div>',
#   dat_kartta_voittaja$municipality_name_fi,
#   dat_kartta_voittaja$municipality_name_fi
# ) %>% lapply(htmltools::HTML)




leaflet(dat_kartta_puolue, options = leafletOptions(worldCopyJump = F, crs = epsg3067)) %>% 
  # addProviderTiles(provider = providers$CartoDB.Positron) %>% 
  leaflet::setView(lng = 25.25,lat = 61.742, zoom = 4) %>% 
  addPolygons(fillColor = ~pal(factor(pl)),
              color = "white",
              weight = 1,
              opacity = 1,
              dashArray = "3",
              fillOpacity = 0.4,
              highlight = highlightOptions(
                weight = 2,
                color = "#666",
                dashArray = "",
                fillOpacity = 0.4,
                bringToFront = TRUE),
              label = labels,
              labelOptions = labelOptions(opacity = .7,
                                          style = list("font-weight" = "normal",
                                                       "font-family" = "Courier New",
                                                       "padding" = "0px"),
                                          textsize = "12px",
                                          direction = "auto")
  ) %>% 
  addLegend(pal = pal, values = ~pl, opacity = 0.7, title = "Kunnan suosituin puolue",
            position = "bottomright") %>% 
  leaflet.extras::addFullscreenControl()

Uudelleenkäyttö

Viittaus

BibTeX-viittaus:
@online{kainu2023,
  author = {Kainu, Markus},
  title = {Eduskuntavaalit 2023: ehdokkaiden kannatus ja puolueiden
    kannatuksen aikasarjat kuntatasolla},
  date = {2023-04-02},
  url = {https://markuskainu.fi/posts/2023-04-02-eduskuntavaalit-kunta},
  langid = {fi}
}
Viitatkaa tähän teokseen seuraavasti:
Kainu, Markus. 2023. “Eduskuntavaalit 2023: ehdokkaiden kannatus ja puolueiden kannatuksen aikasarjat kuntatasolla.” April 2, 2023. https://markuskainu.fi/posts/2023-04-02-eduskuntavaalit-kunta.