Customising brain atlases

#| label: setup-opts
#| include: false
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
#| label: setup
library(ggseg.formats)
# The atlas-manipulation helpers shown here operate on sf-backed atlas
# geometry. Since the sf-optional milestone, sf is a Suggests dependency,
# so load it explicitly here.
library(sf)

Say you are preparing a figure that focuses on the subcortical structures visible in a single sagittal slice. You want to drop the views you don't need, remove small polygon fragments that clutter the image, turn some regions into non-legend context, and add a metadata column so you can facet by structure type. Every one of those steps is a single function call, and they all pipe together.

The manipulation toolkit

ggseg.formats provides three groups of manipulation functions. Region functions (atlas_region_*) control which regions are active in the atlas. View functions (atlas_view_*) control the 2D sf geometry—which views are present and how they are arranged. Core functions (atlas_core_*) enrich the region metadata. All of them accept a ggseg_atlas as the first argument, return a new ggseg_atlas, and play nicely with the pipe.

Keeping and removing regions

atlas_region_remove() strips a region entirely—from core, palette, sf geometry, and 3D data. The pattern argument is passed to grepl() with ignore.case = TRUE, so partial matches work:

#| label: region-remove
no_cc <- atlas_region_remove(dk(), "corpus callosum")
"corpus callosum" %in% atlas_regions(no_cc)

atlas_region_keep() is the inverse: it keeps only the regions that match and turns everything else into context geometry (sf is preserved for surface continuity, but non-matching regions leave core and palette):

#| label: region-keep
frontal <- atlas_region_keep(dk(), "frontal")
atlas_regions(frontal)

Both functions accept a match_on argument to choose whether the pattern matches against "region" (the default, human-readable name) or "label" (the unique identifier):

#| label: region-keep-label
lh_only <- atlas_region_keep(dk(), "^lh_", match_on = "label")
head(atlas_labels(lh_only))

Context regions

Sometimes you want a region's polygon to stay visible (rendered in grey) but not appear in the legend or carry data. This is what atlas_region_contextual() does. It removes the region from core, palette, and 3D data but leaves the sf geometry in place:

#| label: region-contextual
ctx <- atlas_region_contextual(aseg(), "ventricle")
"lateral ventricle" %in% atlas_regions(ctx)

Compare that to atlas_region_remove(), which would delete the ventricle polygons entirely, leaving gaps in the 2D slices.

Renaming regions

atlas_region_rename() changes the region column without touching label (so geometry links stay intact). Pass a fixed string:

#| label: region-rename
renamed <- atlas_region_rename(
  dk(),
  "banks of superior temporal sulcus",
  "STS banks"
)
"STS banks" %in% atlas_regions(renamed)

Or pass a function for programmatic renaming:

#| label: region-rename-func
upper <- atlas_region_rename(dk(), ".*", toupper)
head(atlas_regions(upper))

Managing views

atlas_views() tells you what 2D views an atlas has:

#| label: atlas-views
atlas_views(aseg())

atlas_view_keep() and atlas_view_remove() filter views by pattern. If you only want the sagittal slice:

#| label: view-keep
sag <- atlas_view_keep(aseg(), "sagittal")
atlas_views(sag)

Or remove several views at once by passing a vector:

#| label: view-remove
fewer <- atlas_view_remove(aseg(), c("axial_3", "coronal_2"))
atlas_views(fewer)

Cleaning up geometry

After filtering regions you may have small polygon fragments left over—tiny slivers where a region just barely crossed a slice plane. atlas_view_remove_small() removes region polygons below a minimum area threshold. Context polygons (those not in core) are never removed:

#| label: view-remove-small
cleaned <- atlas_view_remove_small(aseg(), min_area = 50)

You can scope the removal to specific views:

#| label: view-remove-small-scoped
cleaned_sag <- atlas_view_remove_small(
  aseg(),
  min_area = 50,
  views = "sagittal"
)

atlas_view_remove_region() removes a specific region's sf geometry without touching core, palette, or 3D data. This is useful when a region's 2D projection is misleading but you still want it in 3D:

#| label: view-remove-region
no_stem_sf <- atlas_view_remove_region(
  aseg(),
  "brain stem",
  match_on = "region"
)

Reordering and gathering

When you remove views, the remaining geometry keeps its original coordinates, which can leave awkward gaps. atlas_view_gather() repositions views side-by-side with a configurable gap:

#| label: view-gather
trimmed <- aseg() |>
  atlas_view_keep(c("sagittal", "coronal_3", "axial_3")) |>
  atlas_view_gather()
atlas_views(trimmed)

atlas_view_reorder() lets you choose the left-to-right order and repositions at the same time. Views not mentioned in order are appended at the end:

#| label: view-reorder
reordered <- aseg() |>
  atlas_view_keep(c("sagittal", "coronal_3", "axial_3")) |>
  atlas_view_reorder(c("axial_3", "sagittal", "coronal_3"))
atlas_views(reordered)

Adding metadata

atlas_core_add() left-joins a data frame onto the core table. This is useful for attaching grouping variables, statistical results, or any other per-region information. Here we add a custom network column to a handful of regions:

#| label: core-add
network_info <- data.frame(
  region = c(
    "superior frontal",
    "precuneus",
    "inferior parietal",
    "posterior cingulate"
  ),
  network = "default mode"
)
enriched <- atlas_core_add(dk(), network_info)
enriched$core[!is.na(enriched$core$network), c("region", "network")]

The by argument defaults to "region" but you can join on any shared column.

A full pipeline

Here is a realistic pipeline that prepares the aseg atlas for a compact two-view figure of deep grey matter structures:

#| label: full-pipeline
publication_aseg <- aseg() |>
  atlas_view_keep(c("sagittal", "coronal_3")) |>
  atlas_region_contextual("ventricle|choroid|white|cc") |>
  atlas_view_remove_small(min_area = 30) |>
  atlas_view_gather(gap = 0.1)

publication_aseg

Each function returns a valid ggseg_atlas, so you can inspect intermediate results, branch the pipeline, or hand the final object straight to ggseg for plotting.



Try the ggseg.formats package in your browser

Any scripts or data that you put into this service are public.

ggseg.formats documentation built on July 2, 2026, 5:07 p.m.