1

a friend referred me here as opposed to the regular Stack Overflow site, as this community maybe better able to help!

My issue is largely with the syntax and framework of ggmap,ggplot, and the sp package.

I have already summarised and prepped my data. This link shows (some of) the data I'm trying to map. I used the following code block to create Spatial polygon objects instead of lists of lat/long values, as shown in the data in the above link:

createShape = function(sub){
  #This funciton takes the list of lat/lng values and returns a SHAPE which should be plottable on ggmap/ggplot
  tempData = as.data.frame(do.call(rbind, as.list(VICshapes[which(VICshapes$Suburb==sub),] %>% select(coords))[[1]][[1]]))
  names(tempData) = c('lat', 'lng')
  p = Polygon(tempData)
  ps = Polygons(list(p),1)
  sps = SpatialPolygons(list(ps))
  return(sps)
}
VICshapes[['shape']] = lapply(suburbNames, function(x) createShape(x))

So - I've got the data I want to plot. I've got shapes. I've got the packages installed... but how do I actually make things look pretty and presentable? ANY of the help on packages seems to assume I have .shp files, along with other external data which defines how I plot it all. Apparently I need to use ggmap::fortify() or broom::tidy on the shape files to get them to plot. Then I just get warnings from ggmap and ggplot about the length of aes arguments being incorrect.

I'm genuinely not sure how to proceed with this, but I know I have the necessary data to show what I want to show - I just don't know how to move forward.

Using R's inbuilt plot function on the output of the createShape() function above shows me a shape as I want. Great - but what if I want ALL the shapes, then coloured according to another variable - which is linked by a common key?

At this stage I'm so frustrated with it all - I'll literally pay someone's rent for a month if you can help.

1 Answer 1

1

What you want to end up with is a SpatialPolygonsDataFrame, which is like a regular data frame but there's some geometry for each row. This is what you get when you read a shapefile using readOGR, raster::shapefile, or readSHPpoly functions.

Your createShape() function returns a length-one vector of SpatialPolygons objects, then your lapply is returning a list of those. If you rbind to combine them you should get a longer vector of SpatialPolygons objects:

SpP = do.call(rbind, lapply(suburbNames, function(x) createShape(x)))

This should print out something like this depending on your data:

> SpP
class       : SpatialPolygons 
features    : 100 
extent      : 0.5, 10.5, 0.5, 10.5  (xmin, xmax, ymin, ymax)
coord. ref. : NA 

To make a SpatialPolygonsDataFrame, we use the SpatialPolygonsDataFrame function with a data frame argument:

> d = SpatialPolygonsDataFrame(
          SpP,
          data=data.frame(foo=1:length(SpP)),
          match.ID = FALSE)

d is now a SpatialPolygonsDataFrame with 100 features (spatial regions) and one data column, foo:

> d
class       : SpatialPolygonsDataFrame 
features    : 100 
extent      : 0.5, 10.5, 0.5, 10.5  (xmin, xmax, ymin, ymax)
coord. ref. : NA 
variables   : 1
names       : foo 
min values  :   1 
max values  : 100 

and you can make a quick map this way:

> spplot(d,"foo")
> 

To add extra columns to d, treat it like a data frame, and its order is the same order as the SpatialPolygons that constructed it.

The help pages for the SpatialPolygonsDataFrame class give a reproducible example of creating an SPDF from scratch. Run:

  help("SpatialPolygonsDataFrame-class")

Its worth noting that the sp class and its data formats have been mostly superseded by the sf package and its data formats - the principles are the same though - a data frame with a geometry for each row.

Lucky for you I own my house so that rent payment will be zero :)

3
  • Thanks for the tip! I think I'm headed in the right direction - albeit now I've come across an issue with ID's for the spatial polygons, namely invalid class “SpatialPolygons” object: non-unique Polygons ID slot values If I am creating another df to map with surely the IDs should be the rows on which the polygons are created to begin with - namely the $Suburb variable? That's what's common across all of the data I'm using. Thanks for your quick response!
    – rtob
    Commented Oct 24, 2018 at 9:43
  • You are creating all your Polygons with ID=1: ps = Polygons(list(p),1) - your code at that point doesn't have a row number to make into an ID. You could refactor or use a random integer - runif(1, 1, 1e12) should make collisions unlikely. I used match.ID=FALSE so the SpatialPolygons and data frame are matched by order and not rearranged.
    – Spacedman
    Commented Oct 24, 2018 at 10:09
  • Aha!! I should've caught that. I'm now just using the suburb as the id - which I'm passing to that method anyway. Seems like there's some redundant data storage there, but so be it. Making progress, thanks!
    – rtob
    Commented Oct 24, 2018 at 12:31

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.