I am using sf
and ggplot2
to read shapefiles as simple features and plot various maps. I have been working through the maps chapter in the ggplot2 book but could not really find an answer to the following issue:
Plotting a map using geom_sf
and labelling its features with geom_sf_text
is a pretty straightforward task.
library(ggplot2)
library(sf)
library(ozmaps)
oz_states <- ozmaps::ozmap_states
ggplot() +
geom_sf(data = oz_states) +
geom_sf_text(data = oz_states, aes(label = NAME))
Once we zoom in on a section of the previous map, not all labels of the features present in the plot are visible.
xlim <- c(120.0, 140.0)
ylim <- c(-40, -24)
ggplot() +
geom_sf(data = oz_states) +
geom_sf_text(data = oz_states, aes(label = NAME)) +
coord_sf(xlim = xlim, ylim = ylim)
I have found a workaround to zoom in on sections of the map and still be able to label the features present in the plot by calculating the centroids of the features, extracting the coordinates as separate columns, selecting the elements I would like to be displayed in the final map, and using ggrepel
to label them.
library(dplyr)
library(ggrepel)
oz_states_labels <- oz_states %>% st_centroid()
oz_states_labels <- do.call(rbind, st_geometry(oz_states_labels)) %>%
as_tibble() %>%
rename(x = V1) %>%
rename(y = V2) %>%
cbind(oz_states_labels) %>%
slice(4,5,7,3)
ggplot() +
geom_sf(data = oz_states) +
geom_text_repel(data = oz_states_labels, aes(label = NAME, x = x, y = y)) +
coord_sf(xlim = xlim, ylim = ylim)
Naturally, if possible, I would like to avoid the workaround of first having to calculate the centroids, extract the coordinates from the resulting sf
and select the labels to be shown in the final map.
Hence my question: Is there a faster way of labelling all elements visible in the plot for example by specifying this either in geom_sf_text
or coord_sf
?
Thanks in advance for your tips and answers!
I believe the issue you are facing is caused by your applying the crop at presentation level / the actual data underlying your ggplot object is not cropped.
I suggest applying the crop at data level, for example via sf::st_crop()
. In this example I am using the values of your xlim and ylim objects to create a bounding box (called crop_factor
for no good reason) to limit the extent of the oz_states
at the data level, by creating a new object called oz_cropped
& continuing in your original workflow.
All the centroids and labels and what not will be much better behaved now.
library(ggplot2)
library(sf)
library(ozmaps)
oz_states <- ozmaps::ozmap_states
crop_factor <- st_bbox(c(xmin = 120,
xmax = 140,
ymax = -24,
ymin = -40),
crs = st_crs(oz_states))
oz_cropped <- st_crop(oz_states, crop_factor)
ggplot() +
geom_sf(data =oz_cropped) +
geom_sf_text(data = oz_cropped, aes(label = NAME))