-
Notifications
You must be signed in to change notification settings - Fork 11
For developers
The LESYMAP package can benefit from the contribution of other developers. You can write your own functions, integrate them in LESYMAP, and push your changes in Github. If you have never written an R function before, you may need to form an idea of what is a function first. Maybe this page can help you start.
The following paragraphs explain how the LESYMAP package is organized, so you can integrate your code easily.
All LESYMAP functions can be classified in three main components.
-
The
lesymap.R
file.
This is the generic input-output function that takes your data, runs appropriate checks, transforms the images into a matrix of voxels, submits the matrix and behavioral scores to one of thelsm_*
functions, and puts back the results in images.lesymap.R
is the central interface of the software. The output oflesymap.R
is a list object with all the details of the analyses and the results. Beside the attributelist
the object has an additional attributelesymap
which marks it in R when print or plot functions are called (i.e., you can see a summary of the results simply by typing the name of the variable).
Typically you will not need to edit or changelesymap.R
itself, unless you fix a bug or make a major contribution to the package. -
The
lsm_*.R
files
These are the statistical engines of LESYMAP. If you want to add a new type of analysis, you will probably need to add a newlsm_*
function. Alsm_*
function takes a matrix (often calledlesmat
in the code, which contains voxel values) and a vector (the behavioral scores). The function runs a specific analysis and returns a list object with two vectors:
-
statistic
(i.e., the t-score) and -
pvalue
(statistical probability).
The returned list of outputs is used bylesymap.R
to create the final statistical brain maps (i.e.,stat.img
andpval.img
). In other words, the values ofstatistic
andpvalue
vectors are put back into the corresponding voxels in the image. Beside the required vectors, the output oflsm_*
can contain other objects; e.gzscore
,FWEthreshold
, etc. It can also contain a single character note, e.g.'The function did not converge'
. All these additional objects are added to the final LESYMAP output.
If you want to add a new type of analysis in LESYMAP, you can create a newlsm_*
function (e.g.,lsm_SVR
), which takes the voxel matrix and behavioral score and returns back a list withstatistic
andpvalue
. If your new method does not produce p-values you can return apvalue
vector filled with 1, but you still have to return apvalue
vector as output. The currentlsm_sccan
function does this as well.
N.b., the vectors returned bylsm_*
functions (i.e.,statistic
,pvalue
, etc.) must be of the same length as the number of columns in the voxel matrix, because each voxel must have a value to put back in the image.
Thelsm_*
functions can call other functions, they don't need to be self-standing and perform all processes by themselves. As an example, the currentlsm_regresfast
functions calls internallyregresfast
, which is a fast C++ compiled analysis engine. Onceregresfast
has returned the statistical values,lsm_regresfast
performs a few more checks and returns the results. In other words, you can design your contributions to be modular. If you are wondering why don't we callregresfast
directly instead of callinglsm_regresfast
that is because there are several checks and post-processing steps which are better off performed in R than in C++.
Important, thelsm_*
functions may get several arguments that are not available in the mainlesymap
function. However, the user can still set those arguments, which will go in the...
object and passed along to functions that are called. In this example:
lesymap(lesions, behavior, method='regresfast', covariates=cbind(age,gender))
the argumentcovariates
is not a lesymap argument, but alsm_regresfast
argument. The user can still use it, and what happens is that the argument is passed in a chainlesymap
->lsm_regresfast
->regresfast
.
-
The helper functions.
LESYMAP contains other functions that are not essential but helpful to support the processing pipeline. For examplegetUniqueLesionPatches
computes unique voxels and prepares the data that can be used bylesymap.R
andlsm_*
. Similarlyprint.lesymap
prints the results of alesymap
object in the console. TheregisterLesionToTemplate
is standalone helper function which registers lesion maps in template space.
Let's suppose you want to add a new function to perform lesion-to-symptom mapping with random forests. First, you can create a file named lsm_RFs.R
. In it, you can define the function that will take the behavior vector and the voxel matrix, and will output statistic
and pvalue
. I.e., something like:
lsm_RFs <- function(lesmat, behavior) {
# your analysis here
output = list()
output$statistic = yourstats
output$pvalue = yourpvalues
return(output)
}
Please consider that someone will need to read your code sooner your later (including yourself). For this reason, your variables should have meaningful names. For example, a variable name statistic
is meaningful, while a variable name krstat2
is not.
Second, please add comments to the code, to explain what is being done or why. It is always helpful to read in plain English what the code is doing rather than figuring this out from the code. Something like this would be helpful:
# checking for potential infinite values,
# may happen in BM tests
if (any(is.inf(statistic)))
stop('Infite values found in statistics, something might be wrong`)
Third, each added function requires a documentation header. This documentation is what you see in R when you type i.e. ?lesymap
or ?lsm_sccan
. A specific package is used (roxygen) to build that documentation from the documentation header. Your final function with included documentation may look something like this:
#' lsm_RFs
#'
#' Lesion to symptom mapping performed on a prepared matrix.
#' Random forests are used to analyze the data.
#'
#' @param lesmat binary matrix (0/1) of voxels (columns)
#' and subjects (rows).
#' @param behavior vector of behavioral scores.
#' @param ... other arguments received from \code{\link{lesymap}}.
#'
#' @return
#' List of objects returned:
#' \itemize{
#' \item\code{statistic} - vector of statistical values
#' \item\code{pvalue} - vector of pvalues
#' }
#'
#' @examples{
#' set.seed(123)
#' lesmat = matrix(rbinom(200,1,0.5), ncol=2)
#' set.seed(123)
#' behavior = rnorm(100)
#' result = lsm_RFs(lesmat, behavior)
#' }
#'
#' @author FirstName LastName
#'
#' @export
lsm_RFs <- function(lesmat, behavior, ...) {
# your analysis here
output = list()
output$statistic = yourstats
output$pvalue = yourpvalues
return(output)
}
Fourth, you can use RStudio and open the LESYMAP.proj project. This will open the environment for you to quickly install the package with all your changes, so you can check how the software will work after your changes. When you are done editing, you should can press "Check" in the "Build" tab on the right (or use devtools::check()
), and a thorough check will be performed in search of potential errors. This check is also performed automatically on Github if you push the changes online.
LESYMAP is hosted in Github, a platform that facilitates enormously the tracking of software changes and crowd-sourcing. In Github you can go back at any development stage and check the history of how each file was changed in the past. To integrate your code in LESYMAP you need to make the changes in a branch of your own, then create a pull request. Your changes will be automatically checked for coding or compiling errors in the Travis platform, and then will be evaluated by a human. If the changes are useful to the community and do not compromise the existing LESYMAP functionality, your code will be merged with the master branch.
If you don't know how to create a pull request in Github, or what is a software branch, please google those terms and learn the basics. The learning curve is typically quick. If you don't like the learning process... well, you you probably don't like programming either. :)
That's it, feel free to open a github issue if you embark in the endeavor of helping out with LESYMAP development.