--- title: "Grouped layouts and anchor placement" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Grouped layouts and anchor placement} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5 ) ``` ## Overview `explode_grouped()` extends the core two-level exploded-map workflow with a three-level hierarchy for multi-region or national-scale layouts. This grouped extension is most useful when a standard two-level explosion still leaves region blocks visually crowded or difficult to compare across a larger spatial extent. The three levels are: 1. **Level 1 — Local explosion.** Units within each parent region are displaced using the centroid-driven field from the core algorithm. The geometric guarantees of Propositions 1--3 apply at this level. 2. **Level 2 — Radial anchor placement.** Parent region centroids are displaced radially outward from the national centroid to generate initial anchor positions for each region block. 3. **Level 3 — Collision-aware refinement** (optional). Overlapping anchors are iteratively repelled while a spring term maintains proximity to the original radial targets. Levels 2 and 3 preserve structural grouping and directional correspondence rather than topological coverage. The formal geometric guarantees of Propositions 1--3 apply strictly at Level 1. ```{r setup} library(sf) library(explodemap) ``` ## A synthetic grouped example We create a small dataset with six units in three regions, spread across a wider spatial extent than the two-region example in `vignette("getting-started")`. ```{r synthetic-grouped} sq <- function(xmin, ymin, size = 1000) { st_polygon(list(matrix( c(xmin, ymin, xmin + size, ymin, xmin + size, ymin + size, xmin, ymin + size, xmin, ymin), ncol = 2, byrow = TRUE ))) } geom <- st_sfc( sq(0, 0), sq(3000, 0), # R1 sq(9000, 0), sq(12000, 0), # R2 sq(24000, 0), sq(27000, 0), # R3 crs = 3857 ) x <- st_sf( id = paste0("u", 1:6), region = c("R1", "R1", "R2", "R2", "R3", "R3"), geometry = geom ) ``` ## Anchor modes `explode_grouped()` supports three anchor placement modes: | Mode | Description | |------|-------------| | `"auto"` | Level 2 only — radial placement without collision resolution | | `"auto_collision"` | Level 2 + Level 3 — radial placement with iterative refinement | | `"manual"` | User-supplied anchor coordinates | ## Automatic grouped layout The simplest call uses `mode = "auto"`: ```{r auto-mode} g_auto <- explode_grouped( x, region_col = "region", mode = "auto", plot = FALSE, quiet = TRUE ) class(g_auto) print(g_auto) ``` The result is a `grouped_exploded_map` S3 object, which also inherits from `exploded_map`: ```{r auto-names} names(g_auto) ``` Plot the grouped layout: ```{r auto-plot} plot(g_auto) ``` ## Collision-aware grouped layout `mode = "auto_collision"` adds Level 3 refinement. Overlapping region blocks are iteratively repelled while a spring term pulls them back toward their radial targets: ```{r collision-mode} g_collide <- explode_grouped( x, region_col = "region", mode = "auto_collision", plot = FALSE, quiet = TRUE ) plot(g_collide) ``` The anchor table reports the resulting block radii and coordinates: ```{r convergence} g_collide$anchors[, c("region", "block_radius", "anchor_x", "anchor_y")] ``` ## Viewing all stages `plot(g, "all")` shows the original, locally exploded, and grouped layouts side by side: ```{r all-views, fig.width = 10, fig.height = 4} plot(g_collide, "all") ``` ## Inspecting anchor positions `layout_regions()` computes anchor positions as a standalone step, which is useful for custom workflows or manual adjustment: ```{r layout-regions} anchors <- layout_regions( x, region_col = "region", mode = "auto", quiet = TRUE ) anchors[, c("region", "block_radius", "n_units", "anchor_x", "anchor_y")] ``` ## Manual anchors You can edit anchor positions and pass them back into `explode_grouped()`: ```{r manual-anchors} manual_anchors <- anchors manual_anchors$anchor_x <- manual_anchors$anchor_x + c(0, 500, 1000) manual_anchors$anchor_y <- manual_anchors$anchor_y + c(0, 250, 500) g_manual <- explode_grouped( x, region_col = "region", mode = "manual", anchors = manual_anchors, plot = FALSE, quiet = TRUE ) plot(g_manual) ``` ## Key parameters Level 1 parameters control local displacement within regions: | Parameter | Default | Purpose | |-----------|---------|---------| | `alpha_l` | derived | Local expansion magnitude (metres) | | `p` | 1.25 | Distance-scaling exponent | | `gamma_l` | 1.136 | Local clearance coefficient (used if `alpha_l` is NULL) | Level 2 and Level 3 parameters control anchor placement and refinement: | Parameter | Default | Purpose | |-----------|---------|---------| | `kappa` | 1.8 | Radial expansion factor | | `padding` | 50000 | Base padding (map units) | | `delta` | 15000 | Log-density scaling factor | | `lambda` | 0.18 | Spring coefficient for refinement | | `eta` | 0.18 | Repulsion step size for refinement | | `padding_sep` | 20000 | Minimum separation between blocks | For real-world data, these defaults are tuned for national-scale U.S. layouts such as states grouped into larger reporting regions. For smaller or larger extents, adjust `padding`, `delta`, and `padding_sep` to match your coordinate system and visual scale. ## Summary ```{r summary} summary(g_collide) ``` ## Interactive grouped focus maps Grouped results can be passed directly to `focus_map()`. The widget automatically uses `sf_grouped_wgs`, so the displayed geometry matches the grouped layout: ```{r grouped-focus-map, eval=FALSE} focus_map( g_collide, label_col = "id", id_col = "id", group_col = "region", info_cols = c("region"), performance_mode = TRUE ) ``` Inside Shiny, pair `explode_grouped(..., quiet = TRUE, plot = FALSE)` with `renderFocusmap()` to avoid console noise and accidental plot printing. ## What the grouped object stores | Field | Contents | |-------|----------| | `sf_orig` | Original input geometries | | `sf_local` | Geometries after Level 1 local explosion | | `sf_grouped` | Final geometries after anchor displacement | | `sf_grouped_wgs` | Final geometries in WGS84 (EPSG:4326) | | `stats` | Geometry statistics from `compute_stats()` | | `params` | All parameters used | | `anchors` | Anchor table with block radii and positions | | `plots` | ggplot objects for original, local, and grouped layouts | | `diagnostics` | Label, region column, centroid mode, and anchor mode | ## Scope of guarantees The local explosion stage (Level 1) preserves the package's core geometric guarantees: exact feature-level geometry preservation (Proposition 1), radial ordering within regions (Proposition 2), and bounded displacement (Proposition 3). The grouped anchor stage (Levels 2--3) is a higher-level layout extension. It preserves grouping structure and directional correspondence rather than topological coverage. ## Next steps For the core two-level workflow and parameter derivation, see `vignette("getting-started")`. For full paper-scale examples including cross-state calibration, Canada, and HHS grouped layouts, see `vignette("reproducing-paper-examples")`.