Skip to contents

A visual variable describes a certain visual property of a drawn object, such as color, size, shape, line width, line stroke, transparency, fill pattern (in ggplot2 these are called aesthetics). A visual variable can be specified using a constant value (e.g. fill = "blue") or be data-driven (more on this later). If it can only be specified with a constant value, it is called a visual constant.

The following table shows which visual variables are used in standard map layers.

Map layer Visual variables Visual constant
tm_basemap() none alpha
tm_polygons() fill (fill color), col (border color), lwd (border line width), lty (border line type), fill_alpha (fill transparency), col_alpha (border color transparency) linejoin (line join) and lineend (line end)
tm_symbols() fill (fill color), col (border color), size, shape, lwd (border line width) lty (border line type), fill_alpha fill transparency, col_alpha border color transparency linejoin (line join) and lineend (line end)
tm_lines() col (color), lwd (line width), lty (line type), alpha transparency linejoin (line join) and lineend (line end)
tm_raster() col (color), alpha (transparency)
tm_text() size, col

New in tmap 4.0 is that users can write their own custom map layer functions; more on this in another vignette. Important for now is that map layers and their visual variables can be extended if needed.

Constant visual values

The following code draws gold country polygons.

tm_shape(World) +
    tm_polygons("gold")

All the visual variables mentioned in the previous table are used, but with constant values. For instance, polygon borders are drawn with width lwd and colored with col. Each of these visual variables has a default value, in case of the border width and color respectively 1 and "black". The only visual variable for which we have specified a different value is fill, which we have set to "gold".

For those who are completely new to tmap: the function tm_shape() specifies the spatial data object, which can be any spatial data object from the packages sf, stars, terra, sp, and raster. The subsequent map layer functions (stacked with the + operator) specify how this spatial data is visualized.

In the next example we have three layers: a basemap from OpenTopoMap, country polygon boundaries, and dots for metropolitan areas:

if (requireNamespace("maptiles")) {
tm_basemap(server = "OpenTopoMap", zoom = 2, alpha = 0.5) +
tm_shape(World, bbox = sf::st_bbox(c(xmin = -180, xmax = 180, ymin = -86, ymax = 86))) +
    tm_polygons(fill = NA, col = "black") +
tm_shape(metro) +
    tm_symbols(size = 0.1, col = "red") +
tm_layout(inner.margins = rep(0, 4))
}
#> Loading required namespace: maptiles
#> Warning: Current projection unknown. Long lat coordinates (wgs84) assumed.

Each visual variable argument can also be specified with a data variable (e.g., a column name). What happens in that case is that the values of data variable are mapped to values of the corresponding visual variable.

tm_shape(World) +
    tm_polygons("life_exp")

In this example, life expectancy per country is shown, or to put it more precisely: the data variable life expectancy is mapped to the visual variable polygon fill.

To understand this data mapping, consider the following schematic dataset:

#>       geom  x1   vv1
#> 1 polygon1  72 blue6
#> 2 polygon2  58 blue3
#> 3 polygon3  52 blue2
#> 4 polygon4  73 blue7
#> 5      ... ...   ...

The first column contains spatial geometries (in this case polygons, but they can also be points, lines, and raster tiles). The second column is the data variable that we would like to show. T The third column contains the visual values, in this case, colors.

Important to note is that there are many ways to scale data values to visual values. In this example, data values are put into 5-year intervals, and a sequential discrete blue scale is used to show these. With the tm_scale_*() family of functions, users are free to create other scales.

tm_shape(World) +
    tm_polygons("life_exp", 
                fill.scale = tm_scale_continuous(values = "-carto.earth"), 
                fill.legend = tm_legend("Life\nExpectancy"))
#> [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 = FALSE` to disable rescaling.

This map uses a continuous color scale with colors from CARTO. More on scales later.

Transformation variables

Besides visual variables, map layer may use spatial transformation variables.

if (requireNamespace("cartogram")) {
tm_shape(World, crs = 8857) +
    tm_cartogram(size = "pop_est", fill = "income_grp")
}
#> Loading required namespace: cartogram
#> Cartogram in progress...

We used two variables: size to deform the polygons using a continuous cartogram and fill to color the polygons. The former is an example of a transformation variable. In our example dataset:

#>       geom         x1 x_scaled geom_transformed
#> 1 polygon1    491,775   0.0007        polygon1'
#> 2 polygon2  2,231,503   0.0033        polygon2'
#> 3 polygon3 34,859,364   0.0554        polygon3'
#> 4 polygon4  4,320,748   0.0067        polygon4'
#> 5      ...        ...      ...              ...

The data variable x1, in the example pop_est (population estimation), is scaled to x1_scaled which is, in this case, a normalization using a continuous scale. Next, the geometries are distorted such that the areas are proportional to x1_scaled (as much as the cartogram algorithm is able to achieve).