When I save maps using tmap_save (with the default arguments), I get very different results (map size and font sizes (for title, scale bar, compass, etc.)) depending on whether I have first output a plot (any plot) into an R_X11 window or not.
For the plot size, this makes sense according to tmap_save's width argument:
If both width and height are not specified, then the width of the current plotting window will be taken.
But that creates a big reproducibility problem and I feel that, for the sake or reproducibility, there should be a fixed default size which does not depend on the user's window size and whether or not they have activated those values by outputting a plot.
The changes to the font sizes are harder to explain. According to the manuals of tm_layout, tm_compass, and tm_scale_bar, the size of text is "relative" (I am not sure to what. Map size?). But when running code without having output a map to a window, while I get smaller maps, the text is larger.
Here is an example:
If I have ever plotted anything in an R session (not necessarily that particular plot), I get:

But if I rerun the exact same code during another session while having never plotted anything during that session, I get:

The plot is slightly smaller and all the fonts are much larger.
I am on Linux and maybe this is a bug due to some settings in my system (at least for the font size). But the manual for tmap_save (for the width argument) does suggest that, unless the width is specified, the code will output different maps on different systems. If that is the case (if I am understanding things correctly), then maybe width should have a numerical default value (for reproducibility), and be able to accept either numerical values for custom sizes or the value window to use what is currently the default.
Sorry for not providing a reproducible example. If it proves necessary, I can try to create one using a data package.
Thanks!
Edit: It is not whether or not I have ever plotted anything during a session that matters, it is whether or not I have a plot (any plot) in an R_X11 window while running the code that matters.
Setting the width and height arguments of tmap_save() solves the font size issue (as well as the plot size issue of course) and makes the code reproducible, regardless of whether there is an active plot window or not. So the problem is the defaults for width and height in tmap_save() which depend on non-code related environment (the presence of an active window and its size). I think that changing those defaults to some common window size would be good.
I cannot exactly reproduce the procedure, but kind of understand your point.
tmap_save and tmap_arrange use par("din") for the defaults. Note that the object sizes (so font sizes, line widths etc) are fixed some defaults (e.g. points per inch). This means that in a 3 x 3 inch map, the title appears much larger than in a 12 x 12 inch map. These sizes probably also depend on the OS.
We could set the defaults of the width and height to 7 inch (I think ggplot uses this). What do you think?
Note that the object sizes (so font sizes, line widths etc) are fixed some defaults (e.g. points per inch). This means that in a 3 x 3 inch map, the title appears much larger than in a 12 x 12 inch map.
I see. That makes sense. What I did not understand was the size of text is "relative" in the tmap_save() man page. It wasn't clear to me "relative" to what and what that meant.
As a workaround, to be able to run my code without having to make sure I had an active plot window each time, I set the dimensions of all my plots to what they automatically end up being with a window plot active on my computer. In my particular system, those dimensions are 9.989583, 10.46205, "in" (so 7 x 7 seems small).
I looked at the ggsave() defaults (from ggplot2) and it is having the exact same behaviour as tmap_save() :stuck_out_tongue: From the ggsave() man:
width, height, units: Plot size in units ("in", "cm", or "mm"). If not supplied, uses the size of current graphics device.
So what you did seems to actually be quite common and I guess ggsave() is also using par("din").
Maybe it does work for most people in most systems and my system is odd to have this reproducibility problem while plotting? So maybe you shouldn't change anything??? I use ggplot2 all the time though and never noticed any such issue with ggsave(), while with tmap_save() I absolutely have to set some defaults. I am not sure why the difference... Maybe ggsave() is able to get the "current graphics device" size even if it is not active????
Personally, I feel that a hard-set default would be best (including for ggsave()), to make sure code is fully reproducible and not system-dependent. But if things work ok for most systems, then maybe it is fine as it is??
I actually used ggplot2::ggsave as example, but changed some things to make to improve it (in my opinion), e.g. the scale parameter.
Any opinions on this matter, e.g. from @Robinlovelace @Nowosad @jannes-m ?
I actually used ggplot2::ggsave as example
Right, looking at the ggsave() defaults, that makes sense. Maybe we should include Hadley Wickham et al. on this discussion. Maybe they have good arguments to defend these defaults in reply to my reproducibility concerns. Maybe I could open an issue on the ggplot2 repo with a link to this one?
We could set the defaults of the width and height to 7 inch (I think ggplot uses this).
You are right that the ggplot2 default is 7 x 7 but only if no graphic device is open. This was implemented in https://github.com/tidyverse/ggplot2/commit/5fdb48aabef6cc23467720ddd551b9b3730567d9 as a fix for https://github.com/tidyverse/ggplot2/issues/1326.
I still think that 7 x 7 is a bit small, but I guess that is a very personal question. And I still feel that having the graphic device take precedence by default is not great as it forces the user to set dimension values to ensure reproducibility.
(Also see comment about grDevices::dev.size() vs par("din") in that commit.)
Thanks. I've used dev.size() now, instead of par("din").
I am happy to convert to a default size, rather than the device size, if that makes sense?
7 by 7 inch is ok regarding size. Note that for bitmaps, the dpi is set to 300, so that would result in 2100 by 2100 pixels.
However, there is the aspect ratio as well. A square would work, but for some maps, e.g. of the world, halve of the image will be blank. Another strategy would be to set a default size for the longest edge (so either the height of width). The size of the other edge is calculated based on the estimated aspect ratio.
So we have the following options:
Which one to you prefer? (Also asking the others...)
Personally, I prefer option 4:
I guess it probably also is the hardest option to implement :stuck_out_tongue:
I've implemented option 5 ;-)
I've added three options: output.format, output.dpi, and output.size. The first two are respectively png and 300 by default.
Output.size is the area size of the map in inch^2. By default, it is 49. So a square map, will be saved as 7x7 inch and a 2x1 map (e.g. a world map) as approximately 9.8 * 5.
The idea behind is that with option 4, a landscape or portrait map will be much larger than a square map.
Btw, is was surprisingly easy to implement (since I already had some reusable code).
Please reopen this issue if needed.
This is great! Thank you so much @mtennekes for all your work and for being so responsive to suggestions!!!
Most helpful comment
I've implemented option 5 ;-)
I've added three options: output.format, output.dpi, and output.size. The first two are respectively
pngand300by default.Output.size is the area size of the map in inch^2. By default, it is 49. So a square map, will be saved as 7x7 inch and a 2x1 map (e.g. a world map) as approximately 9.8 * 5.
The idea behind is that with option 4, a landscape or portrait map will be much larger than a square map.
Btw, is was surprisingly easy to implement (since I already had some reusable code).
Please reopen this issue if needed.