Open mtennekes opened 1 year ago
I am leaning toward option 4 (my thinking is that the tm_basemap is somewhat similar to tm_graticules), but I also think that option 3 makes a lot of sense.
After a quick nap, I like option 3 better. IT seems to be more consistent with the rest of the tmap code.
Great to see what naps can do, not just with the little ones among us:-)
I also thought of a new option:
tm_map
where crs, bbox, and zoom levels (min, max and current) are determined. In that case, tm_shape
will only be used to specify the spatial object, and optionally is.main
in case there are multiple objects with different bboxes. In case tm_map
is not called, the map properties are extracted from the main shape. In case tm_map
is used, it will determine the properties of the produced map.Still have to think about the pros and cons, but so far:
Pro:
tm_map
is supposed to be called once per map (in case there are multiple, the latest values are taken, just like tm_layout(bg.color = "red') + tm_layout(bg.color = "blue")
will ultimately result in a blue background color. )tm_shape
call, to specify the bounding box.Cons:
tm_map
may be confusing, since tm
already stands for thematic map, and the "mapping" is also used to distinguish visual variables from transformation variables.tm_shape() + tm_map()
stack in case tm_shape(box = )
is used.I think tm_map()
would add unnecessary complexity (for the users point of view) for fairly small benefits.
No strong opinions but from a quick read
tm_shape(bbox = "Amsterdam") + tm_basemap()
Sounds logical to me.
For now I went with the tm_shape
option, but in essence (and implementation wise) a tm_shape
call without shape is still a tm_options
call. That means that:
tm_basemap() + tm_shape(bbox = "Amsterdam")
also works. And also without tm_basemap
:
tm_shape(World) + tm_polygons() + tm_shape(bbox = "Amsterdam")
We could prevent this to bahavior, and make tm_shape 'connected' to tm_basemap, but then we run into a new problem with a common situation, namely where you are in view mode and do not explicitly call tm_basemap
.
So, I am okay with this choice, but from a purely conceptually point of view, I'd like tm_map
better. However, I also increase with Jakub that it may add complexity (and confusion) to some users.
Furthermore, while implementing this, I encountered two other related issues:
tm_basemap
. This was already implemented a while ago. The only purpose is to decide on which zoom level to render the tiles in plot mode. However, this could clash with the zoom level set via tm_shape
(or tm_map
), which is via the argument set.view
(see next issue about the naming). For now, I applied this simple rule: if the zoom level is specified in tm_basemap
, and not in tm_shape
(or tm_map
), use that.tm_view
that determine the map view: set.bounds
, set.view
and set.zoom.limits
. The input specifications and the names are directly taken from the upstream leaflet functions (though the names are in camel case). Problem: I don't find these user friendly. I'd rather change set.view
to zoom
. Via set.view
you can also set the center point in lat/lon coordinates, but this also follows from the bounding box. Furthermore, set.zoom.limits
can be changed to zoom.limits
, and set.bounds
probably can be changed to bound
(logical that determined whether to bound the map or not.Ideas / opinions?
So a tm_shape()
call with no spatial object creates a map with only a basemap?
I do think having a tm_basemap()
function is useful, if only to know where to put basemap argument like starting zoom, max zoom, etc that can feed into the interactive mapping functions below.
I agree that the zoom level in tm_basemap()
should take precedence.
Regarding 2, I agree they are not particularly intuitive. Could those updated argument names go into tm_basemap()
and tm_view
(which implies tm_basemap()
, no?) be deprecated?
Re. 3 I think getting it working from currently working interactive mode and then iterate and ask others to implement for other interactive back-ends is reasonable.
Just my quickfire thoughts after quick read, hope useful.
Thx Robin, certainly useful!
So a
tm_shape()
call with no spatial object creates a map with only a basemap?
In view mode, yes, but in plot mode nothing happens except the message "Nothing to show". This is because basemap(s) are by default added in view mode, but not in plot mode.
In essence, tm_shape
without spatial object is just setting tmap options (just like tm_options
/ tm_layout
). At least, in the current implementation, which we are reconsidering in this discussion.
I do think having a
tm_basemap()
function is useful, if only to know where to put basemap argument like starting zoom, max zoom, etc that can feed into the interactive mapping functions below.I agree that the zoom level in
tm_basemap()
should take precedence.Regarding 2, I agree they are not particularly intuitive. Could those updated argument names go into
tm_basemap()
andtm_view
(which impliestm_basemap()
, no?) be deprecated?
Yes, tm_basemap()
is definitely useful, especially for choosing the tile server. We can specify the starting/min/max zoom in tm_basemap
, but these zoom levels are also relevant for interactive maps without basemap. So that could make things a bit confusing, because then you would have to do something like tm_basemap(server = NULL, zoom = 9, zoom.max = 12)
Re. 3 I think getting it working from currently working interactive mode and then iterate and ask others to implement for other interactive back-ends is reasonable.
Yes, true. The point is, if we can guess a little bit ahead what would be required, we can already anticipate, so that we don't have to change the user interface (function/arguments) after tmap4 is on cran.
How should users be able to set the specs, like crs, bbox, zoom level, etc. for shapeless maps, by which I mean maps without using 'shape' objects (sf,stars,terra )?
So far, the only example I could think of is a basemap without additional data layers:
Few options:
tm_view
andtm_plot
. This is the same behaviour as in tmap3.tm_plot
is new, and added to allow plot-mode specific options.tm_shape(bbox = "Amsterdam") + tm_basemap()
tm_basemap
layer itself, as layer-specific properties.What are your thoughts/options/ideas? (@Nowosad @Robinlovelace others)