Petr
Petr

Reputation: 1817

base_layer not showing in ggmap

I would like to as kfor any advice how to solve ggmap issue.

lets suppose we have some spatial model and residuals and then we would like to plot it in the map. When using ggmap function I can see baseline background plot and regend for base_layer - fill, however it cannot be seen in the plot.

I provide reproduceble example:

library(ggmap)
library(maptools)
library(ggplot2)


#map background
bboxPrague <- c(14.22,49.94,14.71,50.18)
ggMapPrague <- get_map(location = bboxPrague, source = "stamen",maptype = "toner", crop = TRUE, zoom = 12)
ggmap(ggMapPrague)

d = data.frame(
  pred_res = runif(2000, -50, 50),
  lon = runif(2000, 49.94, 50.18),
  lat = runif(2000, 14.22, 14.71)

)
d

#top&bottom coding and discreting pred_res....8
d$res_coded<-replace(d$pred_res,d$pred_res<(-1),8)
d$res_coded<-replace(d$res_coded,d$pred_res>=-1,7)
d$res_coded<-replace(d$res_coded,d$pred_res>=-0.4,6)
d$res_coded<-replace(d$res_coded,d$pred_res>=-0.1,5)
d$res_coded<-replace(d$res_coded,d$pred_res>=0,4)
d$res_coded<-replace(d$res_coded,d$pred_res>=0.1,3)
d$res_coded<-replace(d$res_coded,d$pred_res>=0.4,2)
d$res_coded<-replace(d$res_coded,d$pred_res>=1,1)

d %>% head

d$res_coded %>% head

d$res_coded = as.factor(d$res_coded)

ggmap(ggMapPrague, base_layer = ggplot(d, aes(x = lat, y = lon, fill = res_coded)),extent="device",legend = "topleft") + 
  geom_tile(alpha=0.5) +
  scale_fill_brewer(palette="RdYlGn",name="Residual",labels = c("[1;+inf)","[0.4;1)","[0.1;0.4)","[0;0.1)","[-0.1;0)","[-0.4;-0.1)","[-1;-0.4)","(-inf;-1)"))

Upvotes: 0

Views: 254

Answers (1)

Quar
Quar

Reputation: 1082

In addition to set base_layer = ggplot(aes(...), ...), one still needs to specify a geom (geometric object) layer, such as geom_point(aes(...)), geom_rect(aes(...)) or geom_polygon(aes(...)) appending to the ggmap(...), in order to have data used in base_layer mapped to visual effects.

For example,

+ geom_point(aes(x = lon, y = lat, color = res_coded)) +

demo1-orignal-legend

We can also remove the background grey square in legend keys for a better visual (IMO), by appending with:

+ theme(legend.key=element_blank())

Note: in your example, lat and lon should be swapped -- we usually have x = lon, y = lat. See the fixes in the following demo code.

Demo

demo-full

library(ggmap)
library(maptools)
library(ggplot2)


# map background
# bbox = c( left = min(lon), bottom = min(lat), right = max(lon), top = max(lat) )
bboxPrague <- c(14.22,49.94,14.71,50.18) 
ggMapPrague <- get_map(location = bboxPrague, source = "stamen",maptype = "toner", crop = TRUE, zoom = 12)
ggmap(ggMapPrague)

d = data.frame(
  pred_res = runif(2000, -50, 50),
  lat = runif(2000, 49.94, 50.18),
  lon = runif(2000, 14.22, 14.71)

)
d

#top&bottom coding and discreting pred_res....8
d$res_coded<-replace(d$pred_res,d$pred_res<(-1),8)
d$res_coded<-replace(d$res_coded,d$pred_res>=-1,7)
d$res_coded<-replace(d$res_coded,d$pred_res>=-0.4,6)
d$res_coded<-replace(d$res_coded,d$pred_res>=-0.1,5)
d$res_coded<-replace(d$res_coded,d$pred_res>=0,4)
d$res_coded<-replace(d$res_coded,d$pred_res>=0.1,3)
d$res_coded<-replace(d$res_coded,d$pred_res>=0.4,2)
d$res_coded<-replace(d$res_coded,d$pred_res>=1,1)

d %>% head

d$res_coded %>% head

d$res_coded = as.factor(d$res_coded)


ggmap(ggMapPrague, 
      base_layer = ggplot(d, aes(x = lon, y = lat)),
      extent="device",
      legend = "topleft") + 
  geom_point(aes(x = lon, y = lat, color = res_coded)) +
  scale_fill_brewer(
    palette="RdYlGn",
    name="Residual",
    labels = c("[1;+inf)","[0.4;1)","[0.1;0.4)",
               "[0;0.1)","[-0.1;0)","[-0.4;-0.1)",
               "[-1;-0.4)","(-inf;-1)")) +
  theme(legend.key=element_blank())

Issue with geom_tile

geom_tile draws rectangles specified by (center_x, center_y, width, height), when width and height are unspecified, they will be calculated as the minimum gap between two adjacent points, that is, width = min(abs(diff(df$x))) and height = min(abs(diff(df$y))). In your case, the width = min(abs(diff(d$lon))) ~ 0.0001525275 and height = min(abs(diff(d$lat))) ~ 3.292719e-05 (due to runif, actual value may vary a bit).

This kind of automation will cause problem given the example or GPS coordinates represents "raw points" rather than "center of each region", because the gap between two adjacent "raw points" can be too narrow to worth a pixel to draw. In this case, we will have to manually specify the width and height and bear in mind that the tiles will overlap.

Consider your example, with:

+ geom_tile(aes(fill=res_coded, height = 3E-3, width=3E-3))

# note that when `height` and `width` is small enough, 
# for example, 
#    `height = 3E-4, width=3E-3` will show horizontal lines along `width`
#    `height = 3E-3, width=3E-4` will show vertical lines along `height`
#    `height = 3E-4, width=3E-4` will show nothing (which is your case)

enter image description here

To further illustrate the automated width and height of geom_tile, consider the following simple example:

# library(ggpubr)
# library(ggplot2)

df1 <- data.frame(
  x = c(2, 5, 7, 9),
  y = c(1, 2, 1,  2),
  z = factor(1:4)
)

df2 <- data.frame(
  x = c(2, 5, 5.1, 9),
  y = c(1, 2, 1  ,  2),
  z = factor(1:4)
)

df3 <- data.frame(
  x = c(2, 5  , 7, 9),
  y = c(1, 1.1, 1, 2),
  z = factor(1:4)
)

df4 <- data.frame(
  x = c(2, 5  , 5.1, 9),
  y = c(1, 1.1, 1  , 2),
  z = factor(1:4)
)

ggarrange(
  ggplot(df1, aes(x, y)) + geom_tile(aes(fill = z)),
  ggplot(df2, aes(x, y)) + geom_tile(aes(fill = z)),
  ggplot(df3, aes(x, y)) + geom_tile(aes(fill = z)),
  ggplot(df4, aes(x, y)) + geom_tile(aes(fill = z)),
  labels = paste0("df", 1:4),
  ncol = 2, 
  nrow = 2
)

Therefore, it will be just simpler to use geom_point to visualize "raw GPS points".

enter image description here

Upvotes: 1

Related Questions