Separating/exploding spatial features with R

Author

Philippe Massicotte

Published

August 15, 2023

It has been a while since I posted something! But today I wanted to quickly experiment and create a map where I could separate/explode the spatial geometries. Let’s first download the polygon data for Canada.

canada <- rnaturalearth::ne_states(country = "canada", returnclass = "sf") |>
  st_make_valid()

As we can see, there are three different regions.

canada |>
  distinct(region)
#>            region
#> 1  Western Canada
#> 2  Eastern Canada
#> 3 Northern Canada

These regions can be visualized using ggplot2 and sf.

# Get a good CRS for Canada
crsuggest::suggest_crs(canada)
#> # A tibble: 10 × 6
#>    crs_code crs_name                        crs_type crs_gcs crs_units crs_proj4
#>    <chr>    <chr>                           <chr>      <dbl> <chr>     <chr>    
#>  1 5931     WGS 84 / EPSG Arctic Regional … project…    4326 m         +proj=lc…
#>  2 3979     NAD83(CSRS) / Canada Atlas Lam… project…    4617 m         +proj=lc…
#>  3 3978     NAD83 / Canada Atlas Lambert    project…    4269 m         +proj=lc…
#>  4 3348     NAD83(CSRS) / Statistics Canad… project…    4617 m         +proj=lc…
#>  5 3347     NAD83 / Statistics Canada Lamb… project…    4269 m         +proj=lc…
#>  6 5926     WGS 84 / EPSG Arctic Regional … project…    4326 m         +proj=lc…
#>  7 5921     WGS 84 / EPSG Arctic Regional … project…    4326 m         +proj=lc…
#>  8 6350     NAD83(2011) / Conus Albers      project…    6318 m         +proj=ae…
#>  9 5072     NAD83(NSRS2007) / Conus Albers  project…    4759 m         +proj=ae…
#> 10 5071     NAD83(HARN) / Conus Albers      project…    4152 m         +proj=ae…

canada <- canada |>
  st_transform(5931)

canada |>
  ggplot(aes(fill = region)) +
  geom_sf()

With this following code, we can find the centroid of each region and shift the centers of the new polygons.

canada_exploded <- canada |>
  group_by(region) |>
  mutate(region_centroid = st_centroid(st_union(geometry))) |>
  ungroup() |>
  mutate(geometry = (geometry - region_centroid) * 0.9 + region_centroid)

st_crs(canada_exploded)
#> Coordinate Reference System: NA

As seen above, for a reason I do not know, we have lost the CRS after the operation, so I have to set it back before visualizing it.

canada_exploded <- canada_exploded |>
  st_set_crs(5931)

canada_exploded |>
  ggplot(aes(fill = region)) +
  geom_sf()

Session info
#> ─ Session info ───────────────────────────────────────────────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.5.0 (2025-04-11)
#>  os       Linux Mint 22
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language en_CA:en
#>  collate  en_CA.UTF-8
#>  ctype    en_CA.UTF-8
#>  tz       America/Montreal
#>  date     2025-06-12
#>  pandoc   3.1.3 @ /usr/bin/ (via rmarkdown)
#>  quarto   1.6.39 @ /usr/local/bin/quarto
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────
#>  ! package            * version    date (UTC) lib source
#>  P base64enc            0.1-3      2015-07-28 [?] RSPM (R 4.5.0)
#>  P cachem               1.1.0      2024-05-16 [?] RSPM (R 4.5.0)
#>  P class                7.3-23     2025-01-01 [?] CRAN (R 4.4.2)
#>  P classInt             0.4-11     2025-01-08 [?] RSPM
#>  P cli                  3.6.5      2025-04-23 [?] CRAN (R 4.5.0)
#>  P codetools            0.2-20     2024-03-31 [?] CRAN (R 4.4.0)
#>  P crosstalk            1.2.1      2023-11-23 [?] RSPM
#>  P crsuggest            0.4        2022-07-06 [?] RSPM
#>  P DBI                  1.2.3      2024-06-02 [?] RSPM (R 4.5.0)
#>  P devtools             2.4.5      2022-10-11 [?] RSPM (R 4.5.0)
#>  P digest               0.6.37     2024-08-19 [?] RSPM (R 4.5.0)
#>  P dplyr              * 1.1.4      2023-11-17 [?] RSPM (R 4.5.0)
#>  P e1071                1.7-16     2024-09-16 [?] RSPM (R 4.5.0)
#>  P ellipsis             0.3.2      2021-04-29 [?] RSPM (R 4.5.0)
#>  P evaluate             1.0.3      2025-01-10 [?] RSPM
#>  P extrafont            0.19       2023-01-18 [?] RSPM
#>  P extrafontdb          1.0        2012-06-11 [?] RSPM
#>  P farver               2.1.2      2024-05-13 [?] RSPM (R 4.5.0)
#>  P fastmap              1.2.0      2024-05-15 [?] RSPM (R 4.5.0)
#>  P forcats            * 1.0.0      2023-01-29 [?] RSPM
#>  P fs                   1.6.6      2025-04-12 [?] RSPM
#>  P generics             0.1.4      2025-05-09 [?] RSPM
#>  P ggplot2            * 3.5.2      2025-04-09 [?] RSPM
#>  P ggpmthemes         * 0.0.2      2025-04-14 [?] Github (pmassicotte/ggpmthemes@993d61e)
#>  P glue                 1.8.0      2024-09-30 [?] RSPM (R 4.5.0)
#>  P gtable               0.3.6      2024-10-25 [?] RSPM
#>  P hms                  1.1.3      2023-03-21 [?] RSPM
#>  P htmltools            0.5.8.1    2024-04-04 [?] RSPM (R 4.5.0)
#>  P htmlwidgets          1.6.4      2023-12-06 [?] RSPM
#>  P httpuv               1.6.16     2025-04-16 [?] RSPM
#>  P httr                 1.4.7      2023-08-15 [?] RSPM
#>  P jsonlite             2.0.0      2025-03-27 [?] RSPM (R 4.5.0)
#>  P KernSmooth           2.23-26    2025-01-01 [?] CRAN (R 4.4.2)
#>  P knitr                1.50       2025-03-16 [?] RSPM
#>  P later                1.4.2      2025-04-08 [?] RSPM
#>  P lattice              0.22-5     2023-10-24 [?] CRAN (R 4.3.3)
#>  P leafem               0.2.4      2025-05-01 [?] RSPM
#>  P leaflet              2.2.2      2024-03-26 [?] RSPM
#>  P lifecycle            1.0.4      2023-11-07 [?] RSPM (R 4.5.0)
#>  P lubridate          * 1.9.4      2024-12-08 [?] RSPM
#>  P magrittr             2.0.3      2022-03-30 [?] RSPM (R 4.5.0)
#>  P mapview              2.11.2     2023-10-13 [?] RSPM
#>  P memoise              2.0.1      2021-11-26 [?] RSPM (R 4.5.0)
#>  P mime                 0.13       2025-03-17 [?] RSPM
#>  P miniUI               0.1.2      2025-04-17 [?] RSPM (R 4.5.0)
#>  P pillar               1.10.2     2025-04-05 [?] RSPM
#>  P pkgbuild             1.4.8      2025-05-26 [?] RSPM (R 4.5.0)
#>  P pkgconfig            2.0.3      2019-09-22 [?] RSPM (R 4.5.0)
#>  P pkgload              1.4.0      2024-06-28 [?] RSPM
#>  P png                  0.1-8      2022-11-29 [?] RSPM
#>  P processx             3.8.6      2025-02-21 [?] RSPM
#>  P profvis              0.4.0      2024-09-20 [?] RSPM (R 4.5.0)
#>  P promises             1.3.3      2025-05-29 [?] RSPM (R 4.5.0)
#>  P proxy                0.4-27     2022-06-09 [?] RSPM (R 4.5.0)
#>  P ps                   1.9.1      2025-04-12 [?] RSPM
#>  P purrr              * 1.0.4      2025-02-05 [?] RSPM
#>  P quarto             * 1.4.4      2024-07-20 [?] RSPM
#>  P R6                   2.6.1      2025-02-15 [?] RSPM (R 4.5.0)
#>  P raster               3.6-32     2025-03-28 [?] RSPM
#>  P RColorBrewer         1.1-3      2022-04-03 [?] RSPM (R 4.5.0)
#>  P Rcpp                 1.0.14     2025-01-12 [?] CRAN (R 4.5.0)
#>  P readr              * 2.1.5      2024-01-10 [?] RSPM
#>  P remotes              2.5.0      2024-03-17 [?] RSPM
#>  P renv                 1.1.4      2025-03-20 [?] RSPM
#>  P rlang                1.1.6      2025-04-11 [?] RSPM
#>  P rmarkdown            2.29       2024-11-04 [?] RSPM
#>  P rnaturalearth        1.0.1      2023-12-15 [?] RSPM
#>  P rnaturalearthhires * 1.0.0.9000 2025-04-15 [?] Github (ropensci/rnaturalearthhires@153b0ea)
#>  P rstudioapi           0.17.1     2024-10-22 [?] RSPM
#>  P Rttf2pt1             1.3.12     2023-01-22 [?] RSPM (R 4.5.0)
#>  P s2                   1.1.9      2025-05-23 [?] RSPM
#>  P satellite            1.0.5      2024-02-10 [?] RSPM
#>  P scales               1.4.0      2025-04-24 [?] RSPM
#>  P sessioninfo          1.2.3      2025-02-05 [?] RSPM (R 4.5.0)
#>  P sf                 * 1.0-21     2025-05-15 [?] RSPM
#>  P shiny                1.10.0     2024-12-14 [?] RSPM (R 4.5.0)
#>  P sp                   2.2-0      2025-02-01 [?] RSPM
#>  P stringi              1.8.7      2025-03-27 [?] RSPM
#>  P stringr            * 1.5.1      2023-11-14 [?] RSPM (R 4.5.0)
#>  P terra                1.8-54     2025-06-01 [?] RSPM
#>  P tibble             * 3.3.0      2025-06-08 [?] RSPM (R 4.5.0)
#>  P tidyr              * 1.3.1      2024-01-24 [?] RSPM (R 4.5.0)
#>  P tidyselect           1.2.1      2024-03-11 [?] RSPM (R 4.5.0)
#>  P tidyverse          * 2.0.0      2023-02-22 [?] RSPM
#>  P timechange           0.3.0      2024-01-18 [?] RSPM
#>  P tzdb                 0.5.0      2025-03-15 [?] RSPM
#>  P units                0.8-7      2025-03-11 [?] RSPM
#>  P urlchecker           1.0.1      2021-11-30 [?] RSPM (R 4.5.0)
#>  P usethis              3.1.0      2024-11-26 [?] RSPM (R 4.5.0)
#>  P utf8                 1.2.6      2025-06-08 [?] RSPM (R 4.5.0)
#>  P vctrs                0.6.5      2023-12-01 [?] RSPM (R 4.5.0)
#>  P withr                3.0.2      2024-10-28 [?] RSPM
#>  P wk                   0.9.4      2024-10-11 [?] RSPM
#>  P xfun                 0.52       2025-04-02 [?] RSPM
#>  P xtable               1.8-4      2019-04-21 [?] RSPM (R 4.5.0)
#>  P yaml                 2.3.10     2024-07-26 [?] RSPM
#> 
#>  [1] /tmp/RtmpZPTuyN/renv-use-libpath-279bb9681aab5f
#>  [2] /home/filoche/.cache/R/renv/sandbox/linux-linuxmint-noble/R-4.5/x86_64-pc-linux-gnu/9a444a72
#> 
#>  * ── Packages attached to the search path.
#>  P ── Loaded and on-disk path mismatch.
#> 
#> ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Citation

BibTeX citation:
@online{massicotte2023,
  author = {Massicotte, Philippe},
  title = {Separating/Exploding Spatial Features with {R}},
  date = {2023-08-15},
  url = {https://www.pmassicotte.com/posts/2023-08-15-map-explode/},
  langid = {en}
}
For attribution, please cite this work as:
Massicotte, Philippe. 2023. “Separating/Exploding Spatial Features with R.” August 15, 2023. https://www.pmassicotte.com/posts/2023-08-15-map-explode/.