DOS
DOS

Reputation: 65

How to force text displayed by the tm_text function of R's tmap to remain inside polygon?

Congressional districts of Alabama during the 103rd US CongressI'm using the tm_text function in the tmap package (for R) to draw maps and I want to force the text that is displayed to remain inside the polygon that it refers to. How do I achieve this with this function? (Some polygons are weirdly shaped and they end up having their text falling outside the polygon. The picture above illustrates an example; the 6th district has a weird shape. I would like to know if it is possible to have its label automatically placed inside the polygon as I need to plot a large number of maps.)

Upvotes: 0

Views: 962

Answers (1)

mgrund
mgrund

Reputation: 1625

First of all your text label for e.g. 6 is outside the polygon since tmap's tm_text uses the polygon centroids as position to place the label and the centroid of the corresponding polygon is inside. Here's a reproduction of the centroids (blue dots) that are used (see left plot below):

library(tidyverse)
library(sf)
library(tmap)

# shape file data from: 
# https://earthworks.stanford.edu/catalog/tufts-uscongdist107th01
df <- st_read("GISPORTAL_GISOWNER01_USCONGDIST107TH01.shp") %>% 
  filter(STATE == "AL") %>% 
  distinct(CONG_DIST, .keep_all = T)

# get polygon centroids to show how tmap works
df_points_centroid <- df %>% 
  mutate(centroid = st_centroid(geometry)) %>% 
  as.data.frame() %>% 
  select(-geometry) %>% 
  st_as_sf()

tm_shape(df) +
  tm_borders() +
  tm_fill(col = "gray") +
  tm_text("CONG_DIST") +
  tm_shape(df_points_centroid) +
  tm_dots(col = "blue", size = .1) +
  tm_layout(frame = F)

To use label positions which are always inside the polygon you can use st_point_on_surface() from the sf package (see red dots and labels in the right plot):

# get points guaranteed to be within the polygon
df_points_within <- df %>% 
  mutate(point_within = st_point_on_surface(geometry)) %>%
  as.data.frame() %>%
  select(-geometry) %>%
  st_as_sf()

# show old and new text locations together
tm_shape(df) +
  tm_borders() +
  tm_fill(col = "gray") +
  tm_shape(df_points_centroid) +
  tm_dots(col = "blue", size = .1) +
  tm_shape(df_points_within) +
  tm_dots(col = "red", size = .1) +
  tm_text("CONG_DIST") +
  tm_layout(frame = F)

enter image description here

Upvotes: 1

Related Questions