11  Positions

library(sf)
library(stars)
library(tmap)
slo_elev = read_stars("data/slovenia/slo_elev.tif")
tm = tm_shape(slo_elev) +
    tm_raster()

This chapter focuses on how to move map components, such as legends, scale bars, and insets, freely in the map. They can be placed both inside and outside the map frame – with some being in and some being out (Section 11.1). Moreover, map components can be grouped together, which allows to move them and arrange them as a single unit (Section 11.2).

11.1 Positioning

All of the map components can be positioned in any location in the map frame or outside of it. The positioning is done via the position argument, which can take a variety of values. The most common are:

  • tm_pos_in(): a function that allows to control the position inside the map frame (Figure 11.1). The first argument is the horizontal position and the second is the vertical position. E.g., tm_pos_in("left", "top") locates a component in the top left corner of the map frame. This function can be used directly or through a shortcut – a character vector with two elements, where the first is the horizontal position and the second is the vertical position inside the map frame, e.g., c("left", "top").
  • tm_pos_out(): a function that allows the control of the position outside the map frame. For example, tm_pos_out("center", "top") places a component in the center of the top side of the map frame.

Both functions can take additional arguments to control the position more precisely, including their justification and alignment.

11.1.1 Inside the map frame

Figure 11.1: Examples of positioning map components inside the map frame.

Map legends, by default, are placed outside of the map frame – that is often expected as it does not overlap with the rest of the map content. However, we can find ourselves in a situation when our spatial data is so sparse that the legend can be placed inside the map, filling a white space. Then, we need to use the position argument of tm_legend().

We may use it either with a vector with two elements, or with the tm_pos_in() function (Figure 11.1). For example, position = c("right", "bottom") or position = tm_pos_in("right", "bottom") are equivalent. The first element of the vector is the horizontal position and the second is the vertical position inside the map frame. These elements can be either in lower case letters, UPPER CASE LETTERS, or numbers between 0 and 1.

Lowercase letters, e.g., "right," "bottom", place the selected map component in the right bottom corner but leave some margin to the map frame (Figure 11.2 (a)).

tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = c("right", "bottom")))
# same as:
# tm_shape(slo_elev) +
#     tm_raster(col.legend = tm_legend(position = tm_pos_in("right", "bottom")))

Uppercase letters, e.g., "RIGHT," "BOTTOM", also places the map component in the bottom right corner but directly touch the map frame (Figure 11.2 (b)).

tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = c("RIGHT", "BOTTOM")))

Numbers between 0 and 1, e.g., c(0.8, 0.4) places the map component in the right bottom corner but with a margin of 20% of the map frame size (Figure 11.2 (c)).

tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = c(0.8, 0.4)))
(a) With lowercase letters: β€œright”, β€œbottom”
(b) With uppercase letters: β€œRIGHT”, β€œBOTTOM’”
(c) With numbers: 0.8, 0.4
Figure 11.2: Positioning legends inside the map frame.

There is one important difference between specifying the position with a vector and with the tm_pos_in() function. The latter allows to control the position more precisely with additional arguments – just.h, just.v, align.h, and align.v. The just.h and just.v only work when the position is specified with numbers between 0 and 1, and they arguments control the justification of the map component to that position.

The align.h and align.v arguments are used when many map components are grouped together, which is explained in Section 11.2.

11.1.2 Outside the map frame

Figure 11.3: Examples of positioning map components outside the map frame.

In general, there are eight locations for map components outside the map frame – each of them can be specified with tm_pos_out() (Figure 11.3). We may place a map component either on one of the sides of the map frame (e.g., tm_pos_out("center", "top")), or in its corner (e.g., tm_pos_out("left", "top")).

At the same time, placing a map component outside a map frame brings some additional complexity. Now, we can not only put a component in a specified place, but also arrange it in that place. For example, tm_pos_out("center," "top") puts the specified component to the top of the map frame but is positioned to the left. What should we do if we want to center it?

The tm_pos_out() has four sets of arguments that control the position of a map component outside the map frame:

  • cell.h and cell.v: the horizontal and vertical position of the map component outside the map frame.
  • pos.h and pos.v: the horizontal and vertical position of the map component inside the cell defined by cell.h and cell.v.
  • just.h and just.v: the justification of the map components in relation to the position of the map component inside the cell – only used when pos.h and pos.v are specified as numbers between 0 and 1.
  • align.h and align.v: the alignment of the components is only used when many components are grouped together (Section 11.2).

Let’s see how these arguments work in practice. The cell.h and cell.v arguments are the first two arguments of the tm_pos_out() function and they define the cell in which the map component will be placed (Figure 11.4 (a); Figure 11.4 (b)).

tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = tm_pos_out("center", "bottom")))
tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = tm_pos_out("left", "center")))

Then, we may to control the location of the map component inside the cell with pos.h and pos.v arguments. The pos.h argument controls the horizontal position of the map component inside the cell, while the pos.v argument – the vertical position. The former is mostly useful when our legend is on the top of the map frame and the latter is useful when it is on the left or right side of the map frame (Figure 11.4 (c); Figure 11.4 (d)).

tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = tm_pos_out("center", "bottom", pos.h = "center")))
tm_shape(slo_elev) +
    tm_raster(col.legend = tm_legend(position = tm_pos_out("left", "center", pos.v = "center")))
(a) With cell.h = "center" and cell.v = "bottom"
(b) With cell.h = "left" and cell.v = "center"
(c) With pos.h = "center" in cell (cell.h = "center", cell.v = "bottom")
(d) With pos.v = "center" in cell (cell.h = "left", cell.v = "center")
Figure 11.4: Positioning legends outside the map frame.

11.2 Many components

Various map components can be positioned at the same time – either to different locations or to the same one. For example, we can place a scale bar outside the map frame and a legend inside the map frame (Figure 11.5 (a)).

tm_shape(slo_elev) +
  tm_raster(col.legend = tm_legend(position = c("right", "bottom"))) +
  tm_scalebar(position = tm_pos_out("left", "center"))

Now, you may be wondering what happens if we want to place two (or more) components in the same location. As you can see in Figure 11.5 (b), they will be stacked on top of each other inside one frame.

tm_shape(slo_elev) +
  tm_raster(col.legend = tm_legend(position = tm_pos_out("right", "center"))) +
  tm_scalebar(position = tm_pos_out("right", "center"))
(a) Two components in different locations
(b) Two components in the same location
Figure 11.5: Positioning many map components.

The tmap package also has a mechanism to group map components together and then position and organize them as a single unit. This requires two steps:

  1. Specifying the group_id argument in the map component that we want to group together – this should be a unique integer number.
  2. Using the tm_comp_group() function to select which group of map components we want to position together and where.

In the following example, we have three map components – a legend, a scale bar, and credits – and we want to group the scale bar and credits (Figure 11.6 (a)). First, we specify the group_id argument in the map components functions, and then we use the tm_comp_group() function to position them together. Here, the position argument works exactly as we already described in the previous sections, i.e., it can be specified with a vector or with the tm_pos_in() or tm_pos_out() functions.

tm_shape(slo_elev) +
  tm_raster(col.legend = tm_legend(group_id = 1)) +
  tm_scalebar(group_id = 2) +
  tm_credits("My credits", group_id = 2) +
  tm_comp_group(1, position = tm_pos_in("right", "bottom")) +
  tm_comp_group(2, position = tm_pos_in("left", "top"))

The tm_comp_group() function can also be used to customize the arrangement of map components in the same location. For example, we can stack them vertically (stack = "vertical", default) or horizontally (stack = "horizontal") (Figure 11.6 (b)).

tm_shape(slo_elev) +
  tm_raster(col.legend = tm_legend(group_id = 1)) +
  tm_scalebar(group_id = 2) +
  tm_credits("My credits", group_id = 2) +
  tm_comp_group(1, position = tm_pos_in("right", "bottom")) +
  tm_comp_group(2, position = tm_pos_in("left", "top"), stack = "horizontal")
(a) Two groups of map components in different locations
(b) Two groups of map components in the same location, one stacked horizontally
Figure 11.6: Grouping map components together.

Each additional map component is placed on the bottom of the previous one if they are in the same location. This can be controlled with the z argument of the map component functions – lower the number the component is placed on the top.