16EAGLE / basemaps

A lightweight package for accessing basemaps from open sources in R 🗺️
https://jakob.schwalb-willmann.de/basemaps
GNU General Public License v3.0
57 stars 15 forks source link

Hangs while printing plot using basemap_gglayer() #10

Closed benscarlson closed 1 year ago

benscarlson commented 2 years ago

Thanks for the very promising package!

I've found that whenever I try to print a ggplot object that is created using basemap_gglayer, R hangs. However, basemap_ggplot works just fine.

library(tidyverse)
library(sf)
library(basemaps)

p1 = st_point(c(19.040767, 47.540033))
p2 = st_point(c(19.065183, 47.541033))
p3 = st_point(c(19.047933, 47.509817))
p4 = st_point(c(19.029983, 47.512850))
l1 = st_sfc(st_linestring(c(p1, p2)))
l2 = st_sfc(st_linestring(c(p2, p3)))
l3 = st_sfc(st_linestring(c(p3, p4)))
l4 = st_sfc(st_linestring(c(p4, p1)))

bp_margit <- st_as_sf(c(l1, l2, l3, l4), crs = 4326) %>% st_transform(crs=3857)

p1 <- basemap_ggplot(bp_margit,map_service = "esri", map_type = "world_street_map")

print(p1) #Works!

p2 <- ggplot() + 
  basemap_gglayer(bp_margit,map_service = "esri", map_type = "world_street_map")

print(p2) #Hangs

Any idea what is going on? I'm using R: 4.2.1, ggplot2: 3.3.6, sf: 1.0-7

16EAGLE commented 2 years ago

The returned layer consists of hexadecimal colour codes (character), as basemaps converts RGB values into colours before plotting: https://github.com/16EAGLE/basemaps/blob/21daaa5b5f4b403bab40c9fe355759114fbbc207/R/internal.R#L120

By default, ggplot2 tries to plot characters with a discrete scale. Use scale_fill_identity to let ggplot2 interpret the layer values as colours. This should work:

library(ggplot2)
library(sf)
library(basemaps)

p1 = st_point(c(19.040767, 47.540033))
p2 = st_point(c(19.065183, 47.541033))
p3 = st_point(c(19.047933, 47.509817))
p4 = st_point(c(19.029983, 47.512850))
l1 = st_sfc(st_linestring(c(p1, p2)))
l2 = st_sfc(st_linestring(c(p2, p3)))
l3 = st_sfc(st_linestring(c(p3, p4)))
l4 = st_sfc(st_linestring(c(p4, p1)))

bp_margit <- st_as_sf(c(l1, l2, l3, l4), crs = 4326) %>% st_transform(crs=3857)

ggplot() + 
  basemap_gglayer(bp_margit,map_service = "esri", map_type = "world_street_map") +
  scale_fill_identity() + 
  coord_sf()
benscarlson commented 1 year ago

Thank you, I tested this approach and it works!

If I understand correctly, one potential issue with this approach is that now I can't add another layer that uses the "fill" aesthetic. So, if I wanted to add, say geom_sf(data=myPointDat,aes(fill=date),shape=21), this would not be straight-forward because the fill aesthetic is already set to identity.

A work around might be to manually figure out the color ramp and assign the hexadecimal colors to the myPointDat. But this does not seem very user-friendly! I don't know what a potential solution might be, but I don't believe I've ever run into this problem when using ggmap.

16EAGLE commented 1 year ago

You are completely right – without tweaks, this solution occupies fill with the identity scale (maybe there is a smarter way of adding the basemap to ggplot2). However, you could overcome this by adding a new scale, e.g. using ggnewscale. Here a quick reprex:

library(basemaps)
library(sf)
library(ggplot2)
library(ggnewscale)

# default extent
data(ext)

# some dummy points with a continuous variable
df <- st_as_sf(data.frame(
  x = seq(from = 1226000, to = 1236000, length.out = 10),
  y = seq(from = 6034000, to = 6044000, length.out = 10),
  rnorm = rnorm(10)
), coords = 1:2, crs = st_crs(3857))

# plot basemap (fill used 1st time with idendity)
ggplot() + 
  basemap_gglayer(ext, map_service = "osm", map_type = "topographic") +
  scale_fill_identity() + 
  new_scale_fill() + # make way for a new fill scale
  # plot another layer, not with identity, but another fill scale
  geom_sf(data = df, shape = 21, size = 8, aes(fill = rnorm)) +
  scale_fill_continuous() +
  coord_sf()

Will think about whether this is user-friendly or to rather make basemaps render the map in another way than using scale_fill_identity.

Created on 2022-09-26 with reprex v2.0.2

16EAGLE commented 1 year ago

Closing this due to inactivity. Commend and/or reopen if issue could not be solved adequately.