Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace plot points with polygons

Tags:

r

ggplot2

r-sf

I am trying to create a plot where instead of using points to represent data, I use the outline of administrative boundaries.

The below code illustrates where I am up to. Just a simple ordered scatter plot. I am now stuck, trying to replace the points with the polygon shapes for each administrative boundary (nz_map). Because the polygons in nz_map have their own geometries associated with them, I'm not sure how to position them at the locations of the points in plot space.

Any advice would be much appreciated.

# load packages
library(tidyverse)
library(sf)
library(rnaturalearth)

# map of nz with administrative boundary
nz_map <- ne_states(country  = "new zealand", returnclass = "sf")

# get regions of interest and calculate area
nz_map <- nz_map %>%
  select(name, region) %>%
  filter(region %in% c("South Island", "North Island")) %>%
  mutate(area = as.vector(st_area(.)/1e6))
  

# convert to points to illustrate plotting
nz_map_pnts <- st_centroid(nz_map)

# plot
ggplot() +
  geom_point(data = nz_map_pnts, aes(reorder(name, area), y = area)) +
  labs(x = "Region",
       y = "Area") +
  theme_classic()+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

enter image description here

like image 977
flee Avatar asked Dec 31 '25 21:12

flee


1 Answers

One option would be to use lapply and annotation_custom to add a map for each region. To this end I first create a blank plot in cartesian coordinates where I map the names on x and the areas on y. Then use e.g. lapply to loop over the regions to add a map for the region at your desired coordinates:

library(ggplot2)
library(sf)

nz_map_split <- nz_map |>
  transform(name = reorder(name, area)) |>
  split(~name)

dat <- data.frame(
  name = nz_map$name,
  area = nz_map$area
) |> 
  transform(name = reorder(name, area))

ggplot(dat, aes(name, area)) +
  geom_blank() +
  lapply(
    nz_map_split,
    \(.data) {
      #browser()
      x <- as.numeric(.data$name)
      y <- .data$area
      annotation_custom(
        ggplotGrob(ggplot(.data) +
          geom_sf() +
          theme_void()),
        xmin = x - .5, xmax = x + .5,
        ymin = y - 2000, ymax = y + 2000
      )
    }
  ) +
  labs(
    x = "Region", y = "Area"
  ) +
  theme_classic() +
  theme(
    axis.text.x = element_text(
      angle = 90, vjust = 0.5, hjust = 1
    )
  )

enter image description here

like image 139
stefan Avatar answered Jan 02 '26 11:01

stefan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!