Creating base_layer for ggmap not recognizing data.frame
Asked Answered
A

1

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?
Atingle answered 3/7, 2013 at 23:26 Comment(7)
wild guess: ggplot2 can be fussy about environments when working inside functions; IIRC there are a couple of examples on SO.Shook
I had this in mind, but it doesn't seem to help ggplot. Maybe it's a similar problem with ggmap, but I gave up looking inside that code.Shook
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!Atingle
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 thoughShook
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.Shook
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?Atingle
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.Shook
A
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)
  }
Atingle answered 4/7, 2013 at 22:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.