tmap icon indicating copy to clipboard operation
tmap copied to clipboard

tm_basemap: small issues

Open mtennekes opened this issue 3 years ago • 5 comments

tm_basemap is working in plot mode, Thanks to the maptiles package @rCarto

image

image

(taken from https://github.com/r-tmap/tmap/blob/v4/tests/testing_aux_layers.Rmd)

A few minor issues:

  • maptiles::get_tiles takes a few seconds to run, even when repeating the same code. I thought tiles were cached? My guess is that most running time is not the downloading of tiles, but processing them (i.e. stacking and cutting into the requested bounding box). We could cache the (processed) basemaps in tmap ourselves. We could do this the following way: for every unique (server, bounding box) combination for which tm_basemap is called, we can save the basemap (a SpatRaster) with saveRDS to the temp dir. Or, alternatively, but perhaps less preferable, we could store the SpatRaster in the .TMAP environment.

  • Most (important) map tile servers are supported by both maptiles and leaflet.providers natively, but there are differences:

prov_maptiles = names(maptiles:::maptiles_providers)
prov_leaflet = names(leaflet::providers)

# providers in leaflet which are not supported by maptiles
setdiff(prov_leaflet, prov_maptiles)
#>   [1] "OpenStreetMap.Mapnik"               
#>   [2] "OpenStreetMap.CH"                   
#>   [3] "OpenStreetMap.BZH"                  
#>   [4] "OpenSeaMap"                         
#>   [5] "OpenPtMap"                          
#>   [6] "OpenRailwayMap"                     
#>   [7] "OpenFireMap"                        
#>   [8] "SafeCast"                           
#>   [9] "Thunderforest"                      
#>  [10] "OpenMapSurfer"                      
#> ... 
#> [120] "OneMapSG.LandLot"

# providers in maptiles which are not supported by leaflet
setdiff(prov_maptiles, prov_leaflet)
#> [1] "OpenStreetMap.MapnikBW" "OpenStreetMap.NoLabels"

What do we do with these (to have consistency between plot and view mode)?

  • Sharpness: the basemaps are not very sharp. This is primarily caused by the fact that the map size of the graphics device does not necessarily match the size of the SpatRaster image. For other raster objects (such as satellite images) this is less important, because these usually have a much higher resolution. Is there any trick we can do to improve this?

tm_basemap also works when the main shape is projected. In that case, the SpatRaster is projected to one that is twice as large (in order to make sure it remains as sharp as possible with method = "near"):

tm_shape(NLD_prov) +
	tm_basemap("OpenStreetMap") +
	tm_borders()

image

tm_shape(NLD_prov, crs = 4326) +
	tm_basemap("OpenStreetMap") +
	tm_borders()

image

mtennekes avatar Oct 03 '21 21:10 mtennekes

Hi @mtennekes , That's nice to see maptiles used in tmap! A few comments on these issues :

  • cache The cache in maptiles is only used to avoid repeated tiles downloads. It would be possible to add full caching within maptiles directly, I'll think about it. Note that saving SpatRaster objects is a bit more convoluted than just using saveRDS() (see https://github.com/rspatial/terra/issues/50 and terra::wrap())
  • providers maptiles uses a custom providers list. I should probably use the leaflet.providers package more directly. It would solve this issue.
  • sharpness In the last version of maptiles I have introduced a new adjust argument to plot_tiles() to display tiles in the graphic device without zoom-in or zoom-out. The size of the resulting map is constrained, it can be a bit small or cut. I don't know enough of tmap internals to know if this can be useful.
library(sf)
#> Linking to GEOS 3.9.0, GDAL 3.2.2, PROJ 7.1.0
library(maptiles)
nc_raw <- st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
nc <- st_transform(nc_raw, 3857)
nc_osm <- get_tiles(nc, zoom = 5)
# too large
plot_tiles(nc_osm, adjust = FALSE)

# a bit small
plot_tiles(nc_osm, adjust = TRUE)

nc_osm <- get_tiles(nc, zoom = 8)
# not sharp
plot_tiles(nc_osm, adjust = FALSE)

# cut
plot_tiles(nc_osm, adjust = TRUE)

Created on 2021-10-20 by the reprex package (v2.0.1)

rCarto avatar Oct 20 '21 07:10 rCarto

tm_basemap() is not working for me in plot mode; is it meant to be working or is it for v4?

It just produces a blank white plot.

library(tmap)
data("NLD_prov")
tm_shape(NLD_prov) +
  tm_basemap("OpenStreetMap") +
  tm_borders()

image

natereal avatar Jan 30 '22 01:01 natereal

See the last example at https://r-tmap.github.io/tmap-book/layers.html#tile on how to add a tile map in the plot mode.

Nowosad avatar Jan 30 '22 09:01 Nowosad

Thank you for that. I have already seen that example and was wondering if the example in this thread would work.

I suppose there is no difference between the methods, but the resolution on that example isn't great, the text appears very blurry, and increasing the zoom level argument makes all the text smaller. If a similar method to the adjust argument in maptiles::plot_tiles() could be used in tm_rgb / tm_basemap, that would be very useful as the quality on the output of plot_tiles is much better

natereal avatar Jan 30 '22 17:01 natereal

The adjust argument of maptiles::plot_tiles() does nothing directly to improve the sharpness. It only makes sure that the tiles are plotted in native resolution (so 1 cell is 1 pixel).

For tmap, this would mean that the overall plot would have a different size and layout, which also depends on the used graphics device.

mtennekes avatar Feb 01 '22 14:02 mtennekes

Hi guys, thank you first of all for this great package that works just like a traditional gis program, adding multiple layers! My only point is that...I cannot figure out how you use tm_basemap with plotting. Yo usay it's supported, but can you provide an example os use? When I try a very simple one like: basem <- tm_basemap("OpenStreetMap")+ tm_shape(pnts_sf, bbox=ext)+ tm_dots()

I get an empty white map with only dots.

I also tried to download maps using maptiler, and then using them as basemaps, and this works. But in this case is like downloading a tile independently and then using it inside tmap. Another problem I have is that stamen maps, that I've always uses, in maptiler package are downloaded at a very low resolution, which is just too low for producing any illustration. Do you have a cue on this?

r-poloni avatar Sep 16 '23 10:09 r-poloni

I cannot reproduce the issue using available data:

library(spData)
library(sf)
#> Linking to GEOS 3.11.1, GDAL 3.6.4, PROJ 9.1.1; sf_use_s2() is TRUE
library(tmap)

# works
tm_shape(nz_height) +
        tm_basemap("OpenStreetMap") +
        tm_dots()
#> Loading required namespace: maptiles


# also works
tm_basemap("OpenStreetMap") +
        tm_shape(nz_height) +
        tm_dots()


# also works
tm_shape(nz_height, bbox = st_bbox(nz_height)) +
        tm_basemap("OpenStreetMap") +
        tm_dots()

Created on 2023-09-16 with reprex v2.0.2

Nowosad avatar Sep 16 '23 15:09 Nowosad

I couldn't figure why, I tried to run exactly your same code but in my case also the example code is always giving me a blank map with points. The version is 3.3-4, so it should be the good one. I don't know why...

> library(spData) To access larger datasets in this package, install the spDataLarge package with: install.packages('spDataLarge', repos='https://nowosad.github.io/drat/', type='source')`

library(sf) Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 8.2.1; sf_use_s2() is TRUE library(tmap) tm_basemap("OpenStreetMap") +

  • tm_shape(nz_height) +
  • tm_dots()`

r-poloni avatar Sep 16 '23 16:09 r-poloni

Hi @r-poloni -- I am using version 4 -- the current development version of Github (this feature was not available in the previous version)

Nowosad avatar Sep 16 '23 16:09 Nowosad

Hi Jakob! Thank you again for the answer. Damn...I completely overlooked that thing. It's not marked that the development is v.4 so I kind of thought that it was actually v. 3.3-4. Apologies for increasing universe's entropy!

r-poloni avatar Sep 16 '23 16:09 r-poloni

No problem.

Nowosad avatar Sep 16 '23 16:09 Nowosad

Hello @mtennekes , The processed basemaps are cached now in maptiles (Gihub version).

Before:

library(sf)
#> Linking to GEOS 3.11.1, GDAL 3.6.2, PROJ 9.1.1; sf_use_s2() is TRUE
library(maptiles)
library(tictoc)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
tic()
map1 <- get_tiles(nc, zoom = 9, provider = "CartoDB.Voyager",
                  cachedir = "/home/tim/cache", crop = TRUE, 
                  verbose = TRUE)
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/136/200.png => /home/tim/cache/CartoV/CartoV_9_136_200.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/137/200.png => /home/tim/cache/CartoV/CartoV_9_137_200.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/138/200.png => /home/tim/cache/CartoV/CartoV_9_138_200.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/139/200.png => /home/tim/cache/CartoV/CartoV_9_139_200.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/140/200.png => /home/tim/cache/CartoV/CartoV_9_140_200.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/141/200.png => /home/tim/cache/CartoV/CartoV_9_141_200.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/142/200.png => /home/tim/cache/CartoV/CartoV_9_142_200.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/143/200.png => /home/tim/cache/CartoV/CartoV_9_143_200.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/144/200.png => /home/tim/cache/CartoV/CartoV_9_144_200.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/145/200.png => /home/tim/cache/CartoV/CartoV_9_145_200.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/146/200.png => /home/tim/cache/CartoV/CartoV_9_146_200.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/147/200.png => /home/tim/cache/CartoV/CartoV_9_147_200.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/148/200.png => /home/tim/cache/CartoV/CartoV_9_148_200.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/136/201.png => /home/tim/cache/CartoV/CartoV_9_136_201.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/137/201.png => /home/tim/cache/CartoV/CartoV_9_137_201.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/138/201.png => /home/tim/cache/CartoV/CartoV_9_138_201.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/139/201.png => /home/tim/cache/CartoV/CartoV_9_139_201.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/140/201.png => /home/tim/cache/CartoV/CartoV_9_140_201.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/141/201.png => /home/tim/cache/CartoV/CartoV_9_141_201.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/142/201.png => /home/tim/cache/CartoV/CartoV_9_142_201.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/143/201.png => /home/tim/cache/CartoV/CartoV_9_143_201.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/144/201.png => /home/tim/cache/CartoV/CartoV_9_144_201.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/145/201.png => /home/tim/cache/CartoV/CartoV_9_145_201.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/146/201.png => /home/tim/cache/CartoV/CartoV_9_146_201.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/147/201.png => /home/tim/cache/CartoV/CartoV_9_147_201.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/148/201.png => /home/tim/cache/CartoV/CartoV_9_148_201.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/136/202.png => /home/tim/cache/CartoV/CartoV_9_136_202.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/137/202.png => /home/tim/cache/CartoV/CartoV_9_137_202.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/138/202.png => /home/tim/cache/CartoV/CartoV_9_138_202.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/139/202.png => /home/tim/cache/CartoV/CartoV_9_139_202.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/140/202.png => /home/tim/cache/CartoV/CartoV_9_140_202.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/141/202.png => /home/tim/cache/CartoV/CartoV_9_141_202.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/142/202.png => /home/tim/cache/CartoV/CartoV_9_142_202.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/143/202.png => /home/tim/cache/CartoV/CartoV_9_143_202.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/144/202.png => /home/tim/cache/CartoV/CartoV_9_144_202.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/145/202.png => /home/tim/cache/CartoV/CartoV_9_145_202.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/146/202.png => /home/tim/cache/CartoV/CartoV_9_146_202.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/147/202.png => /home/tim/cache/CartoV/CartoV_9_147_202.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/148/202.png => /home/tim/cache/CartoV/CartoV_9_148_202.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/136/203.png => /home/tim/cache/CartoV/CartoV_9_136_203.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/137/203.png => /home/tim/cache/CartoV/CartoV_9_137_203.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/138/203.png => /home/tim/cache/CartoV/CartoV_9_138_203.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/139/203.png => /home/tim/cache/CartoV/CartoV_9_139_203.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/140/203.png => /home/tim/cache/CartoV/CartoV_9_140_203.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/141/203.png => /home/tim/cache/CartoV/CartoV_9_141_203.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/142/203.png => /home/tim/cache/CartoV/CartoV_9_142_203.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/143/203.png => /home/tim/cache/CartoV/CartoV_9_143_203.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/144/203.png => /home/tim/cache/CartoV/CartoV_9_144_203.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/145/203.png => /home/tim/cache/CartoV/CartoV_9_145_203.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/146/203.png => /home/tim/cache/CartoV/CartoV_9_146_203.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/147/203.png => /home/tim/cache/CartoV/CartoV_9_147_203.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/148/203.png => /home/tim/cache/CartoV/CartoV_9_148_203.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/136/204.png => /home/tim/cache/CartoV/CartoV_9_136_204.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/137/204.png => /home/tim/cache/CartoV/CartoV_9_137_204.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/138/204.png => /home/tim/cache/CartoV/CartoV_9_138_204.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/139/204.png => /home/tim/cache/CartoV/CartoV_9_139_204.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/140/204.png => /home/tim/cache/CartoV/CartoV_9_140_204.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/141/204.png => /home/tim/cache/CartoV/CartoV_9_141_204.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/142/204.png => /home/tim/cache/CartoV/CartoV_9_142_204.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/143/204.png => /home/tim/cache/CartoV/CartoV_9_143_204.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/144/204.png => /home/tim/cache/CartoV/CartoV_9_144_204.png
#> https://a.basemaps.cartocdn.com/rastertiles/voyager/9/145/204.png => /home/tim/cache/CartoV/CartoV_9_145_204.png
#> https://c.basemaps.cartocdn.com/rastertiles/voyager/9/146/204.png => /home/tim/cache/CartoV/CartoV_9_146_204.png
#> https://d.basemaps.cartocdn.com/rastertiles/voyager/9/147/204.png => /home/tim/cache/CartoV/CartoV_9_147_204.png
#> https://b.basemaps.cartocdn.com/rastertiles/voyager/9/148/204.png => /home/tim/cache/CartoV/CartoV_9_148_204.png
#> Zoom:9
#> Data and map tiles sources:
#> © OpenStreetMap contributors © CARTO
toc()
#> 4.11 sec elapsed
tic()
map2 <- get_tiles(nc, zoom = 9, provider = "CartoDB.Voyager",
                  cachedir = "/home/tim/cache", crop = TRUE, 
                  verbose = TRUE)
#> Zoom:9
#> Data and map tiles sources:
#> © OpenStreetMap contributors © CARTO
toc()
#> 2.562 sec elapsed

Now:

library(sf)
#> Linking to GEOS 3.11.1, GDAL 3.6.2, PROJ 9.1.1; sf_use_s2() is TRUE
library(maptiles)
library(tictoc)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
tic()
map1 <- get_tiles(nc, zoom = 9, provider = "CartoDB.Voyager",
                  cachedir = "/home/tim/cache", crop = TRUE, 
                  verbose = TRUE)
#> Zoom: 9
#> Source(s): © OpenStreetMap contributors © CARTO
#> Cache directory: /home/tim/cache/CartoV
#> 65 tiles
toc()
#> 3.963 sec elapsed
tic()
map2 <- get_tiles(nc, zoom = 9, provider = "CartoDB.Voyager",
                  cachedir = "/home/tim/cache", crop = TRUE, 
                  verbose = TRUE)
#> Zoom: 9
#> Source(s): © OpenStreetMap contributors © CARTO
#> Cache directory: /home/tim/cache/CartoV
#> The resulting raster is a previously cached raster.
toc()
#> 0.022 sec elapsed

Created on 2023-12-19 with reprex v2.0.2

rCarto avatar Dec 19 '23 16:12 rCarto