tmap icon indicating copy to clipboard operation
tmap copied to clipboard

tm_scale_continuous displaying with interval legend with linestrings

Open marine-ecologist opened this issue 1 year ago • 4 comments

I'm converting v3 code to v4 and can't seem to get the new tm_scale_continuous to work with linestrings in that the continuous legend color scale reverts to intervals. Example below:

# generate 20 linestrings  with numeric groups:

library(sf)

set.seed(42)

lon_min <- -180
lon_max <- 180
lat_min <- -90
lat_max <- 90

create_random_line <- function() {
  lon_start <- runif(1, lon_min, lon_max)
  lat_start <- runif(1, lat_min, lat_max)
  lon_end <- runif(1, lon_min, lon_max)
  lat_end <- runif(1, lat_min, lat_max)
  
  st_linestring(matrix(c(lon_start, lat_start, lon_end, lat_end), ncol = 2, byrow = TRUE))
}

lines <- lapply(1:20, function(x) create_random_line())

lines_sf <- st_sfc(lines, crs = 4326)  # Use WGS84 (EPSG:4326)
values_df <- data.frame(value = 1:20)
lines_sf <- st_sf(values_df, geometry = lines_sf)

library(tmap)

tm_shape(lines_sf) +
  tm_lines("group", 
           lwd=5, 
           tm_scale_continuous(values="brewer.spectral")) +
tm_place_legends_right()

Screenshot 2024-06-17 at 6 20 58 am

When changing to points tm_scale_continuous works fine (presumably as it's fill and not col?):


tm_shape(points_sf) +
  tm_dots("value", 
           size=2, 
           tm_scale_continuous(values="brewer.spectral")) +
tm_place_legends_right()

Screenshot 2024-06-17 at 6 21 32 am

is there a way of getting a continuous colorscale legend with col?

marine-ecologist avatar Jun 16 '24 20:06 marine-ecologist

This is by (current) design. The legend in the first map are not intervals, but a regular (pretty) sample of geometries (lines in this case) in the continuous scale. I thought that this may be useful in some applications (?) From that perspective, the second map is wrong, and should also include the same sample of bubbles (so a orange bubble with 5, yellow with 10 etc). Note that a sample is also used for other visual variables (e.g. size).

Apart from the fact that maps 1 and 2 are not consistent (which they should be), the question is what you prefer:

  • A regular/pretty sample showing the geometries, so lines or symbols (legend in first map)
  • A continuous color box (legend in second map)

Second question: how should a user select the non-default option? What would be a good argument name in tm_legend_x?

Note-to-self: https://github.com/r-tmap/tmap/blob/master/R/tmapGridComp_leg_portrait.R#L15

mtennekes avatar Jun 25 '24 14:06 mtennekes

I've corrected the maps below to make the example more consistent, where the tm_dots are the endpoints of the tm_lines:

points_sf <- lines_sf |> st_cast("POINT")

tm_shape(points_sf) +
  tm_dots("value", 
          size=0.5, 
          tm_scale_continuous(values="brewer.spectral"), shape=21) +
  tm_shape(lines_sf) +
  tm_lines("value", 
           tm_scale_continuous(values="brewer.spectral"), 
           lwd=1) +
  tm_place_legends_right()

Screenshot 2024-07-11 at 11 53 17 AM

With the above example, the colours are both set as tm_scale_continuous, but the tm_lines are displayed as intervals not as a colour gradient. As an asides, I don't think the map is "wrong" because the bubbles don't reflect size: often tm_bubbles is visually distracting where a fixed size and simple color gradient would suffice.

As a possible answer: why not allow tm_lines to function the same as tm_dots in terms of allowing both tm_scale_continuous and tm_scale_intervals (rather than defaulting continuous to intervals)?

Expanded example on above with tm_dots, same map, different color settings:


a <- tm_shape(points_sf) +
  tm_dots("value", 
          size=1, 
          tm_scale_continuous(values="brewer.spectral"), shape=21) +
  tm_labels("value",
            size=0.8) +
  tm_place_legends_right()

b <- tm_shape(points_sf) +
  tm_dots("value", 
          size=1, 
          tm_scale_intervals(values="brewer.spectral"), shape=21) +
  tm_labels("value",
            size=0.8) +
  tm_place_legends_right()

tmap_arrange(a,b, ncol=1)

Screenshot 2024-07-11 at 11 43 30 AM

marine-ecologist avatar Jul 11 '24 02:07 marine-ecologist

As a clearer "real world" tmap example (hopefully!) that lead me to the question: a tm_scale_continuous legend would be more useful than an interval legend here as the linestring is a continuous (non-linear) gradient!

b

marine-ecologist avatar Jul 11 '24 02:07 marine-ecologist

I have a similar comment regarding tm_scale_continuous but in my case with tm_symbols(). I'm looking the have the continuous color scale legend but so far I haven't been able to create it:

tm_basemap("Esri.WorldImagery", alpha = 0.5) +
  tm_shape(SD_allsps) +
  tm_symbols(
    size = "radius_m", size.legend = tm_legend(show = F),
    col = "fcompleteness_2021", col_alpha = 0.9, 
    col.scale = tm_scale_continuous(values = viridis::mako(100)), 
    col.legend = tm_legend(title = "Mean Completeness 2021", 
                           position = tm_pos_in("left", "bottom"),
                           bg.color = "white",
                           text.size = 0.5, title.size = 0.6,
                           show = T),
    fill = "fcompleteness_2021", fill_alpha = 0.1, 
    fill.scale = tm_scale(values = "white"), fill.legend = tm_legend(show = F))

image

GuiAlDuS avatar Jul 26 '24 16:07 GuiAlDuS

Now by default, all continuous color scales (so both fill and col) come with a gradient legend.

Please check @marine-ecologist and @GuiAlDuS and let us know if you have further questions

mtennekes avatar Dec 26 '24 21:12 mtennekes