1

I am trying to use ggplot to map an area and label based on values in the @data slot. My error is the same as in the questions here, here, and here, but I can't translate those answers to my problem. I can plot states from the US maps from getData in the raster package but am having trouble from there. For an example these are the data sets I tried (I listed packages because I thought they might have something to do with the problem)...

library(rgdal)
library(raster)
library(ggplot2)
library(maps)
library(maptools)
library(ggmap) # used for theme_nothing() later    
us <- getData("GADM",country="USA",level=1)
PA <- us[us$NAME_1 == 'Pennsylvania',]
AK <- us[us$NAME_1 == 'Alaska',]

When I try this I get a funky map (PA is a single polygon).

ggplot(data=PA, aes(long, lat)) +
 geom_polygon(aes(group=group), color='black', fill=NA) +
 geom_text(data=PA, aes(long, lat, label = PA$NAME_1))

enter image description here

And when I try this I get the Aesthetics error (AK consists of 2 polygons).

ggplot(data=AK, aes(long, lat)) +
 geom_polygon(aes(group=group), color='black', fill=NA) +
 geom_text(data=AK, aes(long, lat, label = AK$NAME_1))

Regions defined for each Polygons Regions defined for each Polygons Error: Aesthetics must be either length 1 or the same as the data (816071): x, y, label

I'm not sure why I have to put the $ in the geom_text with a data call already present, but it doesn't recognize the variable without it. I also tried to just color the 2 AK polygons by their OBJECTID as in this code, but get the same Aesthetics error.

ggplot(data=AK, aes(long, lat)) +
 geom_polygon(aes(group=group), color='black', fill=AK$OBJECTID)

Thanks for any insight. I really want to use R for mapping more often.

Community
  • 1
  • 1
tjr
  • 607
  • 2
  • 7
  • 20
  • 1
    What is your desired output? Why are you plotting so many geom_texts? – Heroka Dec 30 '15 at 16:53
  • 1
    Do you really want to add the name of the state at every coordinate? That's why your plot looks so weird. You might check out `annotate` instead to add a label just one time. I can't reproduce the problem you are having with AK not plotting. If you want to fill by a variable you need to move fill inside `aes` - see the help page for `geom_polygon` for examples. – aosmith Dec 30 '15 at 16:54
  • No I don't want to add the label at every coordinate. I am doing this over a group of states and want a single label for each polygon, in this case just the PA polygon. I will look into 'annotate'. I tried running my code in a new session and still get the aesthetics error. I'm using 3.2.2 – tjr Dec 30 '15 at 18:03
  • I have been able to get annotate to work for just the PA single polygon with `annotate("text", x=-77, y=41, label = PA$NAME_1)` but can't get labels where there is more than one polygon, as in AK. – tjr Dec 30 '15 at 18:39
  • Don't the state objects have a center attribute? When I look at str(PA) it appears to me that the line `.. .. .. ..@ labpt : num [1:2] -77.8 40.9` has that value. (Appears designed for table placement.) – IRTFM Dec 30 '15 at 19:01
  • I agree it looks like placement, but I haven't figured out how to use it in the plot functions. – tjr Dec 30 '15 at 19:43

3 Answers3

1

As mentioned in the other answers and comments, modifying geom_text is the first change to be made. My main addition is the use of coord_map(), which is part of ggplot2. coord_map() properly scales the axes for the typical lat-long mapping.

ggplot(data=AK, aes(long, lat)) +
  geom_polygon(aes(group=group), 
               color = "black", 
               fill = NA, 
               alpha = 0.2) + 
  coord_map()

This results in a very long (thus not shown) but accurate mapping. This is due to Alaska's extreme coordinates being interpreted a little improperly by the default scale.

With a little clipping of the axes with scale_x_continuous at -190 and -120 a better cropping is available.

ggplot(data=AK, aes(long, lat)) +
  geom_polygon(aes(group=group), 
               color = "black", 
               fill = "darkgreen", 
               alpha = 0.2) + 
  coord_map()+
  scale_x_continuous(limits = c(-190, -120)) +
  annotate(geom = "text", 
           x = coordinates(AK)[2, 1], # note: [2,] refers to mainland label 
           y = coordinates(AK)[2, 2], 
           label = AK$NAME_1[1],
           size = 10)  

Alaska Plot Notice that the label coordinates need to be selected a little differently for Alaska than Pennsylvania as the Alaska data.frame contains two objects. coordinates(AK)[1,] supplies the label coordinates for the largest island while coordinates(AK)[2,] is the label coordinates for the mainland.

For further reading, I was working a bit with mapping census data with the census shape files and Kevin Johnson's blog post on Making Maps in R was very helpful. The census shape files come in different resolution levels so if you have hang ups with say the many coordinates present in Alaska's outline, the 5m or 20m census shape file versions may be more manageable.

Seth_P
  • 171
  • 3
  • 3
0

The excess of "Pennsylvania" text entries is caused by giving all the long's and lat's values to the geom_text function. You need to switch to a function that takes only single coordinates. After making the PA object, I can do this, which admittedly seems like a hack. The S4 object classes are supposed to have proper extractor methods, but I searched in the ?SpatialPolygonsDataFrame help page and links and do not find an extractor for the labpt slot. (Then @aosmith filled in that blank and I looked up how to set the aspect ration to 1.0):

plot(PA)
text(x= PA@polygons[[1]]@Polygons[[1]]@labpt[1],   
     y=PA@polygons[[1]]@Polygons[[1]]@labpt[2], 
     label=PA$NAME_1)

I tried plotting the Alaska object but my R session hung up. AK is a fairly complex spatial object with all those islands. When you look at the structure, you see way more than 2 polygons:

..@ polygons   :List of 2
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 4147

You will probably need to loop through list of 4147 to find the polygon with the largest area or put in hand-coded coordinates. The ggplot version of this plotting effort on PA might start with this (although the aspect ratio needs to be fixed,):

ggplot(data=PA, aes(long, lat)) +
 geom_polygon(aes(group=group), color='black', fill=NA) + 
 annotate(geom="text", x=coordinates(PA)[1], y=coordinates(PA)[2], label = PA$NAME_1) + 
 coord_fixed(ratio=1)

enter image description here

IRTFM
  • 258,963
  • 21
  • 364
  • 487
0

Still not much luck using ggplot to solve my problem. I have switched to plot and spplot for now and have found out how to label the polygon in the center and the Labpt slot as here...invisible(text(getSpPPolygonsLabptSlots(PA), labels=as.character(PA$NAME_1), cex=0.5)) Thought this might help someone.

tjr
  • 607
  • 2
  • 7
  • 20