Chapter 3 tmap in a nutshell

The tmap package allows the creation of thematic maps with great flexibility. It accepts spatial data in various formats shape objects (section 3.1) Next, the data can be used to create simple, quick maps (section 3.2) and more complex and expandable maps (section 3.3). These maps can be presented in two modes - as a static map and an interactive one. Additionally, tmap makes it possible to create small multiples map (section 3.5) and map animations (section 3.6).

3.1 Shape objects

As we established in chapter 2, spatial data comes in various file formats related to two main data models - vector and raster. There are also several spatial object classes in R, for example, sf from the sf package for vector data and stars from stars for raster data and spatial data cubes. Additionally, packages such as sp, raster, or terra offer their own classes, and this abundance of spatial object classes can be generally overwhelming. Gladly, tmap can work with all of the above objects - it treats all supported spatial data classes as so-called shape objects.

For example, we read the ei_points.gpkg file contains several points on Easter Island into a new object, ei_points, and select only points with the type of "volcano". The volcanoes object is a shape object.

library(tmap)
library(sf)
ei_points = read_sf("data/easter_island/ei_points.gpkg")
volcanoes = subset(ei_points, type == "volcano")

Spatial data, no matter the class, usually stores two interrelated sets of information - about the locations/geometries and their associated values/attributes. Visualization of the attributes only can be done with regular plotting functions (e.g., plot(), hist(), barplot()) or dedicated packages, such as ggplot2 . On the other hand, tmap is suitable when our goal is to visualize spatial geometries only or spatial geometries together with their attributes.

3.2 Quick maps

The tmap package offers a distinction between quick and regular maps. The first approach, using the qtm() function, could be handy for data exploration. It works even if we just provide any shape object - in that case, only the geometry is plotted. Figure 3.1:A shows a visualization of the geometries from the volcanoes.

qtm(volcanoes)

The qtm() function allows to customize many map elements for the provided shape object. For example, we can change the shapes of the points in volcanoes, make their sizes related to the the "elevation" argument, and add a title (Figure 3.1:B).

qtm(volcanoes, symbols.shape = 24, symbols.size = "elevation", title = "Volcanoes")
Two maps created with qtm(): (A) by providing only a shape object, (B) by providing a shape object and some other arguments.

FIGURE 3.1: Two maps created with qtm(): (A) by providing only a shape object, (B) by providing a shape object and some other arguments.

The qtm() function offers similar flexibility to the regular map approach. However, it only supports one shape object.

3.3 Regular maps

Therefore, for most applications, we recommend using the regular map approach. This approach operates on many functions that start with tm_. The first element always is tm_shape(), which specified the input shape object. Next, map layers, additional map elements, and overall layout can be customized.

The last example in 3.2 can be reproduced with the regular map approach using the following code:

tm_shape(volcanoes) +
  tm_symbols(shape = 24, size = "elevation") +
  tm_layout(title = "volcanoes")

Here, we specify the input data (our shape object) with tm_shape(), aesthetics (also known as visual variables) of map layers with tm_symbols(), and the map title with tm_layout().

The tmap package has a number of possible map layers, but the most prominent ones are tm_polygons(), tm_symbols(), tm_lines(), tm_raster(), and tm_text() (chapter 5). Overall, most visual variables of map layers can be assigned in two main ways. First, they accept a fixed, constant value, for instance, shape = 24, which sets the symbols’ shapes to triangles. Second, it is also possible to provide a variable name, for example size = "elevation". This plots each point with a size based on the elevation attribute from the volcanoes object and automatically adds a related map legend.

The tm_shape() function and one or more following map layers create a group together. In other words, map layers are related only to the preceding tm_shape() call. One map can have several groups. Let’s see how many groups work by reading some additional datasets - the ei_elev raster with elevation data for Easter Island, the ei_borders polygon with the island outline, and the ei_roads lines contains a road network for this island.

library(sf)
library(stars)
ei_elev = read_stars("data/easter_island/ei_elev.tif")
ei_borders = read_sf("data/easter_island/ei_border.gpkg")
ei_roads = read_sf("data/easter_island/ei_roads.gpkg")

Look at the following example and try to guess how many groups it has, and how many layers exist for each group (Figure 3.2).

tm_shape(ei_elev) +
  tm_raster(style = "cont", palette = "-RdYlGn",
            title = "Elevation (m asl)") +
  tm_shape(ei_borders) + 
  tm_borders() +
  tm_shape(ei_roads) + 
  tm_lines(lwd = "strokelwd", legend.lwd.show = FALSE) +
  tm_shape(volcanoes) +
  tm_symbols(shape = 24, size = "elevation",
             title.size = "Volcanoes (m asl)") +
  tm_layout(main.title = "Easter Island",
            bg.color = "lightblue")
Example of a map with four groups of map layers: an elevation layer, island borders layer, roads layer, and volcanoes layer.

FIGURE 3.2: Example of a map with four groups of map layers: an elevation layer, island borders layer, roads layer, and volcanoes layer.

The correct answer is four groups, all with just one layer. Each group is put on the top of the previous one - the tmap uses a layered approach. The first group represents elevation data with a continuous color scale style, a color palette called "RdYlGn", and a legend title. The second group shows the borders of Easter Island with the default aesthetics, while the third group presents the road network (the ei_roads object), with each line’s width based on the values from the "strokelwd" column, but with a legend hidden. The last group is similar to our previous example with fixed symbol shapes and sizes related to the "elevation" attribute, but also with the legend title instead of the map title. Additionally, we use the tm_layout() function to add a map title.

Often, maps also have additional map elements, such as graticule lines, north arrow, scale bar, or map credits (Figure 3.3). They help map readers to understand data location or its size, and provide some ancillary information. The tmap package offers a set of functions for additional map elements. The tm_graticules() function draws latitude and longitude graticules and adds their labels. It also uses the layered approach, and thus, the lines will be drawn either below or above the shape objects, depending on the position of this function in the code. In our example below, tm_graticules() is used after all of the map groups, and that is why the graticule lines are put on the top of the spatial data. We can also use tm_compass() to create a north arrow, tm_scale_bar() to add a scale bar, and tm_credits() to add a text annotation representing credits or acknowledgments. The location of all these three elements on the map is, by default, automatically determined. It, however, can be adjusted with the position argument - see an example of its use in the tm_compass() function below. Moreover, it is possible to add any type of manual legend with tm_add_legend(). It includes simple legends, such as the "Roads" legend below that is only represented by a single black line, but more complex legends with several elements are also possible.

my_map = tm_shape(ei_elev) +
  tm_raster(style = "cont", palette = "-RdYlGn",
            title = "Elevation (m asl)") +
  tm_shape(ei_borders) + 
  tm_borders() +
  tm_shape(ei_roads) + 
  tm_lines(lwd = "strokelwd", legend.lwd.show = FALSE) +
  tm_shape(volcanoes) +
  tm_symbols(shape = 24, size = "elevation",
             title.size = "Volcanoes (m asl)") +
  tm_graticules() +
  tm_compass(position = c("right", "top")) +
  tm_scale_bar() +
  tm_credits("Author, 2021") +
  tm_add_legend(type = "line", col = "black", title = "Roads") +
  tm_layout(main.title = "Easter Island",
            bg.color = "lightblue")

Maps created with tmap can be saved as an R object. This is a useful feature, which allows to use one map in a few places in a code, modify existing tmap objects, or save these objects to files.

my_map
Example of a map with four groups of map layers and additional map elements, such as graticule lines, north arrow, scale bar, and text annotation. It also has a manually added legend.

FIGURE 3.3: Example of a map with four groups of map layers and additional map elements, such as graticule lines, north arrow, scale bar, and text annotation. It also has a manually added legend.

3.4 Map modes

Each map created with tmap can be viewed in one of two modes: "plot" and "view". The "plot" mode is used by default and creates static maps similar to those shown before in this chapter. This mode supports almost all of tmap’s features, and it is recommended, for example, for scientific publications or printing.

The second mode, "view", allows creating interactive maps. They can be zoomed in and out or panned, allow for changing background tiles, or click on map objects to get some additional information. This mode has, however, some constraints and limitations comparing to "plot", for example the legend cannot be fully customized, and some additional map elements are not supported.

The tmap package allows using both modes on the same code. Therefore, there is no need to create two separate maps for static and interactive use. The tmap_mode() function can be used to switch from one mode to the other5.

tmap_mode("view")
#> tmap mode set to interactive viewing

The above line of code just changes the mode - it does not return anything except the message. Now, if we want to use this mode, we need to either write a new tmap code provide some existing tmap object, such as my_map.

my_map

As a result, we get several messages and an interactive map. These messages inform us that some map elements specified in the previous code are not possible in the "view" mode. It includes the text annotation (“Credits”), the north arrow (“Compass”), and some legend options.

FIGURE 3.4: Map from the previous figure shown using the interactive (“view”) mode.

Our main result is the interactive map (Figure 3.4). It shows our spatial data using similar aesthetics to Figure 3.3, but allows us to zoom in and out or move the map. We also can select a background tile or click on any line and point to get some information.

To go back to the "plot" mode, we need to use the tmap_mode() function again - map not shown:

tmap_mode("plot")
#> tmap mode set to plotting
my_map

More information about the interactive "view" mode and how to customize its outputs is in chapter 9.

3.5 Small multiples

Chapter 10

3.6 Animations

Chapter 13


  1. Map modes can be also changed globally using tmap_options() or switched using ttm().↩︎