Customising brain atlases

library(ggseg.formats)

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:

no_cc <- atlas_region_remove(dk(), "corpus callosum")
"corpus callosum" %in% atlas_regions(no_cc)
#> [1] FALSE

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):

frontal <- atlas_region_keep(dk(), "frontal")
atlas_regions(frontal)
#> [1] "caudal middle frontal"  "frontal pole"           "lateral orbitofrontal" 
#> [4] "medial orbitofrontal"   "rostral middle frontal" "superior 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):

lh_only <- atlas_region_keep(dk(), "^lh_", match_on = "label")
head(atlas_labels(lh_only))
#> [1] "lh_bankssts"                "lh_caudalanteriorcingulate"
#> [3] "lh_caudalmiddlefrontal"     "lh_corpuscallosum"         
#> [5] "lh_cuneus"                  "lh_entorhinal"

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:

ctx <- atlas_region_contextual(aseg(), "ventricle")
"lateral ventricle" %in% atlas_regions(ctx)
#> [1] FALSE

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:

renamed <- atlas_region_rename(
  dk(),
  "banks of superior temporal sulcus",
  "STS banks"
)
"STS banks" %in% atlas_regions(renamed)
#> [1] TRUE

Or pass a function for programmatic renaming:

upper <- atlas_region_rename(dk(), ".*", toupper)
head(atlas_regions(upper))
#> [1] "BANKS OF SUPERIOR TEMPORAL SULCUS" "CAUDAL ANTERIOR CINGULATE"        
#> [3] "CAUDAL MIDDLE FRONTAL"             "CORPUS CALLOSUM"                  
#> [5] "CUNEUS"                            "ENTORHINAL"

Managing views

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

atlas_views(aseg())
#> [1] "axial_3"   "axial_4"   "axial_5"   "axial_6"   "coronal_1" "coronal_2"
#> [7] "sagittal"

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

sag <- atlas_view_keep(aseg(), "sagittal")
atlas_views(sag)
#> [1] "sagittal"

Or remove several views at once by passing a vector:

fewer <- atlas_view_remove(aseg(), c("axial_3", "coronal_2"))
atlas_views(fewer)
#> [1] "axial_4"   "axial_5"   "axial_6"   "coronal_1" "sagittal"

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:

cleaned <- atlas_view_remove_small(aseg(), min_area = 50)
#> ℹ Removed 20 geometries below area 50

You can scope the removal to specific views:

cleaned_sag <- atlas_view_remove_small(
  aseg(),
  min_area = 50,
  views = "sagittal"
)
#> ℹ Removed 2 geometries below area 50

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:

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:

trimmed <- aseg() |>
  atlas_view_keep(c("sagittal", "coronal_3", "axial_3")) |>
  atlas_view_gather()
atlas_views(trimmed)
#> [1] "axial_3"  "sagittal"

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:

reordered <- aseg() |>
  atlas_view_keep(c("sagittal", "coronal_3", "axial_3")) |>
  atlas_view_reorder(c("axial_3", "sagittal", "coronal_3"))
atlas_views(reordered)
#> [1] "axial_3"  "sagittal"

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:

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")]
#> # A tibble: 8 × 2
#>   region              network     
#>   <chr>               <chr>       
#> 1 inferior parietal   default mode
#> 2 posterior cingulate default mode
#> 3 precuneus           default mode
#> 4 superior frontal    default mode
#> 5 inferior parietal   default mode
#> 6 posterior cingulate default mode
#> 7 precuneus           default mode
#> 8 superior frontal    default mode

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:

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)
#> ℹ Removed 2 geometries below area 30

publication_aseg
#> 
#> ── aseg ggseg atlas ────────────────────────────────────────────────────────────
#> Type: subcortical
#> Regions: 12
#> Hemispheres: left, NA, right
#> Views: sagittal
#> Palette: ✔
#> Rendering: ✔ ggseg
#> ✔ ggseg3d (meshes)
#> ────────────────────────────────────────────────────────────────────────────────
#> # A tibble: 38 × 4
#>    hemi  region          label                   structure    
#>    <chr> <chr>           <chr>                   <chr>        
#>  1 left  Cerebellum      Left-Cerebellum-Cortex  cerebellum   
#>  2 left  Cerebellum      Left-Cerebellum-Cortex  cerebellum   
#>  3 left  Thalamus        Left-Thalamus           basal ganglia
#>  4 left  Thalamus        Left-Thalamus           basal ganglia
#>  5 left  Thalamus Proper Left-Thalamus           basal ganglia
#>  6 left  Thalamus Proper Left-Thalamus           basal ganglia
#>  7 left  Caudate         Left-Caudate            basal ganglia
#>  8 left  Caudate         Left-Caudate            basal ganglia
#>  9 left  Putamen         Left-Putamen            basal ganglia
#> 10 left  Putamen         Left-Putamen            basal ganglia
#> 11 left  Pallidum        Left-Pallidum           basal ganglia
#> 12 left  Pallidum        Left-Pallidum           basal ganglia
#> 13 <NA>  Brain Stem      Brain-Stem              brainstem    
#> 14 left  Hippocampus     Left-Hippocampus        limbic       
#> 15 left  Hippocampus     Left-Hippocampus        limbic       
#> 16 left  Amygdala        Left-Amygdala           limbic       
#> 17 left  Amygdala        Left-Amygdala           limbic       
#> 18 left  ventraldc       Left-VentralDC          <NA>         
#> 19 left  vessel          Left-vessel             <NA>         
#> 20 right Cerebellum      Right-Cerebellum-Cortex cerebellum   
#> 21 right Cerebellum      Right-Cerebellum-Cortex cerebellum   
#> 22 right Thalamus        Right-Thalamus          basal ganglia
#> 23 right Thalamus        Right-Thalamus          basal ganglia
#> 24 right Thalamus Proper Right-Thalamus          basal ganglia
#> 25 right Thalamus Proper Right-Thalamus          basal ganglia
#> 26 right Caudate         Right-Caudate           basal ganglia
#> 27 right Caudate         Right-Caudate           basal ganglia
#> 28 right Putamen         Right-Putamen           basal ganglia
#> 29 right Putamen         Right-Putamen           basal ganglia
#> 30 right Pallidum        Right-Pallidum          basal ganglia
#> 31 right Pallidum        Right-Pallidum          basal ganglia
#> 32 right Hippocampus     Right-Hippocampus       limbic       
#> 33 right Hippocampus     Right-Hippocampus       limbic       
#> 34 right Amygdala        Right-Amygdala          limbic       
#> 35 right Amygdala        Right-Amygdala          limbic       
#> 36 right ventraldc       Right-VentralDC         <NA>         
#> 37 right vessel          Right-vessel            <NA>         
#> 38 <NA>  Optic Chiasm    Optic-Chiasm            other

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.

mirror server hosted at Truenetwork, Russian Federation.