Skip to content

Commit

Permalink
working on rewrite vigs
Browse files Browse the repository at this point in the history
  • Loading branch information
mtennekes committed Dec 5, 2024
1 parent 03e9dc3 commit 4d74d97
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 26 deletions.
4 changes: 2 additions & 2 deletions R/tm_legend.R
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@
#' @param item.na.width PARAM_DESCRIPTION
#' @param item.na.space PARAM_DESCRIPTION
#' @param item.shape PARAM_DESCRIPTION
#' @param ticks PARAM_DESCRIPTION
#' @param ticks List of vectors of size 2 that determines the horizontal tick mark lines (for portrait legends). The values are the y-values of begin and endpoint of each tick mark.
#' @param ticks.disable.na PARAM_DESCRIPTION
#' @param ticks.col PARAM_DESCRIPTION
#' @param ticks.lwd PARAM_DESCRIPTION
#' @param title.align PARAM_DESCRIPTION
#' @param margins PARAM_DESCRIPTION
#' @param margin.item.text PARAM_DESCRIPTION
#' @param ... passed on (?)
#' @param ... visual values, e.g. col, fill, lwd, can be specified. If so, they overrule the default visual values, which are determined by the drawn map objects (e.g. polygons)
#' @param variable visual (or transformation) variable to combine the legend with: e.g. `"fill"` or `"size"`
#' @return A tm_legend component
#' @export
Expand Down
5 changes: 5 additions & 0 deletions R/tmapGridComp_leg_landscape.R
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ tmapGridCompWidth.tm_legend_standard_landscape = function(comp, o) {

#' @export
tmapGridLegPlot.tm_legend_standard_landscape = function(comp, o, fH, fW) {

# replace gp visual values with user-specified used (e.g. tm_shape(World) + tm_polygons("HPI", fill.legend = tm_legend(col = "red")))
comp$gp = add_user_specified_values(comp$gp, comp[intersect(names(comp), names(comp$gp))])


textS = comp$text.size * comp$scale
titleS = if (comp$title == "") 0 else comp$title.size * comp$scale

Expand Down
28 changes: 16 additions & 12 deletions R/tmapGridComp_leg_portrait.R
Original file line number Diff line number Diff line change
Expand Up @@ -226,26 +226,30 @@ tmapGridCompWidth.tm_legend_standard_portrait = function(comp, o) {

}

add_user_specified_values = function(gp, usr) {
if (!length(usr)) return(gp)

for (v in names(usr)) {
fun = paste0("tmapValuesCheck_", v)
val = usr[[v]]
if (!do.call(fun, list(x = val, is_var = TRUE))) stop("Values assigned to visual variable ", v, " in tm_legend incorrect")
gp[[v]] = val
}
gp
}



#' @export
tmapGridLegPlot.tm_legend_standard_portrait = function(comp, o, fH, fW) {

# replace gp visual values with user-specified used (e.g. tm_shape(World) + tm_polygons("HPI", fill.legend = tm_legend(col = "red")))
comp$gp = add_user_specified_values(comp$gp, comp[intersect(names(comp), names(comp$gp))])

textS = comp$text.size * comp$scale #* o$scale

titleS = if (comp$title == "") 0 else comp$title.size * comp$scale #* o$scale


if (comp$type == "Bivariate") {
gp = comp$gp

g = grid::rectGrob(gp=grid::gpar(fill = "pink"))

#g = do.call(grid::grobTree, c(list(grTitle), grText, grItems, grTicks, grDesign, list(vp = vp)))

return(g)

}

n = if (comp$type == "bivariate") attr(comp$gp$fill, "n") else 1
m = if (comp$type == "bivariate") attr(comp$gp$fill, "m") else 1

Expand Down
10 changes: 7 additions & 3 deletions R/tmapLeafletComp_leg_portrait.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ tmapLeafletCompPrepare.tm_legend_standard_portrait = function(comp, o) {
}

tmapLeaflet_legend_comp = function(comp, o) {
# replace gp visual values with user-specified used (e.g. tm_shape(World) + tm_polygons("HPI", fill.legend = tm_legend(col = "red")))
comp$gp = add_user_specified_values(comp$gp, comp[intersect(names(comp), names(comp$gp))])

within(comp, {
if ("biv" %in% names(attributes(gp$fill))) {
warning("Bivariate legend not implemented for view mode", call. = FALSE)
show = FALSE
}

nuq = vapply(comp$gp, length, FUN.VALUE = integer(1))
varying = names(nuq)[which(nuq>1)]

Expand All @@ -44,11 +47,12 @@ tmapLeaflet_legend_comp = function(comp, o) {
} else {
"symbols"
}

bg.color = do.call("process_color", c(list(col=bg.color), o$pc))
title.color = do.call("process_color", c(list(col=title.color), o$pc))
text.color = do.call("process_color", c(list(col=text.color), o$pc))



gp2 = gp_to_lpar(gp, mfun = comp$mfun, shape = comp$item.shape, size_factor = 14)
})
}
Expand Down
2 changes: 1 addition & 1 deletion R/tmapScale_misc.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ get_scale_defaults = function(scale, o, aes, layer, cls, ct = NULL) {
m = getPalMeta(as.character(values[1]))
ona = getAesOption("value.na", o, aes, layer, cls = cls)

if (!is.na(ona) || is.null(m)) {
if ((!is.na(ona) && "value.na" %in% scale$called) || is.null(m)) {
ona
} else{
cols4all::c4a_na(values)
Expand Down
50 changes: 50 additions & 0 deletions sandbox/issues2.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
f = system.file("shapes/world.gpkg", package = "spData")
world = read_sf(f)
tanzania = read_sf(f, query = 'SELECT * FROM world WHERE name_long = "Tanzania"')

tmap_design_mode()

tm_shape(tanzania) +
tm_polygons(lwd = 2) +
tm_scalebar(c(0, 200, 400), position = tm_pos_out("center", "bottom"))


# problem 1: alignment
# problem 2: scalebar (comp in general?) width: wsu[3] = fW, margins make it smaller. Why are margins not included in fW?


tmap_design_mode()

tm_shape(tanzania) +
tm_polygons(lwd = 2) +
tm_title("gfjgklds hgfjdhkljghkl ;gfdgjklgf", position = tm_pos_out("center", "bottom"))

tm_shape(tanzania) +
tm_polygons(lwd = 2) +
tm_compass(position = tm_pos_out("center", "bottom"), frame = TRUE)


tm_shape(tanzania) +
tm_polygons(lwd = 2) +
tm_scalebar(c(0, 200, 400), position = tm_pos_out("center", "bottom"), margins = rep(0,4)) +
tm_compass(position = tm_pos_out("center", "bottom"), frame = TRUE, margins = rep(0,4))


# problem 3:
tm_shape(World) +
tm_polygons(lwd = 2) +
tm_compass(position = tm_pos_out("center", "bottom"), frame = TRUE)

tm_shape(World) +
tm_polygons(lwd = 2, fill = "life_exp") +
tm_compass(position = tm_pos_out("center", "bottom"), frame = TRUE)



tm_shape(World) +
tm_polygons(lwd = 2, fill = "life_exp") +
tm_compass(position = tm_pos_out("center", "bottom"), frame = TRUE)

# process_meta 381
# problem: don't know yet if autoout is placed t/b or l/r.
# autoout right bottom
26 changes: 18 additions & 8 deletions vignettes/00_grammar_of_graphics.Rmd
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: "grammar of graphics applied"
title: "Grammar of Graphics`"
output:
bookdown::html_vignette2:
pkgdown:
Expand Down Expand Up @@ -176,19 +176,29 @@ plot_tmap_grammar = function(asp = 5/7, scale = 0.7) {
}
```

tmap is based on the Grammar of Graphics [@wilkinson2005] in a similar way as ggplot2 [@ggplot2].
The Grammar of Graphics [@wilkinson2005] is a framework for building statistical graphics by combining key components like data, aesthetic mappings, geometric objects, scales, transformations, and statistical summaries. It provides a systematic, modular approach to creating flexible and consistent visualizations.

```{r echo=FALSE, fig.width = 5, fig.height=7}
plot_tmap_grammar(asp = 5/7, scale = .8)
```
### Components:
- **Data**: The dataset being visualized.
- **Aesthetic Mappings**: How data maps to visual properties (e.g., position, color, size).
- **Geometric Objects**: Shapes representing the data (e.g., points, lines, bars).
- **Scales**: Rules linking data values to aesthetic values.
- **Transformations**: Adjustments to data or coordinates (e.g., log scales).
- **Statistical Summaries**: Computed data representations (e.g., means, trends).
- **Facets**: Layouts for splitting data into subsets for comparison.

It is applied in **ggplot2** [@ggplot2] and also in **tmap**, but slightly differently.

## tmap

```{r echo=FALSE, fig.width = 7, fig.height=7}
plot_tmap_grammar(asp = 7/7, scale = .8)
```

# Differences with ggplot2
## ggplot2

* In ggplot2, the visual variables are defined on plot level (by default), but in tmap on layer level. This makes sense, since in non-spatial visualizations the x and y variables, the most important ones, are shared among the plot layers. However, in spatial visualizations the x and y variables are not considered data-driven but rather geometry-driven. The other visual variables, such as fill and border color, line width, and symbol shape.
* This also applies to the scale funtions: e.g. in ggplot2, the `scale_fill_continuous()` is defined for the visual variable fill for the whole plot. In tmap, the scale functions are mapped 1 to 1 to the visual variables per layer: `tm_polygons(fill = "my_var", fill.scale = tm_scale_continuous())`



See other vignette (to do: link) that compares tmap with ggplot2 by a series of examples

101 changes: 101 additions & 0 deletions vignettes/01_ggplot2_compare.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: "A comparison with ggplot2"
output:
bookdown::html_vignette2:
pkgdown:
as_is: true
template:
math-rendering: mathjax
bibliography: '`r system.file("tmap.bib", package="tmap")`'
csl: "`r system.file('ieee.csl', package = 'tmap')`"
editor_options:
chunk_output_type: console
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
fig.width=6,
fig.height=3,
comment = "#>"
)
hook_output <- knitr::knit_hooks$get("output")
knitr::knit_hooks$set(output = function(x, options) {
lines <- options$output.lines
if (is.null(lines)) {
return(hook_output(x, options)) # pass to default hook
}
x <- unlist(strsplit(x, "\n"))
more <- "..."
if (length(lines)==1) { # first n lines
if (length(x) > lines) {
# truncate the output, but add ....
x <- c(head(x, lines), more)
}
} else {
x <- c(more, x[lines], more)
}
# paste these lines together
x <- paste(c(x, ""), collapse = "\n")
hook_output(x, options)
})
```


```{r, echo = FALSE, message = FALSE}
library(tmap)
#devtools::load_all()
data(World, metro, rivers, land)
#tmap_design_mode()
```


## Choropleth

```{r}
library(ggplot2)
library(cols4all)
ggplot(World) +
geom_sf(aes(fill = HPI), color = "grey20", linewidth = .4) +
scale_fill_continuous_c4a_div("pu_gn", mid = 35) +
coord_sf(crs = "+proj=eqearth") +
theme_void()
```


```{r}
tm_shape(World, crs = "+proj=eqearth") +
tm_polygons(fill = "HPI",
col = "grey20",
lwd = 1,
fill.scale = tm_scale_continuous(values = "pu_gn", midpoint = 35))
```

Note the different line width values. The unit of a line width is different. tmap follows the lwd parameter (see [graphics::par]) whereas in ggplot2 `linewidth = 1` equals roughly 0.75 [due to a historical error](https://ggplot2.tidyverse.org/articles/ggplot2-specs.html#linewidth)


## Mimicing ggplot2 layout

Using tmap to match the style of ggplot2 exactly:

```{r}
tm_shape(World, crs = "+proj=eqearth") +
tm_polygons(fill = "HPI",
col = "grey20",
lwd = 1,
fill.scale = tm_scale_continuous(values = "pu_gn", midpoint = 35),
fill.legend = tm_legend(reverse = TRUE,
frame = FALSE,
item.height = 2.25,
item.width = 1.8,
position = tm_pos_out(pos.v = "center"),
na.show = FALSE,
ticks = list(c(0, 0.1), c(0.9, 1)),
ticks.col = "white",
col = "white")) +
tm_layout(frame = FALSE, outer.margins = 0)
```


Loading

0 comments on commit 4d74d97

Please sign in to comment.