Cara membuat peta pilihan raya di R

Sekiranya anda memetakan hasil pilihan raya, katakanlah, pilihan raya presiden AS berdasarkan negara, adalah masuk akal untuk menunjukkan satu warna merah untuk negeri yang dimenangi oleh Republikan, dan satu warna biru untuk negeri yang dimenangi oleh Demokrat. Itu kerana tidak kira sama ada calon menang dengan tiga ribu undi atau tiga juta: "Pemenang mengambil semua."

Tetapi apabila menganalisis hasil daripada pilihan raya negeri oleh county , atau pilihan raya seluruh bandar oleh presint , perkara-perkara margin. Jumlah keseluruhan yang menentukan pemenang. Sebagai contoh, memenangi "Atlanta" bukan yang perlu anda ketahui ketika melihat keputusan di seluruh negeri untuk gabenor. Anda ingin mengetahui berapa banyak undi yang dimenangi oleh Demokrat , dan membandingkannya dengan kawasan lain. 

Itulah sebabnya saya suka membuat peta yang diberi kod warna oleh pemenang dan dengan intensiti warna yang menunjukkan margin kemenangan. Itu memberitahu anda bidang mana yang menyumbang lebih banyak dan mana yang menyumbang lebih sedikit untuk hasil keseluruhan.

Dalam demo ini, saya akan menggunakan keputusan presiden Pennsylvania 2016. Sekiranya anda ingin mengikuti, muat turun data dan shapefiles geospasial:

memuat turun keputusan pilihan raya Pennsylvania 2016 oleh shapefiles daerah dan daerah data pilihan raya dan shapefile. Sharon Machlis

Saya mula-mula memuatkan beberapa pakej: dplyr, gam, timbangan, htmltools, sf, dan leaflet. Saya akan menggunakan rio untuk mengimport fail CSV data, jadi anda juga menginginkannya di sistem anda.

perpustakaan (dplyr); perpustakaan (gam); perpustakaan (timbangan);

perpustakaan (htmltools); perpustakaan (sf); perpustakaan (risalah)

pa_data <- rio :: import ("pa_2016_presidential.csv")

Import dan persediaan data

Seterusnya, saya menggunakan st_read()fungsi sf untuk mengimport shapefile daerah Pennsylvania.

pa_geo <- sf :: st_read ("PaCounty2020_08 / PaCounty2020_08.shp",

stringsAsFactors = PALSU)

Saya tidak menyukai nama lajur daerah COUNTY_NAM di pa_geo, jadi saya akan menukarnya menjadi "County" dengan kod ini:

nama (pa_geo) [2] <- "Daerah"

Sebelum saya menggabungkan data saya dengan geografi saya, saya ingin memastikan bahawa nama daerah sama di kedua-dua fail. anti_join()fungsi dplyr menggabungkan dua set data dan menunjukkan baris mana yang tidak sepadan. Saya akan menyimpan hasilnya dalam kerangka data yang disebut masalah dan melihat enam baris pertama dengan kepala () dan tiga lajur pertama:

masalah <- anti_join (pa_geo, pa_data, oleh = "County")

kepala (masalah [, 1: 3])

MSLINK County COUNTY_NUM geometri 1 42 MCKEAN 42 MULTIPOLYGON (((-78.20638 4 ...

Terdapat satu masalah. Ini kerana McKean County adalah MCKEAN dalam data ini tetapi McKEAN dalam kerangka data lain. Saya akan menukar McKean menjadi huruf besar dalam pa_data dan menjalankan anti_join()pemeriksaan semula.

pa_data $ County [pa_data $ County == "McKEAN"] <- "MCKEAN"

anti_join (pa_geo, pa_data, oleh = "County")

Tidak ada baris masalah sekarang.

Baris kod seterusnya menggabungkan data dengan geografi:

pa_map_data <- penggabungan (pa_geo, pa_data, oleh = "County")

Akhirnya, saya akan memastikan bahawa objek geografi dan data baru saya menggunakan unjuran yang sama seperti jubin risalah saya. Unjuran adalah topik GIS yang cukup kompleks. Buat masa ini, ketahuilah bahawa saya memerlukan WGS84 untuk memadankan risalah. Kod ini menetapkan unjuran saya:

pa_map_data <- st_transform (pa_map_data, "+ proj = longlat + datum = WGS84")

Sekarang data saya dalam bentuk yang saya perlukan, saya mempunyai tiga tugas lagi: Buat palet warna untuk setiap calon, buat pop timbul untuk peta, dan kemudian kodkan peta itu sendiri.

Palet warna

Saya akan mulakan dengan palet.

Saya akan memetakan perbezaan undian mentah dalam demo ini, tetapi anda mungkin ingin menggunakan perbezaan peratusan. Baris pertama dalam kod di bawah menggunakan range()fungsi asas R untuk mendapatkan perbezaan suara terkecil dan terbesar di lajur Margin. Saya telah memberikan warna paling ringan untuk nombor terkecil, dan yang paling gelap ke nombor terbesar. 

Seterusnya saya membuat dua palet, menggunakan warna merah konvensional untuk Republikan dan biru untuk Demokrat. Saya menggunakan skala intensiti yang sama untuk kedua palet: paling ringan untuk margin terendah, tanpa mengira calon, dan tertinggi untuk margin tertinggi, tanpa mengira calon. Ini akan memberi saya idea di mana setiap calon terkuat dalam skala intensiti tunggal. Saya menggunakan colorNumeric()fungsi risalah , dengan warna palet Reds atau Blues, untuk membuat palet. ( domainArgumen menetapkan nilai minimum dan maksimum untuk skala warna.)

min_max_values ​​<- range (pa_map_data $ Margin, na.rm = TRUE)

trump_palette <- colorNumeric (palet = "Merah",

domain = c (min_max_values ​​[1], min_max_values ​​[2]))

clinton_palette <- colorNumeric (palet = "Blues",

domain = c (min_max_values ​​[1], min_max_values ​​[[2]]))

Kumpulan kod seterusnya membuat  dua bingkai data yang berbeza : Satu untuk setiap calon, yang mengandungi hanya tempat yang dimenangi oleh calon. Mempunyai dua bingkai data membantu saya mendapatkan kawalan yang baik terhadap pop timbul dan warna. Saya boleh menggunakan teks pop timbul yang berbeza untuk setiap teks. 

trump_df <- pa_map_data [pa_map_data $ Pemenang == "Trump",]

clinton_df <- pa_map_data [pa_map_data $ Pemenang == "Clinton",]

Pop up

Tugas seterusnya adalah pop timbul. Di bawah ini saya menghasilkan beberapa HTML termasuk  teg kuat untuk teks tebal dan tag br untuk jeda baris. Sekiranya anda tidak biasa dengan gam, kod di dalam pendakap {} adalah pemboleh ubah yang dinilai. Dalam pop timbul, saya akan memaparkan nama calon yang menang diikuti dengan jumlah suara mereka, nama dan jumlah calon yang lain, dan margin kemenangan di daerah itu. Yang  scales::comma() fungsi menambah koma untuk Jumlah undi angka seribu atau lebih, dan  accuracy = 1memastikan ia adalah satu integer pusingan tanpa titik perpuluhan.

Kod itu kemudian glue()memasukkan string teks ke HTML()fungsi htmltools  , yang mana risalah perlu menampilkan teks pop timbul dengan betul. 

trump_popup <- gam (" {trump_df $ County} COUNTY

Pemenang: Trump

Trump: {timbangan :: koma (trump_df $ Trump, ketepatan = 1)}

Clinton: {timbangan :: koma (trump_df $ Clinton, ketepatan = 1)}

Margin: {skala :: koma (trump_df $ Margin, ketepatan = 1)} ")%>%

lapply (htmltools :: HTML)

clinton_popup <- lem (" {clinton_df $ County} COUNTY

Pemenang: Clinton

Clinton: {timbangan :: koma (clinton_df $ Clinton, ketepatan = 1)}

Trump: {timbangan :: koma (clinton_df $ Trump, ketepatan = 1)}

Margin: {skala :: koma (clinton_df $ Margin, ketepatan = 1)} ")%>%

lapply (htmltools :: HTML)

Kod peta

Akhirnya, peta. Kod peta dimulakan dengan membuat objek risalah asas menggunakan leaflet() tanpa menambahkan data sebagai argumen dalam objek utama. Ini kerana saya akan menggunakan dua set data yang berbeza. Baris seterusnya dalam kod di bawah menetapkan jubin latar belakang ke CartoDB Positron. (Itu pilihan. Anda boleh menggunakan lalai, tetapi saya suka gaya itu.)

risalah ()%>%

addProviderTiles ("CartoDB.Positron")

Seterusnya saya akan menggunakan addPolygons()fungsi risalah dua kali, satu untuk bingkai data setiap calon dilapisi pada lapisan peta yang sama.

risalah ()%>%

addProviderTiles ("CartoDB.Positron")%>%

tambahPoligon (

data = trump_df,

fillColor = ~ trump_palette (trump_df $ Margin),

label = trump_popup,

strok = BENAR,

smoothFactor = 0.2,

fillOpacity = 0.8,

warna = "# 666",

berat = 1

)%>%

tambahPoligon (

data = clinton_df,

isiColor = ~ clinton_palette (clinton_df $ Margin),

label = clinton_popup,

strok = BENAR,

smoothFactor = 0.2,

fillOpacity = 0.8,

warna = "# 666",

berat = 1

)

Pada blok kod di atas, saya menetapkan data untuk setiap addPolygons() fungsi ke kerangka data setiap calon. The fillColorhujah mengambil palet setiap calon dan menerapkannya kepada margin kemenangan. Pop-up (sebenarnya rollover label) akan menjadi HTML calon itu, yang saya buat di atas.

Selebihnya adalah reka bentuk standard. strokemenetapkan garis sempadan di sekitar setiap poligon. smoothFactor memudahkan paparan garis besar poligon; Saya menyalin nilai dari peta demo RStudio yang saya suka. Dan fillOpacityitulah yang anda harapkan.

coloradalah warna garis sempadan poligon , bukan poligon itu sendiri ( warna poligon ditetapkan dengan fillColor). weightialah ketebalan garis sempadan poligon dalam piksel. 

Kod itu menghasilkan peta seperti yang ada di bawah, tetapi dengan kemampuan tambahan untuk menggulung tetikus anda (atau ketik pada telefon bimbit) dan melihat data yang mendasari. 

Sharon Machlis,

Philadelphia berada di kanan bawah. Anda dapat melihat betapa pentingnya, mengikut populasi, berbanding dengan semua kawasan lain di Pennsylvania yang besar di peta tetapi mempunyai pengundi yang jauh lebih sedikit. 

Sharon Machlis,

Mungkin menarik untuk memetakan perbezaan margin undi mentah antara satu pilihan raya dan pilihan raya lain, seperti Pennsylvania pada 2016 berbanding 2020. Peta itu akan menunjukkan di mana corak berubah paling banyak dan mungkin dapat membantu menjelaskan perubahan hasil di seluruh negara.

Sekiranya anda berminat dengan lebih banyak visualisasi data pilihan raya, saya telah menyediakan pakej pilihan raya 2 R di GitHub. Anda boleh memasangnya sebagaimana adanya atau melihat kod R saya di GitHub dan menyesuaikannya untuk kegunaan anda sendiri.

Untuk lebih banyak petua R, pergi ke halaman Do More With R.