rgisgeospatialr-sfcartogram

Congressional District as a Cartogram in R?


Currently, I am using United States Congressional District Shapefiles. I want to make a Cartogram using the steps laid out in the cartogram package. But I cannot seem to make it into the cartogram object using the cartogram_cont function successfully.

Any help, advice, or insight you can offer in getting me past this point and closer to the cartogram would be incredibly helpful.

Please the bottom of the code for where the error occurs.

Thank you!

######################### Library #####################
library(sf)
library(tmap)
library(cartogram)
library(ggplot2)
library(ggmap)
library(maptools)


###################### Get Congress Map ###################
get_congress_map <- function(cong=113) {
  tmp_file <- tempfile()
  tmp_dir  <- tempdir()
  zp <- sprintf("http://cdmaps.polisci.ucla.edu/shp/districts%03i.zip",cong)
  download.file(zp, tmp_file)
  unzip(zipfile = tmp_file, exdir = tmp_dir)
  fpath <- paste(tmp_dir, sprintf("districtShapes/districts%03i.shp",cong), sep = "/")
  st_read(fpath)
}


cd114 <- get_congress_map(114)

################ Create Congressional District ID ###################

State_Dictonary <- rbind(data.frame(state.abb, STATENAME= state.name), data.frame(state.abb= "DC", STATENAME= "District Of Columbia"))

#Add DC
cd114.1 <- merge(State_Dictonary, cd114, by = c("STATENAME"))
unique(cd114$STATENAME)
#**************** Paste Zero infront of Single Districts ****************
cd114.1$district_code <- as.character(cd114.1$DISTRICT)
cd114.1$district_code[cd114.1$district_code == 98] <- "01" #Account for the weird code for DC
cd114.1$district_code[cd114.1$district_code == 0] <- "01"  #Account for at large districts
cd114.1$district_code[cd114.1$district_code == 1] <- "01"
cd114.1$district_code[cd114.1$district_code == 2] <- "02"
cd114.1$district_code[cd114.1$district_code == 3] <- "03"
cd114.1$district_code[cd114.1$district_code == 4] <- "04"
cd114.1$district_code[cd114.1$district_code == 5] <- "05"
cd114.1$district_code[cd114.1$district_code == 6] <- "06"
cd114.1$district_code[cd114.1$district_code == 7] <- "07"
cd114.1$district_code[cd114.1$district_code == 8] <- "08"
cd114.1$district_code[cd114.1$district_code == 9] <- "09"

#************** Create CD in  Data ****************
cd114.1$CD <- paste(cd114.1$state.abb, cd114.1$district_code, sep = "")


################ Create Fake Data TO Simulate My Own ########################
CD <- unique(cd114.1$CD)
Values <- sample(1:100, 436, replace = T)

Df <- data.frame(CD, Values)


################### Merge Shape File to Donor #####################
#******************** Merge Descriptive Stats *********************
Df.2 <- merge(x = Df, y = cd114.1, by = c("CD"), all.y = T)

################### Make SF Object ####################
SF.DF.1 <- st_as_sf(Df.2)
SF.DF.2 <- st_make_valid(SF.DF.1)
class(SF.DF.2)

################### Make cartogram ####################
#Follow Proceedure Laid out: https://cran.r-project.org/web/packages/cartogram/readme/README.html

# I use st_transform instead of spTransform beause I'm using an SF Ojbect
SF.DF.3 <- st_transform(SF.DF.1, CRS("+init=epsg:3395")) 

cartogram_cont(SF.DF.3, "Value", itermax = 5)
#Error in Fij[distance <= radius[j]] <- Fbij[distance <= radius[j]] : 
#NAs are not allowed in subscripted assignments





Solution

  • The geometry entry in row 87 is empty (MULTIPOLYGON EMPTY). You can overcome this issue by:

    library(dplyr)
    
    SF.DF.3 <- st_transform(SF.DF.1, CRS("+init=epsg:3395")) %>% 
      filter(!st_is_empty(.))
    

    Additionally, there's no column Value included in you df, it's Values ;)

    sf_ncont <- cartogram_ncont(SF.DF.3, "Values")
    
    tm_shape(sf_ncont) + tm_polygons("Values", style = "jenks", legend.show = FALSE) +
      tm_layout(frame = FALSE)
    

    Note, I filtered out Alaska and Hawaii for the following plot, as well as used cartogram_ncont instead of cartogram_cont since the former operation is very time consuming.

    enter image description here