6  Layers

Table 6.1

Table 6.1: Map layers.
Function Element Geometry
Basic functions
tm_polygons() polygons (borders and fill) polygons
tm_symbols() symbols points, polygons, and lines
tm_lines() lines lines
tm_raster() raster raster
tm_text() text points, polygons, and lines
tm_basemap() tile
tm_tiles() tile
Derived functions
tm_borders() polygons (borders) polygons
tm_fill() polygons (fill) polygons
tm_bubbles() bubbles points, polygons, and lines
tm_dots() dots points, polygons, and lines
tm_markers() marker symbols points, polygons, and lines
tm_square() squares points, polygons, and lines
tm_iso() lines with text labels lines
tm_rgb()/tm_rgba() raster (RGB image) raster

In this chapter, we focus on what map layers are available in tmap and how they differ. Chapter 7, on the other hand, is all about how to present information given in variables using colors, sizes, and shapes.

6.1 Polygons

library(tmap)
library(sf)
ei_borders = read_sf("data/easter_island/ei_border.gpkg")

The main function to visualize polygons is tm_polygons(). By default, it plots areas of polygons in light gray (gray85) and polygons borders in slightly dark gray (gray25).

tm_shape(ei_borders) +
  tm_polygons()

Both, colors of areas (polygons’ fillings) and colors of borders can be modified using the fill and col arguments (Figure 6.1 (a)).

tm_shape(ei_borders) +
  tm_polygons(fill = "lightblue", col = "black", lwd = 0.5, lty = "dashed")

In fact, tm_polygons() is a combination of two separate functions: tm_fill() and tm_borders(). The tm_fill() function fills polygons with a fixed color or a color palette representing a selected variable (Figure 6.1 (b)).

tm_shape(ei_borders) +
  tm_fill(fill = "lightblue")

The tm_borders() function draws the borders of the polygons only (Figure 6.1 (c)). It allows to change the colors of borders, their widths, or the lines type.

tm_shape(ei_borders) +
  tm_borders(col = "black", lwd = 0.5, lty = "dashed")
(a) tm_polygons()
(b) tm_fill()
(c) tm_borders()
Figure 6.1: Example of a map created using:

More information on colors, and how they can be applied and modified is explained in detail in Section 7.1.

6.2 Symbols

ei_points = read_sf("data/easter_island/ei_points.gpkg")
volcanos = subset(ei_points, type == "volcano")

Symbols are a very flexible layer type. They are usually used to represent point data, but can be also used for lines and polygons. In the latter cases, they are located in centroid coordinates of each feature. Their flexibility is also related to the ways symbols can be visualized – it is possible to show values of a given variable by colors of symbols, their sizes, or shapes (more about that is explained in Chapter 7).

The tm_symbols() is the main function in tmap allowing to use and modify symbol elements (Figure 6.2). By default, this function draws a gray circle symbol with a black border for each element of an input feature.

Figure 6.2: A map showing the default tmap symbols.

In the above example, each symbol is related to one feature (row) in the volcanos object. However, in a case when we provide multi-element features (such as MULTIPOINT; Section 2.2.1), each multi-element object is first split into a number of single-element features and then plotted.

The tm_symbols() is a very flexible function with a large number of arguments. While this allows adjusting its results to almost any need, it also makes this function complicated. Therefore, four additional layers are implemented in tmap: tm_squares(), tm_bubbles(), tm_dots(), tm_markers(). All of them use tm_symbols(), but with different default values.

tm_squares() uses square symbols (shape = 22) instead of circles (shapes = 21) (Figure 6.3 (a)).

tm_shape(volcanos) +
  tm_squares()
tm_shape(volcanos) +
  tm_bubbles()

The main role of tm_dots() is to present many locations at the same time. To do this, this layer has a small size value (0.02) at the default (Figure 6.3 (c)).

tm_shape(volcanos) +
  tm_dots()

The last additional layer is tm_markers(), which uses a marker icon by default (Figure 6.3 (d)).

tm_shape(volcanos) +
  tm_markers()
(a) tm_squares()
(b) tm_bubbles()
(c) tm_dots()
(d) tm_markers()
Figure 6.3: Maps showing default visualizations using:

6.3 Lines

ei_roads = read_sf("data/easter_island/ei_roads.gpkg")

The tm_lines() function allows to visualize different types of line data (Figure 6.4).

tm_shape(ei_roads) + 
  tm_lines()
Figure 6.4: Example of a map created with tm_lines().

Lines can be presented using different colors, widths, or types (Chapter 7). This allows to show a hierarchy (for example, increased line widths for higher capacity roads) or distinguish between types of objects (for example, blue rivers comparing to gray roads).

6.4 Text

Text labels are often an integral part of many maps. They can serve several functions, from naming features, indicating relations between them, or representing a given variable’s values. The main function to create text labels is tm_text(), which adds a label to each spatial feature (Figure 6.5).

tm_shape(volcanos) +
  tm_text(text = "name", size = "elevation") +
  tm_layout(legend.outside = TRUE)
Figure 6.5: Example of a map created with tm_text().

We can adjust sizes (size; Section 7.2), colors (col), font faces (fontface), and background colors (bgcol) of labels either by providing a single value or a name of a data variable. Text labels can be further modified with the opt_tm_text() function provided to the options argument. It includes a set of arguments that allow to adjust the text labels’ appearance, such as remove_overlap, along_lines, and shadow.

Text labels can be added to spatial (multi-)points, (multi-)lines, and (multi-)polygons, and each of the cases is quite different. The simplest case is for POINT data, for which each text label will be located precisely in coordinates of the given points (Figure 6.5). However, how to add text labels to multipoints, lines, multilines, polygons, or multipolygons? Should each label correspond to one spatial feature, or should every sub-feature have their own label? Where should the labels be placed for lines or polygons - in the center of a line and centroid of a polygon or somewhat different?

# x2 = x |> 
#   dplyr::group_by(region_un) |> 
#   dplyr::summarise()
# tm_shape(x2) +
#   tm_polygons() +
#   tm_text("region_un")

Text labels are also often presented together with lines (Section 6.3). One example is an isopleth – a line drawn on a map through all points having the same value of a given variable, such as atmospheric pressure or elevation. Isopleths can be created with the tm_iso() function.

# to improve
library(stars)
#> Loading required package: abind
library(terra)
#> terra 1.8.5
#> 
#> Attaching package: 'terra'
#> The following objects are masked from 'package:magrittr':
#> 
#>     extract, inset
ei_elev = read_stars("data/easter_island/ei_elev.tif")
ei_elev_raster = rast(ei_elev)
elev_isopleths = as.contour(ei_elev_raster)
tm_shape(elev_isopleths) +
  tm_iso()

ei_terrain = terra::terrain(ei_elev_raster, c("slope", "aspect"), unit = "radians")
hs = terra::shade(ei_terrain[[1]]*3, ei_terrain[[2]])

tm_shape(hs) +
    tm_grid() +
    tm_raster(col.scale = tm_scale(values = gray(0:100 / 100), n = 100),
            col.legend = tm_legend_hide()) +
    tm_shape(ei_elev) +
    tm_raster(col_alpha = 0.25,
            col.scale = tm_scale(values = terrain.colors(25)),
            col.legend = tm_legend_hide()) +
    tm_shape(elev_isopleths) +
    tm_lines(col = "white") +
    tm_text("level", col = "white")

6.5 Raster

library(stars)
ei_elev = read_stars("data/easter_island/ei_elev.tif")
ei_geomorphons = read_stars("data/easter_island/ei_geomorphons.tif")

Visualization of raster data depends on the raster type (continuous or categorical), its resolution, and the number of layers. Figure 14.2 shows two simple example of continuous and categorical raster visualization created with tm_raster(). This function attempts to recognize the type of a given raster – when the input raster is continuous then the pretty style is used. However, the continuous style ("tm_scale_continuous") often better represent phenomena that progressively vary in space (?fig-rasterdown-1).

tm_shape(ei_elev) +
  tm_raster(col.scale = tm_scale_continuous(values = "viridis"),
            col.legend = tm_legend(title = "Elevation (m asl):"))

On the other hand, when the given raster is categorical, then tm_raster uses tm_scale_categorical automatically (?fig-rasterdown-2). We can also adjust the legend title, used colors, and many more, in a similar fashion as in the previously mentioned layers.

tm_shape(ei_geomorphons) +
  tm_raster(col.legend = tm_legend(title = "Geomorphons:"))
(a) Continuous raster map
(b) Categorical raster map
Figure 6.6: Examples of raster maps

The above examples used a raster with one layer only. However, rasters can have many layers, either represented by dimensions or attributes. By default, tmap shows all of the layers, where each raster has its own legend.

raster2 = c(ei_elev, ei_geomorphons)
tm_shape(raster2) +
  tm_raster()

We can modify their arrangement with tm_facets() (Figure 6.7).

tm_shape(raster2) +
  tm_raster() +
  tm_facets(ncol = 1) +
  tm_layout(panel.labels = c("Elevation", "Geomorphons"))
Figure 6.7: A map created from a multilayered raster.

If you want to learn more – we focus on how to specify and modify facets (also known as small multiples) in Chapter 10 and how to modify map layout in Chapter 8.

#to replace later
library(stars)
landsat = read_stars(system.file("raster/landsat.tif", package = "spDataLarge"))

The landsat object contains four bands (blue, green, red, and near-infrared) of the Landsat 8 image for the area of Zion National Park taken on 18th of August 2015. We can plot all of the bands independently or as a combination of three bands. This combination is known as a color composite image, and we can create such images with the tm_rgb() function (Figure 6.8).

Standard composite image (true color composite) uses the visible red, green, and blue bands to represent the data in natural colors. We can specify which band in landsat relates to red (third band), green (second band), and blue (first band) color in tm_rgb().

tm_shape(landsat) +
  tm_rgb(tm_vars(dimvalues = c(3, 2, 1), multivariate = TRUE),
         col.scale = tm_scale_rgb(stretch = TRUE))

True color images are straightforward to interpret and understand, but they make subtle differences in features challenging to recognize. However, nothing stops us from using the above tools to integrate different bands to create so called false color composites. Various band combinations emphasize some spatial characteristics, such as water, agriculture, etc., and allows us to visualize wavelengths that our eyes can not see. Figure 6.8 (b) shows a composite of near-infrared, red, and green bands, highlighting vegetation with a bright red color.

tm_shape(landsat) +
  tm_rgb(tm_vars(dimvalues = c(4, 3, 2), multivariate = TRUE),
         col.scale = tm_scale_rgb(stretch = TRUE))
(a) True color composite image
(b) False color composite image
Figure 6.8: Two color composite images

6.6 Tile

Tile layers can be used for two purposes: either as a basemap or an overlay layer. By default, three basemaps are used in the interactive mode (tmap_mode("view")): "Esri.WorldGrayCanvas", "OpenStreetMap", and "Esri.WorldTopoMap". However, we can change the basemaps with a vector with the names of the tile layers’ providers (Figure 6.9).

tmap_mode("view")
tm_basemap(c(StreetMap = "OpenStreetMap", TopoMap = "OpenTopoMap")) +
  tm_shape(volcanos, is.main = TRUE) + 
  tm_dots(col = "red", group = "Volcanos")
Figure 6.9: OpenStreetMap tile layer used as a base map with the red dots representing volcanos on Easter Island.

In the above code, we made two basemaps available: "OpenStreetMap" and "OpenTopoMap", and for the map legend purpose, we renamed them as StreetMap and TopoMap. A complete list of available basemaps is in the leaflet::providers object and on the https://leaflet-extras.github.io/leaflet-providers/preview/ website1. The tm_basemap(NULL) function allows to disable basemaps entirely.

The tm_tiles() function, on the other hand, draws the tile layer on the top (as overlay layer) of the previous tm_ layer. In the next example, we put the vector "CartoDB.PositronOnlyLabels" tiles on top of the previously set basemaps, but below the dots layer (Figure 6.10).

tm_basemap(c(StreetMap = "OpenStreetMap", TopoMap = "OpenTopoMap")) +
  tm_tiles(c(CartoDB = "CartoDB.PositronOnlyLabels")) +
  tm_shape(volcanos, is.main = TRUE) + 
  tm_dots(col = "red", group = "Volcanos")
Figure 6.10: OpenStreetMap tile layer used as a base map with dashed lines representing island coastline and the red dots representing volcanos on Easter Island.

Tile layers are usually created to be used interactively. We can see it, for example, by their number of details varying depending on the zoom level we set. That being said, many people find them useful also for static maps, and tmap allows to use them in this way. It uses the maptiles package to download the tiles and then plot them as a raster layer.

A complete list of available providers and some information about zoom levels are in the help file of the ?maptiles::get_tiles() function. Different map tiles providers offer unique map styles, while zoom levels relate to different levels of detail – the larger level, the more details we will get. When using map tiles, we should also consider adding their attribution to the map. Attribution for each provider can be obtained using the maptiles::get_credit() function by specifying the provider name, for example get_credit("CartoDB.VoyagerNoLabels").

The code below plots the "CartoDB.VoyagerNoLabels" tiles in the background, adds the island outline in light blue color, and puts attribution text in the bottom right corner of the map (Figure 6.11)).

tmap_mode("plot")
#> ℹ tmap mode set to "plot".
tm_basemap("CartoDB.VoyagerNoLabels") + 
  tm_shape(ei_borders) +
  tm_borders(lwd = 5, col = "lightblue") +
  tm_credits(maptiles::get_credit("CartoDB.VoyagerNoLabels"),
             bg.color = "white")
Figure 6.11: Example of a static map using a downloaded "CartoDB.VoyagerNoLabels" tile layer.

  1. Additional details can be found in the leaflet::providers.details object↩︎