knitr::opts_chunk$set(echo = TRUE) rgl::setupKnitr()
First we specify a subjects dir and the subject we want to use. Feel free to replace this with your data.
library('fsbrain') sjd = '~/data/subject1_only' sj = 'subject1'
Now increase the figure size.
fsbrain.set.default.figsize(1000, 1000);
Let's start with a basic example and plot cortical thickness on the surface of our subject:
vis.subject.morph.native(sjd, sj, 'thickness')
This loaded the morphometry data files surf/lh.thickness
and surf/rh.thickness
of the subject, applied a colormap to the values, and visualized the results on the white surface, i.e., the brain surface meshes in the files surf/lh.white
and surf/rh.white
.
The default view above shows the brain from four different angles in four tiles and is called t4
view. Maybe you prefer a different view? In addition, let's mask the medial wall (the large blue parts in the lower two tiles).
vis.subject.morph.native(sjd, sj, 'thickness', views='t9', cortex_only = TRUE)
The mask for the medial wall was created by setting the data of all vertices which are not part of the cortex to NA
, based on the cortex definition in the label files label/lh.cortex.label
and label/rh.cortex.label
of the subject.
Next, we will try a third view, add a colorbar, use the pial surface, and plot something different. Let's try mean curvature.
vis.subject.morph.native(sjd, sj, 'curv', views='si', cortex_only = TRUE, draw_colorbar = 'vertical', surface = 'pial')
That does not look very exciting. Why? The curvature data has long tails and is far from Normal:
hist(subject.morph.native(sjd, sj, 'curv', hemi = 'both'))
There are various solutions to this problem, but for plotting, the easiest one is to apply some function that removes outliers or performs some other sort of data transformation before plotting. You can pass any transformation function you want using rglactions, in the next example we clip the data.
The si
view is single interactive view, and you can rotate the brain with your mouse in an R session. That is not possible in this markdown document though, so better try it in R. We will use another view here and switch back to the white surface.
vis.subject.morph.native(sjd, sj, 'curv', views='sd_medial_lh', cortex_only = TRUE, draw_colorbar = 'horizontal', rglactions=list('trans_fun'=clip.data))
That looks more suitable.
In group studies, you typically have a single standard space that data gets mapped to for comparison. For FreeSurfer surface data, typically the fsaverage subject is used, but you could create and use your own template, of course. Let's have a look at some standard space data mapped to fsaverage. We will use sulcal depths in this example.
vis.subject.morph.standard(sjd, sj, 'sulc', cortex_only = TRUE, fwhm="5");
This loaded the morphometry data files surf/?h.curv.fwhm5.fsaverage.mgh
of the subject, applied a colormap to the values, and visualized the results on the white surface of fsaverage (also using the fsaverage cortex labels). The function will do its best to find fsaverage automatically, but if it fails or you want to use a different template subject, have a look at the optional parameters template_subject
and template_subjects_dir
.
When data is mapped to standard space, they will get smoothed and different versions with a number of kernel settings will be available after running FreeSurfer's recon-all
with the qcache
option. That is what the fwhm
parameter is about. Try different values depending on what files you have, start with "5", "10", or "15".
The exact colormap you use is a matter of taste, but you should maybe chose a type of colormap that is suitable for your data: sequential like heat
for morphometry data, diverging like cm.colors
for positive and negative clusters, or qualitative like Set3
from the RColorbrewer
package for atlas regions. The default colormap used by fsbrain is a sequential multi-hue palette (squash::rainbow2
).
A great and popular sequential palette is viridis
from the viridis
package. Here we used the makecmap_options
parameter to use it:
vis.subject.morph.standard(sjd, sj, 'sulc', cortex_only = TRUE, fwhm="15", makecmap_options = list('colFn'=viridis::viridis), draw_colorbar = T, views='sd_dorsal');
Try some different colormaps and see which one you like best. If you want to use interpolated colormaps with many colors based on the RColorBrewer
palettes (which have too few colors for morphometry data in most cases), try something like this:
manyblues = colorRampPalette(RColorBrewer::brewer.pal(9, name="Blues")); vis.subject.morph.standard(sjd, sj, 'area', makecmap_options = list('colFn'=manyblues), draw_colorbar = T, views='sd_dorsal');
If you prefer a smoother colorbar, try increasing the number of colors by adapting the makecmap_options
parameter, e.g.:
makecmap_options = list('colFn'=manyblues, 'n=100')
Plotting a brain parcellation is straightforward, here we plot the Desikan atlas:
vis.subject.annot(sjd ,sj, 'aparc');
This loads the Desikan labels for the subject from the files label/?h.aparc.annot
and uses colors from the contained color lookup table.
By default, FreeSurfer computes brain parcellations for the following brain atlases:
Of course, one can select different view angles, surfaces, and other options as illustrated above for morphometry data.
A unique option that is available with annotations is to draw outlines around them:
vis.subject.annot(sjd ,sj, 'aparc', outline = TRUE, surface="inflated");
You can customize the look of the outlines (or region borders) by passing a list of extra arguments to annot.outline
instead of a logical value, see the documentation for details. Here is a more complex example that draws a green border around the middle temporal gyrus and a blue border around the postcentral gyrus:
vis.subject.annot(sjd ,sj, 'aparc', outline=list('outline_color'=c('green', 'blue'), 'limit_to_regions'=c('middletemporal', 'postcentral'), expand_inwards=2L), surface="inflated", views="sd_lateral_lh");
Note that you can also use this function for drawing borders around arbitrary custom regions (activation cluster or whatever). A custom region really is nothing but a label, and you can convert a label (or several labels) to an annotation using label.to.annot
.
Here is an example for visualizing a label:
vis.subject.label(sjd, sj, 'cortex', hemi='lh', views = 'sd_medial_lh');
Here, the file label/lh.cortex.label
was used. If you want to visualize preloaded data, there is no need to save it to a file first, just use the vis.labeldata.on.subject
function.
If you perform atlas based analyses, you will typically get one result (significance, effect size, or whatever) per atlas region. The function vis.region.values.on.subject
comes in very handy here. Typically the results are displayed on the fsaverage subject, but you can use any subject you want:
atlas = 'aparc'; # Desikan atlas # For the left hemisphere, we just assign a subset of the # atlas regions. The others will get the default value. lh_region_value_list = list("bankssts"=0.9, "precuneus"=0.7, "postcentral"=0.8, "lingual"=0.6); # For the right hemisphere, we retrieve the full list of regions for # the atlas, and assign random values to all of them. atlas_region_names = get.atlas.region.names(atlas, template_subjects_dir = sjd, template_subject = sj); rh_region_value_list = rnorm(length(atlas_region_names), 0.8, 0.2); names(rh_region_value_list) = atlas_region_names; vis.region.values.on.subject(sjd, sj, atlas, lh_region_value_list, rh_region_value_list, draw_colorbar = T);
If your data are symmetric around zero, e.g., t-values, you should use a symmetric colormap. An example is available in the default makecmap_topions settings of the vis.symmetric.data.on.subject
function, which we will use next.
When performing vertex-wise analyses in standard space, you get one result per vertex, e.g., a t-map, which may be thresholded to yield clusters. Here is an example that visualizes the clusters and uses a gray-scale background computed from the mean curvature of the fsaverage cortex:
subjects_dir = file.path(find.freesurferhome()$found_at, 'subjects'); subject_id = 'fsaverage'; lh_demo_cluster_file = system.file("extdata", "lh.clusters_fsaverage.mgz", package = "fsbrain", mustWork = TRUE); rh_demo_cluster_file = system.file("extdata", "rh.clusters_fsaverage.mgz", package = "fsbrain", mustWork = TRUE); lh_clust = freesurferformats::read.fs.morph(lh_demo_cluster_file); # contains a single positive cluster (activation, group difference), the other values are 0 rh_clust = freesurferformats::read.fs.morph(rh_demo_cluster_file); # contains two negative clusters vis.symmetric.data.on.subject(subjects_dir, subject_id, lh_clust, rh_clust, bg="curv_light");
To learn more, read the vignettes:
browseVignettes('fsbrain');
In general, the vignettes are a great way to get started with fsbrain. You can also read them online at CRAN, they are linked on the fsbrain page on GitHub.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.