Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Labeling center of map polygons in R ggplot

I am trying to label my polygons by using ggplot in R. I found a topic here on stackoverflow that I think is very close to what I want except with points.

Label points in geom_point

I found some methods online. Now I first need to find the central location of each shape and then I have to put these locations together with the name together. Then link this to the labeling function in geom_text()

ggplot centered names on a map

Since I have been trying for a long time now I decided to ask the question and hope that someone here can give me the final push to what I want. My plotting function:

region_of_interest.fort <- fortify(region_of_interest, region = "score")
region_of_interest.fort$id <- as.numeric(region_of_interest.fort$id)
region_of_interest.fort$id <- region_of_interest.fort$id


region_of_interest.fort1 <- fortify(region_of_interest, region = "GM_NAAM")
region_of_interest.fort1$id <- as.character(region_of_interest.fort1$id)
region_of_interest.fort1$id <- region_of_interest.fort1$id

idList <- unique(region_of_interest.fort1$id)
centroids.df <- as.data.frame(coordinates(region_of_interest))
names(centroids.df) <- c("Longitude", "Latitude")
randomMap.df <- data.frame(id = idList, shading = runif(length(idList)), centroids.df)

ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
  geom_polygon() +
  geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
  scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
  coord_equal() +
  theme() +
  ggtitle("Title")

It gives me the error: ggplot2 doesn't know how to deal with data of class uneval

My data

region_of_interest$GM_NAAM
 [1] Groningen        Haren            Ooststellingwerf Assen            Aa en Hunze      Borger-    Odoorn   
 [7] Noordenveld      Westerveld       Tynaarlo         Midden-Drenthe  
415 Levels: 's-Gravenhage 's-Hertogenbosch Aa en Hunze Aalburg Aalsmeer Aalten ... Zwolle

region_of_interest$score
 [1] 10 -2 -1  2 -1 -4 -4 -5  0  0
like image 713
Zuenie Avatar asked Feb 26 '14 10:02

Zuenie


2 Answers

Try something like this?

  1. Get a data frame of the centroids of your polygons from the original map object.

  2. In the data frame you are plotting, ensure there are columns for the ID you want to label, and the longitude and latitude of those centroids.

  3. Use geom_text in ggplot to add the labels.

Based on this example I read a world map, extracting the ISO3 IDs to use as my polygon labels, and make a data frame of countries' ID, population, and longitude and latitude of centroids. I then plot the population data on a world map and add labels at the centroids.

library(rgdal) # used to read world map data
library(rgeos) # to fortify without needing gpclib
library(maptools)
library(ggplot2)
library(scales) # for formatting ggplot scales with commas

# Data from http://thematicmapping.org/downloads/world_borders.php.
# Direct link: http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip
# Unpack and put the files in a dir 'data'

worldMap <- readOGR(dsn="data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
# Change "data" to your path in the above!
worldMap.fort <- fortify(world.map, region = "ISO3")
# Fortifying a map makes the data frame ggplot uses to draw the map outlines.
# "region" or "id" identifies those polygons, and links them to your data. 
# Look at head(worldMap@data) to see other choices for id.
# Your data frame needs a column with matching ids to set as the map_id aesthetic in ggplot. 
idList <- worldMap@data$ISO3
# "coordinates" extracts centroids of the polygons, in the order listed at worldMap@data
centroids.df <- as.data.frame(coordinates(worldMap))
names(centroids.df) <- c("Longitude", "Latitude")  #more sensible column names
# This shapefile contained population data, let's plot it.
popList <- worldMap@data$POP2005

pop.df <- data.frame(id = idList, population = popList, centroids.df)

ggplot(pop.df, aes(map_id = id)) + #"id" is col in your df, not in the map object 
  geom_map(aes(fill = population), colour= "grey", map = worldMap.fort) +
  expand_limits(x = worldMap.fort$long, y = worldMap.fort$lat) +
  scale_fill_gradient(high = "red", low = "white", guide = "colorbar", labels = comma) +
  geom_text(aes(label = id, x = Longitude, y = Latitude)) + #add labels at centroids
  coord_equal(xlim = c(-90,-30), ylim = c(-60, 20)) + #let's view South America
  labs(x = "Longitude", y = "Latitude", title = "World Population") +
  theme_bw() 

Population map of South America

Minor technical note: actually coordinates in the sp package doesn't quite find the centroid, but it should usually give a sensible location for a label. Use gCentroid in the rgeos package if you want to label at the true centroid in more complex situations like non-contiguous shapes.

like image 73
Silverfish Avatar answered Nov 01 '22 13:11

Silverfish


The accepted answer here may work, but the actual question asked specifically notes that there is an error "ggplot2 doesn't know how to deal with data of class uneval."

The reason that it is giving you the error is because the inclusion of centroids.df needs to be a named variable (e.g. accompanied by "data=")

Currently:

ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
  geom_polygon() +
  geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
  scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
  coord_equal() +
  theme() +
  ggtitle("Title")

Should be (note: "data=centroids.df"):

ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
  geom_polygon() +
  geom_text(data=centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
  scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
  coord_equal() +
  theme() +
  ggtitle("Title")

This issue was addressed here: How to deal with "data of class uneval" error from ggplot2?

like image 3
Jarrod Olson Avatar answered Nov 01 '22 15:11

Jarrod Olson