2

I am attempting to make a map with three layers using ggmap. The layers are as follows:

  1. A map of the US (toner-lite)
  2. a set of geometries that color the states on some value (simulated data below)
  3. labels for the state names, as annotations in the center of each state.

To do this I have created a map of US states with states colored by a randomized value (rnorm) and this part is successful. From here I am attempting to print the abbreviations of each state at the longitude and latitude coordinates of each state's center, using geom_text. The part that fails is the 'geom_text' overlay, with the following error:

Error: 'x' and 'units' must have length > 0 In addition: Warning messages: 1: In gpclibPermit() : support for gpclib will be withdrawn from maptools at the next major release 2: Removed 855070 rows containing missing values (geom_text).

Here is the script, which I have worked hard to run as on its own. It will download the shapefile and center of state data, as well as to simulate data to fill the states. I've tested it and it works up to what I have commented out (geom_text layer).

I have searched for answers to this already, so please let me know if you have any advice on how to do what I am attempting. If there is a better strategy for placing labels on top of the polygon fills, I am all ears (or eyes in this case).

###Combining Census data with a tract poly shapefile
library(maptools)
library(ggplot2)
library(gpclib)
library(ggmap)
library(rgdal)
library(dplyr)

#Set working directory to where you want your files to exist (or where they already exist)
setwd('~/Documents/GIS/USCensus/')
#Read and translate coord data for shape file of US States
if(!file.exists('tl_2014_us_state.shp')){
        download.file('ftp://ftp2.census.gov/geo/tiger/TIGER2014/STATE/tl_2014_us_state.zip',
                      'tl_2014_us_state.zip')
        files <- unzip('tl_2014_us_state.zip')
        tract <- readOGR(".","tl_2014_us_state") %>% spTransform(CRS("+proj=longlat +datum=WGS84"))
} else {
        tract <- readOGR(".","tl_2014_us_state") %>% spTransform(CRS("+proj=longlat +datum=WGS84"))
}

#two column dataset of state abbreviations and center of state
#Downloadable from: https://dev.maxmind.com/static/csv/codes/state_latlon.csv
if(!file.exists('state_latlon.csv')){
        download.file('http://dev.maxmind.com/static/csv/codes/state_latlon.csv','state_latlon.csv')
}
centers <- read.csv('state_latlon.csv')
#Change values of longitude and latitude from state center data so as not to interfere with shapefile at merge
names(centers)[2:3] <- c('long_c','lat_c')

#simulated data for plotting values
mydata<- data.frame(rnorm(55, 0, 1)) #55 "states" in the coord dataset for state centers
names(mydata)[1] <- 'value'

#hold names in tract dataset and for simulated data
ntract<-names(tract)
ndata<-names(mydata) 

#Turn geo data into R dataframe
gpclibPermit()
tract_geom<-fortify(tract,region="STUSPS")

#Merge state geo data with simulated data
state_data <- cbind(centers,mydata)
#merge state center and value data with shapefile data
tract_poly <- merge(state_data,tract_geom,by.x="state",by.y="id", all = F) 
tract_poly<-tract_poly[order(tract_poly$order),]

#Create map of US
mymap <- get_stamenmap(bbox = c(left = -124.848974,
                                bottom = 24.396308,
                                right = -66.885444,
                                top = 49.384358),zoom=5,
                       maptype="toner-lite")

#This plots a map of the US with just the state names as labels (and a few other landmarks). Used for reference
USMap <- ggmap(mymap,extent='device') +
        geom_polygon(aes(x = long, y = lat, group = group, fill = value),
                     data = tract_poly,
                     alpha = 1, 
                     color = "black",
                     size = 0.2) #+
#         geom_text(aes(x = long_c, y = lat_c, group = group, label = state),
#                   data= tract_poly,
#                   alpha = 1,
#                   color = "black")

USMap
Patrick Williams
  • 694
  • 8
  • 22
  • This isn't the source of the error, but you shouldn't use `tract_poly` as the data frame for `geom_text`. For `geom_text` you want one row for each state, but `tract_poly` has thousands of rows for each state (one for each segment of state borders). For example, you could use `data=tract_poly %>% group_by(state) %>% slice(1)`. – eipi10 Apr 06 '15 at 19:54

2 Answers2

2

That's a strange error message for what ended up being the problem. Somewhere along the way you have flipped the latitude and longitude for centers. (I also took into account elpi's advice above and didn't plot the Initials repeatedly by using your centers dataset directly). The code below works, but I'd recommend fixing your centers dataset.

centers$new_long <- centers$lat_c
centers$new_lat <- centers$long_c
USMap <- ggmap(mymap,extent='device') +
        geom_polygon(aes(x = long, y = lat, group = group, fill = value),
                     data = tract_poly,
                     alpha = 1, 
                     color = "black",
                     size = 0.2) +
         geom_text(aes(x = new_long, y = new_lat, label = state),
                   data= centers,
                   alpha = 1,
                   color = "black")
GregF
  • 1,292
  • 11
  • 14
  • Thank you everyone for the advice. I'm working on the fix now and this all makes total sense. From what I read, the error was likely due to the plotting being outside the mappable range, which would make sense of the lon/lat coords were being flipped. Will update after I have had time to get it working. – Patrick Williams Apr 06 '15 at 20:07
  • Taking into account GregF's fix (which takes into account elpi's advice), I was able to get this to work. The problem was in the line `names(centers)[2:3] <- c('long_c','lat_c')` Which was reversing the long/lat by renaming. It was replaced by: `names(centers)[2:3] <- c('lat_c','long_c')` I then used GregF's map addition `geom_text(aes(x = new_long, y = new_lat, label = state), data= centers, alpha = 1, color = "black")` And everything works – Patrick Williams Apr 07 '15 at 16:34
1

Try this

centroids <- setNames(do.call("rbind.data.frame", by(tract_poly, tract_poly$group, function(x) {Polygon(x[c('long', 'lat')])@labpt})), c('long', 'lat')) 
centroids$label <- tract_poly$state[match(rownames(centroids), tract_poly$group)]
USMap + with(centroids, annotate(geom="text", x = long, y=lat, label = label, size = 2.5))

(via)

Community
  • 1
  • 1
lukeA
  • 53,097
  • 5
  • 97
  • 100