Although seemingly simple, this is actually a quite complex issue. I did some research and found out that you can achieve this by tweaking both size
and scale
arguments. However, if you are using ggmap
v3.0.0 as I do, you will find that specifying non-square dimensions just gives you a "noisy image" as follows:
base_map <- ggmap::get_googlemap(center = c(lon= -2.325278, lat=54.6000000), zoom = 5, size = c(331, 367), style = 'element:labels|visibility:off', color= "bw")
ggmap(base_map, extent = "panel")

This involves a known bug in the ggmap
package. It has not yet been resolved. Although there exists a solution as mentioned here, that only partially solves the problem because the solution has failed for some cases mentioned in this post. Hence, I'd suggest rewriting that function to make it work in a robust way. Luckily, after investigating the source code, I found the problem not so hard to deal with. The problem results from some image-processing failure in the get_goolemap
function. Therefore, outsourcing the image processing in that function to a dedicated package is a simple workaround.
Consider this get_googlemap2
(to make it simple, I have ignored all those argument checkings in the original get_goolemap
, so be careful with your inputs)
require(RgoogleMaps)
require(httr)
require(magick)
require(urltools)
require(tibble)
get_googlemap2 <- function(
api_key = "Your API Key",
center = c(lon = -95.3632715, lat = 29.7632836),
zoom = 10, size = c(640, 640), scale = 2,
maptype = c("terrain", "satellite", "roadmap", "hybrid"),
grayscale = FALSE, style
) {
maptype <- match.arg(maptype)
params <- c(
center = paste0(center[c(2L, 1L)], collapse = ","),
zoom = zoom,
size = paste0(size, collapse = "x"),
scale = scale,
maptype = maptype,
style = style,
key = api_key
)
url <- "https://maps.googleapis.com/maps/api/staticmap"
urltools::parameters(url) <- paste(names(params), params, sep = "=", collapse = "&")
url <- URLencode(url)
message("Souce: ", url)
img <- magick::image_read(httr::content(httr::GET(url)))
if (grayscale) img <- magick::image_quantize(img, colorspace = "gray")
ll <- RgoogleMaps::XY2LatLon(
list(lat = center[2], lon = center[1], zoom = zoom),
-size[1]/2 + 0.5, -size[2]/2 - 0.5
)
ur <- RgoogleMaps::XY2LatLon(
list(lat = center[2], lon = center[1], zoom = zoom),
size[1]/2 + 0.5, size[2]/2 - 0.5
)
structure(
as.raster(img), class = c("ggmap", "raster"),
source = "google", maptype = maptype, zoom = zoom,
bb = tibble::tibble(ll.lat = ll[1], ll.lon = ll[2], ur.lat = ur[1], ur.lon = ur[2])
)
}
I tried some specifications of size
and scale
with this new function and found out that the following specifications render the best map possible.
base_map <- get_googlemap2(
"Your API Key",
center = c(lon = -2.325278, lat = 54.6000000), zoom = 5, size = c(330, 380), scale = 2, style = 'element:labels|visibility:off', grayscale = TRUE
)
ggmap(base_map, extent = "panel")
Output

I hope this is what you want. I call this the best-possible result because if you attempt to further narrow the width, for example, down to 250, the attribution text will overlap with the logo.
base_map <- get_googlemap2(
"Your API Key",
center = c(lon = -2.325278, lat = 54.6000000), zoom = 5, size = c(250, 380), scale = 2, style = 'element:labels|visibility:off', grayscale = TRUE
)
ggmap(base_map, extent = "panel")

As far as I can tell, this is Google's problem, not ggmap
's. I have no way to solve it. Another workaround would be removing the attribution text from the image but reintroducing it as plain text within the content, as mentioned in Google's attribution guidlines. However, as Google's logo still needs to be there, you then have to figure out how to paste that onto the map. IMO, using plain text gives you greater flexibility in page layouts, and thus might be a better way to go.