4

I'm trying to plot a line layer over Google maps.

Data

> dput(map)
new("SpatialLinesDataFrame"
        , data = structure(list(att = c(463643, 2291491, 315237340, 10348934, 
309845150, 674351, 58057, 55962, 302861, 1405635)), .Names = "att",     row.names = c(NA, 
10L), class = "data.frame")
    , lines = list(<S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>, 
    <S4 object of class structure("Lines", package = "sp")>)
    , bbox = structure(c(50.497608475813, 26.1186426230732, 50.6164182652142, 
26.2649832975207), .Dim = c(2L, 2L), .Dimnames = list(c("x", 
"y"), c("min", "max")))
    , proj4string = new("CRS"
    , projargs = "+proj=longlat +ellps=WGS84 +towgs84=0,0,0,-0,-0,-0,0 +no_defs"
)
)

Approach

library(rgdal)
library(ggmap)

gmap <- get_map(location=rowMeans(bbox(segMap)), zoom = 11) # get Google map to use as background    

Variant I

plot(map, col = map$att, lwd = 1.5)
plot(gMap) 

Variant II

plot(map, col = map$att, lwd = 1.5)
ggmap(gMap)

Problem

Background map is plotted on top of feature map, rather than as background, as a result feature map is not visible. To clarify, both plot calls ( plot() and ggmap) work fine independently. Thank you

jpinelo
  • 1,414
  • 5
  • 16
  • 28
  • 1
    If you really want to use `ggmap`, you should seriously consider also using the functions from `ggplot2`, which `ggmap` is based on (in terms of the syntax) and more importantly, the two packages work together perfectly (have a look at `ggplot2::geom_line()`, `geom_polygon()` and `fortify()`). If you do not want to use ggplot syntax, rather go with the `openstreetmap` package, `rGooglemaps` etc. – maj Sep 05 '15 at 13:09
  • Thanks @maj. Am I right to understand that using ggmap is a way to avoid going the gis route? What solution would you recommend if I were to also wan to do some spatial analysis? – jpinelo Sep 05 '15 at 13:23
  • 2
    @jpinelo they are not mutually exclusive. you can add polygon and map layers to a ggmap created ggplot and `dput`s of `sp` objects (as you can see) don't transport well. This SO answer is an OK example http://stackoverflow.com/questions/10930737/ggmap-with-geom-map-superimposed/10940778#10940778 – hrbrmstr Sep 05 '15 at 15:17

1 Answers1

5

Something like this?

library(raster)    # for getData(...), also loads sp
library(ggmap)     # for get_map, also loads ggplot2

map <- getData("GADM",country="GBR",level=2)  # SpatialPolygonsDataFrame of UK
map <- map[map$NAME_2=="London",]             # extract London
# this builds a spatialLinesDataFrame object - random walks around London
# you have this already...
set.seed(1)    # for reproducible example
get.coords <- function() {
  do.call(cbind,lapply(rowMeans(bbox(map)),  
                               function(x)cumsum(sample(0.01*(-1:1),50,replace=TRUE))+x))
}
route <- SpatialLines(lapply(1:3,function(i)Lines(list(Line(get.coords())),ID=i)))
route <- SpatialLinesDataFrame(route, data.frame(att=c("A","B","C")))

# you would start here...
gg.df <- do.call(rbind,lapply(route$att, function(x)data.frame(att=x,coordinates(route[route$att==x,]))))

ggmap(get_map(location=rowMeans(bbox(map)),zoom=12)) + 
  geom_path(data=gg.df,  aes(x,y, color=att), size=2)+
  geom_point(data=gg.df, aes(x=x[1], y=y[1]),color="black",size=5)

First of all, thanks for trying to include your data. Normally, dput(...) is the way to go, but with spatial objects it just isn't useful. You really need to upload the file (or files, usually) somewhere and post a link.

Second, this is not a trivial problem. It's true that ggmap(...) produces a ggplot object which can be augmented by adding additional features using +, and it's also true that ggplot provides a very powerful fortify(...) function for converting SpatialPolygonsDataFrames into something usable by ggplot. But fortify(...) does not work with SpatialLines objects, so we have to do this explicitly.

So the bulk of this code just creates a SpatialLinesDataFrame with three lines, each of which has a corresponding attribute att in the attributes table. This should mimic your example pretty well. As this is a spatial object, all the methods in sp, rgeos, and so on on will be able to manipulate it.

Now, ggplot requires a data.frame with columns corresponding to the aesthetics mapped in the call to aes(...), so here, x and y for the location of the points, and color for the color of the lines. We create that using:

gg.df <- do.call(rbind,lapply(route$att, function(x)data.frame(att=x,coordinates(route[route$att==x,]))))

which extracts the coordinates for each value of att into a list of data.frames and binds these together row-wise.

Having done that, it's a simple matter to add the lines using

ggmap(get_map(location=rowMeans(bbox(map)),zoom=12)) + 
  geom_path(data=gg.df,  aes(x,y, color=att), size=2)+
  geom_point(data=gg.df, aes(x=x[1], y=y[1]),color="black",size=5)

Note that, (a) you need to use geom_path(...), because geom_line(...) will sort the x-axis, and (b) you need to tell ggplot that there's a layer-specific dataset (gg.df).

jlhoward
  • 58,004
  • 7
  • 97
  • 140
  • Thank you @jilhoward for a good and detailed answer. It is much appreciated. I'm having trouble understanding `function(x)` (fifth line from the end). Could you please explain that part? Using this I'm getting the error `Error in eval(expr, envir, enclos) : object 'x' not found`. – jpinelo Sep 05 '15 at 18:15
  • 1
    `lapply(...)` takes two arguments. The first is a vector or list. The second is a function. `lapply(...)` passes each element, in sequence, in the first argument to the function specified in the second argument, and then assembles the result into a new list. The use of `function(x)...` here just creates a so-called anonymous (un-named) function for the second argument. In your case, does the equivalent of `route$att` exist? – jlhoward Sep 05 '15 at 18:22
  • Thank you @jilhoward, for the Brilliant answer. I understand now. Thank you for the advice re sharing a link to spatial data rather than posting it. – jpinelo Sep 05 '15 at 18:34