---
title: "Customising brain atlases"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Customising brain atlases}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r}
#| label: setup-opts
#| include: false
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r}
#| 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:

```{r}
#| 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):

```{r}
#| 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):

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| label: atlas-views
atlas_views(aseg())
```

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

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

Or remove several views at once by passing a vector:

```{r}
#| 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:
```{r}
#| label: view-remove-small
cleaned <- atlas_view_remove_small(aseg(), min_area = 50)
```

You can scope the removal to specific views:

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| 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:

```{r}
#| 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.
