2

I am trying to use ggmap to plot locations on a map. Because I want to use faceting, I have to supply the base_layer argument to ggmap. I am also trying to wrap this in a function.

I have variables that define the bounding box of my map:

long.range <- c(-71.5, -67.5)
lat.range <- c(42.5, 44.5)

And a data.frame that defines the data I want to plot:

test.data <- data.frame("Name" = c("site1","site2","site3"),
                        "LAT" = c(43.25,43.4,44),
                        "LONG" = c(-71.25,-69.5,-68.5))

I have a function that goes out and grabs the map and applies the data.frame as the base_layer:

CreateBaseMap <- function(lat.range = c(NA,NA),
                          long.range = c(NA,NA),
                          data.in = NULL){    
  # download the map tile
  base.map.in <- get_map(location = c(min(long.range),
                                      min(lat.range),
                                      max(long.range),
                                      max(lat.range)),
                         source = "osm")
  # create the map object
  if (is.null(data.in)){
    base.map <- ggmap(base.map.in)
  } else {    
    base.map <- ggmap(base.map.in,
                      base_layer = ggplot(aes_string(x = "LONG",
                                                     y = "LAT"),
                                          data = data.in))
  }
  base.map <- base.map +
    labs(x = "Longitude",
         y = "Latitude") + 
    coord_map()
  print(base.map)
  return(base.map)
}

and then I call my function using

base.map <- CreateBaseMap(lat.range = lat.range, long.range = long.range, data.in = test.data)

and I get this error.

Error in ggplot(aes_string(x = "LONG", y = "LAT"), data = data.in) : 
  object 'data.in' not found

Troubleshooting so far

I know if I call the guts of the function directly, like this:

base.map <- ggmap(get_map(location = c(min(long.range),
                                       min(lat.range),
                                       max(long.range),
                                       max(lat.range)),
                          source = "osm"),
                  base_layer = ggplot(aes_string(x = "LONG",
                                                 y = "LAT"),
                                      data = test.data)) +
  geom_point()
print(base.map)

then it works fine.

The image I want

I have also checked using print(data.in) that the data.in exists before it gets to the call to base_layer, and I can see that it's there.

Question

It appears that the call to base_layer doesn't recognize data.in.

  1. How can I persuade base_layer that it really wants to accept data.in?
  2. Is this a problem with ggplot, or am I doing something wrong?
Andy Clifton
  • 4,926
  • 3
  • 35
  • 47
  • wild guess: `ggplot2` can be fussy about environments when working inside functions; IIRC there are a couple of examples on SO. – baptiste Jul 03 '13 at 23:30
  • I had [this in mind](http://stackoverflow.com/a/10662937/471093), but it doesn't seem to help `ggplot`. Maybe it's a similar problem with `ggmap`, but I gave up looking inside that code. – baptiste Jul 03 '13 at 23:47
  • Thanks @baptiste. I tried setting environment = environment() in the call to ggplot, but that doesn't help. Coming from a Matlab background where the only data you have is whatever you pass in to a function, this is confusing! – Andy Clifton Jul 03 '13 at 23:53
  • uh? I recall vividly that in Matlab there were many pitfalls with global variables all over the place. It's supposed to be the point that `R`, as a functional language, would avoid such dangers. It doesn't mean that all R code is properly written though – baptiste Jul 03 '13 at 23:56
  • if you skim through the `ggmap` code, you'll notice this bit `base <- deparse(eval(args$base_layer))`; I reckon that's where the problem lies, as `eval()` isn't given the right environment to find your data. – baptiste Jul 04 '13 at 00:01
  • Any suggestions as to how to fix this, then? Do I have to make sure I'm passing in a variable that's defined in the main environment? – Andy Clifton Jul 04 '13 at 00:14
  • 1
    the only way seems to be manual editing of the `ggmap` code (it seems to more or less work when changing those `eval()` calls), but I'd suggest you contact the package maintainer directly/file a bug report. – baptiste Jul 04 '13 at 00:19

1 Answers1

0

The solution seems to be to use %+% on the ggplot item that is created from the ggmap call, rather than including base_layer in the original call to ggmap. This bypasses the code problem that @baptiste identified.

To implement this solution, copy in the following code in place of the #create the map object in my original question:

# create the map object
  if (is.null(data.in)){
    base.map <- ggmap(base.map.in)
  } else {    
    base.map <- ggmap(base.map.in ) %+% data.in + aes(x = LONG,
                                                      y = LAT)
  }
Andy Clifton
  • 4,926
  • 3
  • 35
  • 47