Det har gått mer än en vecka sedan valet och resultatdata har nu börjat publiceras på valmyndigheten.se. I det här inlägget tänkte jag visa hur vi kan använda swemaps2
för att analysera valresultatet på kommunal nivå.
Till att börja med kan vi ladda ner valresutlatet som finns i en Excel på valmyndigheten.se
library (readxl)
library (tidyverse)
download.file ("https://www.val.se/download/18.14c1f613181ed0043d567ae/1663009000443/valresultat-riksdagen-preliminar-jamforande-statistik.xlsx" ,
destfile = "data/valresultat-riksdagen-preliminar-jamforande-statistik.xlsx" )
valresultat <- read_excel ("data/valresultat-riksdagen-preliminar-jamforande-statistik.xlsx" , sheet = 3 ) |>
janitor:: clean_names ()
valresultat
# A tibble: 4,350 × 9
riksdagsvalkrets kommu…¹ parti roste…² andel…³ diff diff_a…⁴ roste…⁵ andel…⁶
<chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Västra Götaland… Ale Mode… 3451 0.182 -188 -0.00588 3639 0.188
2 Västra Götaland… Ale Cent… 994 0.0525 -364 -0.0177 1358 0.0703
3 Västra Götaland… Ale Libe… 631 0.0333 -283 -0.0139 914 0.0473
4 Västra Götaland… Ale Kris… 1065 0.0563 -147 -0.00642 1212 0.0627
5 Västra Götaland… Ale Arbe… 5687 0.301 286 0.0211 5401 0.279
6 Västra Götaland… Ale Väns… 1259 0.0665 -219 -0.00993 1478 0.0765
7 Västra Götaland… Ale Milj… 664 0.0351 -95 -0.00417 759 0.0393
8 Västra Götaland… Ale Sver… 4864 0.257 563 0.0346 4301 0.223
9 Västra Götaland… Ale Övri… 307 0.0162 39 0.00236 268 0.0139
10 Västra Götaland… Ale Gilt… 18922 1 -408 NA 19330 1
# … with 4,340 more rows, and abbreviated variable names ¹kommunnamn,
# ²roster_2022, ³andel_2022, ⁴diff_andel, ⁵roster_2018, ⁶andel_2018
Vi ser att det i kolumnen parti
finns en del värden som inte är partier, ex. Röstberättigande
.
valresultat |>
group_by (parti) |>
summarise (roster_2022 = sum (roster_2022)) |>
arrange (desc (roster_2022))
# A tibble: 15 × 2
parti roster_2022
<chr> <dbl>
1 Röstberättigade 7772120
2 Valdeltagande vallokaler 6320963
3 Giltiga Röster 6227229
4 Arbetarepartiet-Socialdemokraterna 1897965
5 Sverigedemokraterna 1282352
6 Moderaterna 1187350
7 Centerpartiet 417851
8 Vänsterpartiet 414604
9 Kristdemokraterna 333327
10 Miljöpartiet de gröna 314579
11 Liberalerna (tidigare Folkpartiet) 286503
12 Övriga anmälda partier 92698
13 Ogiltiga röster - blanka 59218
14 Ogiltiga röster - övriga 31137
15 Ogiltiga röster - inte anmälda partier 3379
Vi är bara intresserade av de stora riksdagspartierna, så vi filtrerar bort värden som inte är partier.
library (stringr)
valresultat_partier <- valresultat |>
filter (! (parti %in% c ("Röstberättigade" ,
"Valdeltagande vallokaler" ,
"Giltiga Röster" )) &
! str_detect (parti, "Ogiltiga" ))
För att kunna redovisa resultatet på en karta behöver vi knyta det till ett geografiskt objekt. Det kan vi enkelt göra genom att joina vår data.frame med municipality
som är ett dataset i swemaps2
.
library (swemaps2)
valresultat_kommun <- swemaps2:: municipality |>
left_join (
valresultat_partier, by = c ("kn_namn" = "kommunnamn" )
)
valresultat_kommun
Simple feature collection with 2602 features and 12 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 1230810 ymin: 6137234 xmax: 1880916 ymax: 7669583
Projected CRS: RT90 2.5 gon V
# A tibble: 2,602 × 13
kn_kod kn_namn ln_kod ln_namn geometry riksd…¹ parti roste…²
<chr> <chr> <chr> <chr> <MULTIPOLYGON [m]> <chr> <chr> <dbl>
1 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Mode… 5043
2 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Cent… 1461
3 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Libe… 1126
4 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Kris… 1194
5 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Arbe… 7389
6 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Väns… 1805
7 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Milj… 894
8 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Sver… 5205
9 0114 Upplan… 01 Stockh… (((1620218 6599562, 1618… Stockh… Övri… 450
10 0115 Vallen… 01 Stockh… (((1637371 6601120, 1636… Stockh… Mode… 5272
# … with 2,592 more rows, 5 more variables: andel_2022 <dbl>, diff <dbl>,
# diff_andel <dbl>, roster_2018 <dbl>, andel_2018 <dbl>, and abbreviated
# variable names ¹riksdagsvalkrets, ²roster_2022
Jag är intresserad av hur det gått för Moderaterna i Skåne så jag filtrerar ut Skåne och moderaterna.
valresultat_skane <- valresultat_kommun |>
filter (parti == "Moderaterna" & str_detect (tolower (ln_namn), "skåne" ))
Nu har vi valresultat knutet till geografiska objekt och kan visualisera det.
Attaching package: 'scales'
The following object is masked from 'package:purrr':
discard
The following object is masked from 'package:readr':
col_factor
plot_skane <- valresultat_skane |>
ggplot (aes (fill = diff_andel)) +
geom_sf () +
scale_fill_viridis_c (option = "magma" , label = scales:: percent) +
theme_swemap2 ()
plot_skane
För att göra visualiseringen lite mer informativ kan vi skapa en dataframe där vi har de kommuner där Moderaterna tappat mest och där det ökat mest.
top_skane <- valresultat_skane |>
slice_max (diff_andel, n = 3 )
bottom_skane <- valresultat_skane |>
slice_min (diff_andel, n = 3 )
labels_skane <- bind_rows (top_skane, bottom_skane)
För att skapa snygga labels använder jag ggrepel
. Vi ser att Bromölla är den kommun där moderaterna gått framåt. Annars ser de ut att tappa i de flesta kommuner.
library (ggrepel)
plot_skane <- plot_skane +
geom_label_repel (
data = labels_skane,
aes (label = kn_namn, geometry = geometry),
stat = "sf_coordinates" ,
min.segment.length = 0 ,
color = "black" ,
fill = "white"
)
plot_skane
Till sist ändrar jag titel och lite andra parametrar för att få en mer tilltalande visualisering:
plot_skane +
labs (
title = "Förändring andel röster för Moderaterna" ,
subtitle = "2018 till 2022" ,
fill = "Skillnad" ,
caption = "Källa: Valmyndigheten och SCB"
)