Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tm_scalebar width calculation #919

Open
rhurlin opened this issue Aug 22, 2024 · 8 comments
Open

tm_scalebar width calculation #919

rhurlin opened this issue Aug 22, 2024 · 8 comments

Comments

@rhurlin
Copy link

rhurlin commented Aug 22, 2024

In the current v3.99.9002, the examples for arranging tm_scalebar no longer work as expected for me. E.g. in the first example from #747:

tm_scalebar(c(0, 200, 400), position = c(“right”, “bottom”)) positions bottom left instead of bottom right.

The positioning obviously only works if no other parameters such as breaks= or width= are used.

In addition, width does not seem to have any influence on the scaling, e.g. with breaks = seq(0,1000,200) the length of the scale cannot be changed with width = 600 or width = 1200.

@Nowosad Nowosad added the bug label Aug 22, 2024
mtennekes added a commit that referenced this issue Aug 24, 2024
@mtennekes
Copy link
Member

Thanks, should be fixed now. Please check if it works as expected, and reopen if necessary.

@rhurlin
Copy link
Author

rhurlin commented Aug 24, 2024

@mtennekes, it works much better now. Many thanks!

I would like to express two wishes for the long-term improvement of tm_scalebar:

  • The distance of the scalebar from the right edge of the map with pos.h=“right” is a bit large. This is particularly noticeable when the scalebar is integrated into a legend on the right (both with pos.h=“right”);
  • text.size only works very roughly for tm_scalebar (e.g. 0.5, 1.0 work);

For presentations and reports, I like to work with tmap-generated visualizations. These are very appealing to many viewers.
That's why I'm already looking forward to an official release of version 4 :D

mtennekes added a commit that referenced this issue Aug 24, 2024
@mtennekes
Copy link
Member

Thx!

  • Checkout last commit: the RHS-margin should be much smaller now. A bit trial and error: In case the last break is not printed anymore, these margin should be increased again.
  • text.size should work with any continuous size. For me 0.7, 0.8 etc. worked. Otherwise, please share some examples

@mtennekes mtennekes reopened this Aug 24, 2024
@mtennekes mtennekes changed the title tmap4: tm_scalebar does not work as expectect with tmap_3.99.9002 tm_scalebar width calculation Aug 24, 2024
@rhurlin
Copy link
Author

rhurlin commented Aug 24, 2024

The distance of the scalebar to the right is now better, but rather too small. This becomes clear, for example, when tm_scalebar is used within a legend and the scalebar is wider than the legend text. In the example, the unit “km” already touches the right edge of the legend box:

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

f = system.file("shapes/world.gpkg", package = "spData")
tanzania = read_sf(f, query = 'SELECT * FROM world WHERE name_long = "Tanzania"')
tanzania_buf = st_buffer(tanzania, 50000)
tanzania_buf_geom = st_geometry(tanzania_buf)
tanzania_buf_wkt = st_as_text(tanzania_buf_geom)
tanzania_neigh = read_sf(f, wkt_filter = tanzania_buf_wkt)

# works fine
tm_shape(tanzania_neigh) +
  tm_polygons() +
  tm_text(text = "name_long",
          text.scale = tm_scale(auto.placement = FALSE, remove.overlap = FALSE), 
          size = "AREA", size.legend = tm_legend_hide()) +
  tm_shape(tanzania_buf) +
  tm_polygons(col = "red", fill = "red", fill_alpha = 0.05) +
  tm_add_legend(type = "polygons", labels = "50km buffer around Tanzania",
                col = "red", fill_alpha = 0.1, fill = "red", position = c("left","bottom"))  +
  tm_scalebar(seq(0, 1000, 200), position = c("left", "bottom"), text.size = 0.6)

Other distances are also not yet ideal, here for example the distance between legend entries and the scalebar. But you can already work with it ;)

The text.size of the scalebar works as desired in the example shown here. Apparently my other code is more complex, so it doesn't scale there for other reasons? I'll look into this more thoroughly and come back to it if necessary.

Thanks again for the very quick and competent help and the patches :D

mtennekes added a commit that referenced this issue Aug 24, 2024
@mtennekes
Copy link
Member

You're welcome. Thx for the example. Three update in latest commit:

  1. Label width/margin computation further improved. Looks perfect on my machine now. Let me know if it doesn't on your system.
  2. Another thing that I changed, is the use of the "width" argument. Now, if breaks are specified, width can still be used for finetuning.
  3. If the last labels doen't fit, but the scale bar does, this last label is removed, but the unit is printed after the second-last label. This only applies when breaks are not specified.

@rhurlin
Copy link
Author

rhurlin commented Aug 25, 2024

  1. Label width/margin computation further improved. Looks perfect on my machine now. Let me know if it doesn't on your system.
  1. Another thing that I changed, is the use of the "width" argument. Now, if breaks are specified, width can still be used for finetuning.

I'm afraid I don't understand the use of width properly now. I have always specified the maximum value that the scalebar should use. If I do this now, it has unpredictable effects for me. If I use the scalebar separately from the legend, width changes the position of the scalebar. If width is used within the legend, the legend is set to maximum width.

Here are some examples, derived from the example above:

# works fine
tm_shape(tanzania_neigh) +
  tm_polygons() +
  tm_text(text = "name_long",
          text.scale = tm_scale(auto.placement = FALSE, remove.overlap = FALSE), 
          size = "AREA", size.legend = tm_legend_hide()) +
  tm_shape(tanzania_buf) +
  tm_polygons(col = "red", fill = "red", fill_alpha = 0.05) +
  tm_add_legend(type = "polygons", labels = "50km buffer around Tanzania",
                col = "red", fill_alpha = 0.1, fill = "red", position = c("left","bottom"))  +
  tm_scalebar(seq(0, 1000, 200), position = c("left", "bottom"), text.size = 0.6)
# box of the legend too wide
tm_shape(tanzania_neigh) +
  tm_polygons() +
  tm_text(text = "name_long",
          text.scale = tm_scale(auto.placement = FALSE, remove.overlap = FALSE), 
          size = "AREA", size.legend = tm_legend_hide()) +
  tm_shape(tanzania_buf) +
  tm_polygons(col = "red", fill = "red", fill_alpha = 0.05) +
  tm_add_legend(type = "polygons", labels = "50km buffer around Tanzania",
                col = "red", fill_alpha = 0.1, fill = "red", position = c("left","bottom"))  +
  tm_scalebar(seq(0, 1000, 200), width = 1000, position = c("left", "bottom"), text.size = 0.6)
# For 'tm_scalebar()', 'breaks' and 'width' are not supposed to be used together; normally, setting the exact width is not needed when breaks have been specified.FALSE
# scalebar outside the legend is set arbitrarily
tm_shape(tanzania_neigh) +
  tm_polygons() +
  tm_text(text = "name_long",
          text.scale = tm_scale(auto.placement = FALSE, remove.overlap = FALSE), 
          size = "AREA", size.legend = tm_legend_hide()) +
  tm_shape(tanzania_buf) +
  tm_polygons(col = "red", fill = "red", fill_alpha = 0.05) +
  tm_add_legend(type = "polygons", labels = "50km buffer around Tanzania",
                col = "red", fill_alpha = 0.1, fill = "red", position = c("left","bottom"))  +
  tm_scalebar(seq(0, 1000, 200), width = 1000, position = c("right", "bottom"), text.size = 0.6)
# For 'tm_scalebar()', 'breaks' and 'width' are not supposed to be used together; normally, setting the exact width is not needed when breaks have been specified.FALSE
# [plot mode] fit legend/component: Some legend items or map compoments do not fit well, and are therefore rescaled. Set the tmap option 'component.autoscale' to FALSE to disable rescaling.
# Scale bar set for latitude km and will be different at the top and bottom of the map.

Overall, I currently prefer to work without width, as the results are more reliable.
The overall calculation for setting the legend and scalebar is actually very complex and tricky. Thank you for your efforts to further improve this algorithm.

  1. If the last label doesn't fit, but the scale bar does, this last label is removed, but the unit is printed after the second-last label. This only applies when breaks are not specified.

I really like this automated shortening. It significantly improves the aesthetics.

@mtennekes
Copy link
Member

One important piece of information you miss (apparently haven't share properly): width has nothing to do with coordinates, but the unit is 'line heights'. So width = 1000 means the maximal width (which is the width of the map minus margins).

For the last example: if the position is different, then the scale bar doesn't take the other components (in this case add_legend) into account.

You can see the margins a bit better when you enable tmap_design_mode.

I still see some room for improvement (apart from the documentation), so I'll leave this open.

@rhurlin
Copy link
Author

rhurlin commented Aug 26, 2024

One important piece of information you miss (apparently haven't share properly): width has nothing to do with coordinates, but the unit is 'line heights'. So width = 1000 means the maximal width (which is the width of the map minus margins).

Oh, I'm really sorry. I must have misunderstood that completely. I hadn't found any explanation in the tm_scalebar help, so I had assumed that 'width' referred to the width of the scalebar (in terms of units, e.g. 1000 km in my example). Thanks for the clarification.

For the last example: if the position is different, then the scale bar doesn't take the other components (in this case add_legend) into account.

I understand that very well, but with my understanding of width at the time, I had expected the scalebar to be oriented to the right edge of the graph in the last example. Instead, it is more to the left of the center of the graphic.

You can see the margins a bit better when you enable tmap_design_mode.

With design_mode active, you can see that the scalebar in the last example is much wider than I expected due to width=1000. Thanks for this tip too!

I still see some room for improvement (apart from the documentation), so I'll leave this open.

For me, the design possibilities with tmap are already quite good, so I can continue with my projects.
Thanks again for the spontaneous help, the quick patches and the patience. Very appreciated!

@mtennekes mtennekes added finetuning and removed bug labels Aug 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants