The following code works well for drawing polygons

SP <- SpatialPolygons(spd)
centroids  <- coordinates(SP)
x  <- centroids[,1]
y  <- centroids[,2]
SP1  <- SpatialPolygonsDataFrame(SP, data = data.frame(x = x, y = y, z = z, row.names = row.names(SP)))
ggplot(data = SP1, aes(x = long, y = lat, group = group)) + geom_path()

Instead if I change the last two lines of the code to fill these polygons based on some value vector it does not work:

penetration <- runif(n = length(SP), min = 1, max = 10)
SP1  <- SpatialPolygonsDataFrame(SP, data = data.frame(x = x, y = y, z = z,  value = penetration, row.names = row.names(SP)))
ggplot(data = SP1, aes(x = long, y = lat, group = group)) + geom_polygon(aes(fill=SP1$value))

spd is created with data from the following link:

data source: https://www.google.com/maps/d/viewer?mid=1mf9TQY3bocarO4SaIXAtco_C1LE&hl=en_US

I then extracted coordinates from the kml file... which is then into a list of Polygons so that I could draw it using some plotting function...

tkml <- getKMLcoordinates(kmlfile="Pune all Electoral Wards.kml", ignoreAltitude=T)
len <-length(tkml)

del <- NA
for(i in 1:len)
  if(length(tkml[[i]]) == 2)
    del <- c(del, i)
del <- del[-1]
tkmlCleaned <- tkml[!tkml %in% tkml[del]]
size <- length(tkmlCleaned)
sr <- vector(mode = "list", length = size)
srs <- vector(mode = "list", length = size)
spd <- list()
for(j in 1:length(sr))

  sr[[j]] <- Polygon(tkmlCleaned[[j]])
  srs[[j]] <- Polygons(list(sr[[j]]), j)
  spd <- c(srs[[j]], spd)
  • Start with library(rgdal); spd <- readOGR("Pune all Electoral Wards.kml", "Pune Prabhags 2012 onwards"); plot(spd, col = sample(grey(seq(0, 1, length = nrow(spd))))) then learn about plotting polys with ggplot2 (or generally). Do you just want to recreate the map/s in the webpage, as they appear? This is all bit trickier than it should be, but this is a better starting point IMO
    – mdsumner
    Aug 19, 2016 at 9:02
  • I missed a couple things, you can't use the value column literally like that, you have to merge the attributes back on after fortify(SP1) - which you seem to have left out? More soon, but please update with answers
    – mdsumner
    Aug 19, 2016 at 9:26
  • Yes I want to recreate the map based on population density of the wards...
    – AdiPiratla
    Aug 19, 2016 at 11:00
  • I did not quite understand the usage of fortify. I am trying to make sense of it and will let you know if I get results
    – AdiPiratla
    Aug 19, 2016 at 11:12

2 Answers 2


There's a lot more to this, it's interestingly painful in a couple of places. There are easier steps in some ways with less base ggplot2 functions, but I'm not used to them yet.

Maybe this will help you . . .


## we can only read one layer at a time, to see which layers are there run
##ogrListLayers("Pune all Electoral Wards.kml")
#"Pune Prabhags 2012 onwards"
#"PMC Adminstrative Ward Offices"

spd <- readOGR("Pune all Electoral Wards.kml", "PMC Adminstrative Ward Offices")


## this is the table of all coordinates, classified by object and part-of-object
spdtab <- fortify(spd)

## but note that we don't have any of the layer-attributes

## to put them on we can use merge(), but it's much easier with dplyr IMO
gislayerdata <- mutate(as.data.frame(spd), id = as.character(row_number()))
spdtab <- inner_join(spdtab, gislayerdata, "id")

ggplot(spdtab) + aes(x = long, y = lat, group = group, fill = Name) + 
   geom_polygon() + 
   guides(fill = FALSE) 
  • I am getting an error on using fortify function ... spdtab <- fortify(spd) Error: ggplot2 doesn't know how to deal with data of class SpatialPointsDataFrame Is there anything I am missing? Thanks in advance
    – AdiPiratla
    Aug 19, 2016 at 10:56
  • It's not for points, it's for polygons or lines. Your KML contains polygons. The "fortify" version of SpatialPointsDataFrame is just as.data.frame(x), since there's only one coordinate per row. Fortify is just all the coordinates in one table, with "id" the object (one row in SpolyDF), "group" (or piece) the sub-geometry (i.e. a ring polygon), order, hole status, and x/y coords.
    – mdsumner
    Aug 19, 2016 at 13:16
  • WARNING!!! id = as.character(row_number()) could be wrong depending on the version. It should rather be id = as.character(row_number() - 1)). I checked the dataset and the id starts with 0 for the spdtab dataset therefore the -1!! May 22, 2020 at 13:13

you don't mention which error it yields, but, for these cases,

aes(x=long, y=lat, group=group, fill=group)

has worked for me

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.