From 33c866f46e473384c7dab1b95e8de8744e807daf Mon Sep 17 00:00:00 2001 From: Tim Schaefer Date: Fri, 19 Jun 2020 16:00:19 +0200 Subject: [PATCH] support unnamed data in vis.region.valus.on.subject --- R/fsdir_abstraction_subject.R | 5 +++++ R/morph_atlas_agg.R | 32 +++++++++++++++++++++++++++-- R/vis.R | 2 +- man/spread.values.over.hemi.Rd | 4 ++-- man/vis.region.values.on.subject.Rd | 2 +- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/R/fsdir_abstraction_subject.R b/R/fsdir_abstraction_subject.R index a387353f..9acd6508 100644 --- a/R/fsdir_abstraction_subject.R +++ b/R/fsdir_abstraction_subject.R @@ -627,6 +627,11 @@ labeldata.from.mask <- function(mask, invert=FALSE) { #' #' @export subject.annot <- function(subjects_dir, subject_id, hemi, atlas) { + + if(!(hemi %in% c("lh", "rh", "both"))) { + stop(sprintf("Parameter 'hemi' must be one of 'lh', 'rh' or 'both' but is '%s'.\n", hemi)); + } + if(hemi == "both") { lh_annot_file = file.path(subjects_dir, subject_id, "label", sprintf("%s.%s.annot", "lh", atlas)); if(!file.exists(lh_annot_file)) { diff --git a/R/morph_atlas_agg.R b/R/morph_atlas_agg.R index 9a2322fe..1f7704b3 100644 --- a/R/morph_atlas_agg.R +++ b/R/morph_atlas_agg.R @@ -456,7 +456,7 @@ write.region.values <- function(subjects_dir, subject_id, hemi, atlas, region_va #' #' @param atlas, string. The atlas name. E.g., "aparc", "aparc.2009s", or "aparc.DKTatlas". Used to construct the name of the annotation file to be loaded. #' -#' @param region_value_list, named list. A list in which the names are atlas regions, and the values are the value to write to all vertices of that region. +#' @param region_value_list, named list. A list in which the names are atlas regions, and the values are the value to write to all vertices of that region. You can pass an unnamed list or vector, but then the length must exactly match the number of regions in the atlas, and the order must match the annotation file of the subject and hemisphere. Use with care, and keep in mind that some subjects do not have all regions. #' #' @param value_for_unlisted_regions, numeric scalar. The value to assign to vertices which are part of atlas regions that are not listed in region_value_list. Defaults to NaN. #' @@ -474,17 +474,45 @@ write.region.values <- function(subjects_dir, subject_id, hemi, atlas, region_va #' @family atlas functions #' #' @export -spread.values.over.hemi <- function(subjects_dir, subject_id, hemi, atlas, region_value_list, value_for_unlisted_regions=NaN) { +spread.values.over.hemi <- function(subjects_dir, subject_id, hemi, atlas, region_value_list, value_for_unlisted_regions=NA) { if(!(hemi %in% c("lh", "rh"))) { stop(sprintf("Parameter 'hemi' must be one of 'lh' or 'rh' but is '%s'.\n", hemi)); } annot = subject.annot(subjects_dir, subject_id, hemi, atlas); + + if(is.null(names(region_value_list))) { + # This is not a named list. If the number of values matches the number of atlas regions, we can still use it. + regions = annot$colortable$struct_names; + if(length(region_value_list) == length(regions)) { + names(region_value_list) = regions; + message(sprintf("Received unnamed list for hemi '%s'. That's totally fine, here is the assumed mapping for double-checking:\n%s\n", hemi, pp.named.list(region_value_list))); + } else { + stop(sprintf("Received unnamed data of length %d, but atlas '%s' has %d regions for subject '%s' hemi '%s'. Pass a named list, or make sure the length of your data matches the number of atlas regions.\n", length(region_value_list), atlas, length(regions), subject_id, hemi)); + } + } + spread = spread.values.over.annot(annot, region_value_list, value_for_unlisted_regions=value_for_unlisted_regions); morph_data = spread$spread_data; return(morph_data); } + +#' @title Pretty-print a named list or vector. +#' +#' @param named_list a named list or vector +#' +#' @return character string, the printed list +#' +#' @keywords internal +pp.named.list <- function(named_list) { + dkeys = names(named_list); + dvalues = named_list; + names(named_list) = NULL; + return(paste(dkeys, dvalues, sep='=', collapse=" ")); +} + + #' @title Spread the values in the region_value_list and return them for one hemisphere. #' #' @description Given an atlas and a list that contains one value for each atlas region, create morphometry data in which all region vertices are assigned the value. Can be used to plot stuff like p-values or effect sizes onto brain regions. diff --git a/R/vis.R b/R/vis.R index 48ef09b2..36cdb7ef 100644 --- a/R/vis.R +++ b/R/vis.R @@ -636,7 +636,7 @@ vis.subject.annot <- function(subjects_dir, subject_id, atlas, hemi='both', surf #' #' @param atlas string. The brain atlas to use. E.g., 'aparc' or 'aparc.a2009s'. #' -#' @param lh_region_value_list named list. A list for the left hemisphere in which the names are atlas regions, and the values are the value to write to all vertices of that region. +#' @param lh_region_value_list named list. A list for the left hemisphere in which the names are atlas regions, and the values are the value to write to all vertices of that region. You can pass an unnamed list, but then the its length must exactly match the number of atlas regions. The order of values must also match the order of regions in the annotation, of course. The resulting mapping will be printed so you can check it. #' #' @param rh_region_value_list named list. A list for the right hemisphere in which the names are atlas regions, and the values are the value to write to all vertices of that region. #' diff --git a/man/spread.values.over.hemi.Rd b/man/spread.values.over.hemi.Rd index c20cb037..92187cfe 100644 --- a/man/spread.values.over.hemi.Rd +++ b/man/spread.values.over.hemi.Rd @@ -10,7 +10,7 @@ spread.values.over.hemi( hemi, atlas, region_value_list, - value_for_unlisted_regions = NaN + value_for_unlisted_regions = NA ) } \arguments{ @@ -22,7 +22,7 @@ spread.values.over.hemi( \item{atlas, }{string. The atlas name. E.g., "aparc", "aparc.2009s", or "aparc.DKTatlas". Used to construct the name of the annotation file to be loaded.} -\item{region_value_list, }{named list. A list in which the names are atlas regions, and the values are the value to write to all vertices of that region.} +\item{region_value_list, }{named list. A list in which the names are atlas regions, and the values are the value to write to all vertices of that region. You can pass an unnamed list or vector, but then the length must exactly match the number of regions in the atlas, and the order must match the annotation file of the subject and hemisphere. Use with care, and keep in mind that some subjects do not have all regions.} \item{value_for_unlisted_regions, }{numeric scalar. The value to assign to vertices which are part of atlas regions that are not listed in region_value_list. Defaults to NaN.} } diff --git a/man/vis.region.values.on.subject.Rd b/man/vis.region.values.on.subject.Rd index d4fa877b..1f207450 100644 --- a/man/vis.region.values.on.subject.Rd +++ b/man/vis.region.values.on.subject.Rd @@ -28,7 +28,7 @@ vis.region.values.on.subject( \item{atlas}{string. The brain atlas to use. E.g., 'aparc' or 'aparc.a2009s'.} -\item{lh_region_value_list}{named list. A list for the left hemisphere in which the names are atlas regions, and the values are the value to write to all vertices of that region.} +\item{lh_region_value_list}{named list. A list for the left hemisphere in which the names are atlas regions, and the values are the value to write to all vertices of that region. You can pass an unnamed list, but then the its length must exactly match the number of atlas regions. The order of values must also match the order of regions in the annotation, of course. The resulting mapping will be printed so you can check it.} \item{rh_region_value_list}{named list. A list for the right hemisphere in which the names are atlas regions, and the values are the value to write to all vertices of that region.}