Aesthetic refinements of ggbrain plots
Michael Hallquist
3 Oct 2022
Source:vignettes/ggbrain_aesthetics.Rmd
ggbrain_aesthetics.Rmd
Images that will be used in the demo
The package includes a few images that can be used for demonstrating its capabilities. The locations of the images (and the code to load them) are listed below.
# MNI 2009c anatomical underlay
underlay_3mm <- system.file("extdata", "mni_template_2009c_3mm.nii.gz", package = "ggbrain")
# onset of decision phase for learning task
decision_onset_3mm <- system.file("extdata", "decision_onset_zstat_3mm.nii.gz", package = "ggbrain")
# Parametric modulator: entropy change following feedback in learning task
echange_overlay_3mm <- system.file("extdata", "echange_overall_zstat_3mm.nii.gz", package = "ggbrain")
# Schaefer 200-parcel atlas of cortex
schaefer200_atlas_3mm <- system.file("extdata", "Schaefer_200_7networks_2009c_3mm.nii.gz", package = "ggbrain")
print(c(underlay_3mm, decision_onset_3mm, echange_overlay_3mm, schaefer200_atlas_3mm))
## [1] "/home/runner/work/_temp/Library/ggbrain/extdata/mni_template_2009c_3mm.nii.gz"
## [2] "/home/runner/work/_temp/Library/ggbrain/extdata/decision_onset_zstat_3mm.nii.gz"
## [3] "/home/runner/work/_temp/Library/ggbrain/extdata/echange_overall_zstat_3mm.nii.gz"
## [4] "/home/runner/work/_temp/Library/ggbrain/extdata/Schaefer_200_7networks_2009c_3mm.nii.gz"
Converting to a ggplot object and displaying the plot
For reasons that are somewhat boring (having to do with how R handles
S3 operators like +
), the brain-related addition steps for
ggbrain
object must come before generic
ggplot2
modifications of the plot. More specifically, the
use of the +
operator for ggbrain commands like
geom_brain()
or images()
create and modify an
object that is internal to the
Adjustments to the appearance of image layers
fill_holes
blur_edge = NULL,
fill_holes = NULL, remove_specks = NULL, trim_threads = NULL)
Cleaning small ‘specks’ from image slices
At times, when slicing a given image (esp. functional activations),
it is possible that some clusters are very small, yielding small
‘specks’ on some rendered slices. These are visually unappealing and may
merit removal, depending on your tastes. Of course, removing these
specks can, at the extreme, misrepresent the data, which is undesirable.
This concern notwithstanding, you can use the clean_specks
argument of images
to specify the voxel threshold used to
remove clusters smaller than a certain size. For example,
clean_specks = 30
would remove any clusters smaller than 30
voxels in size from each slice on the rendered image.
# TODO: make this in geom_brain
gg_obj <- gg_obj + images(echange=echange_overlay_3mm)
Filling small holes in image slices
Another aesthetic problem is that at times there will be small holes
on the interior of a cluster. These may reflect voxels that fall below a
statistical threshold (e.g., voxels that have a z-statistic value of
3.02 in a cluster defined by z > 3.1). These can be filled in using
the fill_holes
argument of images
. This
specifies the size of holes (in voxels) that should be filled on the
rendered slices. For example, fill_holes = 30
would fill
holes of 30 or fewer voxels on the interior of each cluster. The holes
are filled by nearest neighbor imputation in which the nearest
non-missing voxels are used to impute missing voxels. In
integer-valued/categorical images, the mode of the neighboring voxels is
used for imputation.
# TODO: make this in geom_Brain
gg_obj <- gg_obj + images(echange=echange_overlay_3mm)
Labeling regions
a <- ggbrain(bg_color = "gray60", text_color = "black") +
images(c(underlay = "template_brain.nii.gz")) +
images(c(dan_clust = dan_clust), fill_holes = TRUE, clean_specks = 20, labels = dan_labels) +
# slices(paste0("x = ", seq(10, 90, 10), "%")) +
slices(montage("axial", 10, min = 0.1, max = 0.8)) +
# add_slice("y=50%", title = "hello", xlab = "testx", border_size = 1, border_color = "blue") +
geom_brain(definition = "underlay", fill_scale = scale_fill_gradient(low = "grey8", high = "grey62"), show_legend = FALSE) +
geom_brain(definition = "dan_clust", mapping = aes(fill = label), fill_scale = scale_fill_brewer("DAN 17 label", palette = "Set1"), show_legend = TRUE) +
geom_outline(definition = "dan_clust", mapping = aes(group = roi_label), show_legend = TRUE, outline = "black") + # fill_scale = scale_fill_discrete("hello"),
# geom_outline(definition = "dan_clust", show_legend = TRUE, mapping=aes(group=label), size=2, outline="cyan") + #fill_scale = scale_fill_discrete("hello"),
# geom_outline(definition = "dan_clust", show_legend = TRUE, outline = "cyan") + #fill_scale = scale_fill_discrete("hello"),
geom_region_label_repel(image = "dan_clust", label_column = "roi_label", min.segment.length = 0, size = 1.5, color = "black", force_pull = 0.2, max.overlaps = Inf) +
render() + plot_layout(guides = "collect")
Other considerations
Resampling images to have the same resolution
Oftentimes, higher-resolution images (e.g., 1mm) yield better
graphics since they potentially provide more detail. But fMRI data are
often of lower resolution than T1-weighted images. If you wish to render
your fMRI data on a higher-resolution anatomical template in
ggbrain
, you can first use AFNI’s 3dresample
command to resample your functional data to match the anatomical
template (underlay).
Here is an example of resampling a 3mm statistic image to a 1mm underlay using nearest neighbor interpolation. Note that the image to be resampled should be in the same sterotaxic space as the master/template image.
3dresample -input echange_overall_zstat_3mm.nii.gz \
-prefix echange_overall_zstat_1mm.nii.gz \
-master mni_template_2009c_1mm.nii.gz \
-rmode NN
Overview of ggbrain
The ggbrain
package uses the ggplot2
package to create 2D volume renderings of NIfTI files containing MRI
data. It seeks to follow the principles of a graphical grammar in which
plots are built from datasets that are mapped onto the visual space via
a set of aesthetic mappings. Likewise, ggbrain
follows the
approach of creating layers in which different geometric marks (e.g.,
square pixels) are overlaid on the plot, such that many images and marks
can be combined.
The hierarchy of a ggbrain plot
Every ggbrain plot is composed of one or more panels that have layers representing different images that have been overlaid. Each panel contains a slice along one of the three axes of the volume: x (Left-Right), y (Anterior-Posterior), or z (Superior-Inferior). Panels can also contain annotations that reflect one or more marks to aid in the interpretation of the plot, as well as region labels in which text is positioned at certain markers within the displayed brain slice.
- Plot
- Panels (aka Slices)
- Layers: each pixel in the 2D slice contains a value such as a test statistic from a voxelwise analysis. Pixel values can also be categorical, such as levels of a factor (e.g., lobe).
- Annotations: custom text or graphical marks overlaid on the panel
using the ggplot2
annotate
function (e.g., coordinate label) - Region Labels: a variant of ggplot2
geom_text
, region labels represent text that should be overlaid at one or more spatial positions across the panel/slice (e.g., anatomical labels)
- Panels (aka Slices)