-
Notifications
You must be signed in to change notification settings - Fork 131
Code Guidelines
In order to ensure high-quality methods in SeuratWrappers, as well as to streamline the code review process, we have a few guidelines we ask developers to follow.
Each method and associated helper functions should be placed in a single .R
file, including both exported and internal functions. This file should be placed in the R/
directory and named after the method (eg. fast_mnn.R
). Developers should not modify the .R
files of other methods, or the internal.R
, the latter of which is maintained by the Satija Lab for helper functions that we believe would be useful. Bug fixes, however, are always welcome.
All functions should be documented using Roxygen syntax. Internal functions should omit the '
in the comment block (eg. #
instead of #'
). Please be sure to include @author
, @references
, and @seealso
tags to ensure proper attribution and links back to original code.
We anticipate most code submitted to SeruatWrappers will be standalone functions. However, we welcome the addition of new generics and methods. New generics should have an accompanying Seurat
and default
(or whatever object the "default" method should run on), to allow further extension by other developers (for an example, see alra.R
).
Methods for generics defined in imported packages are welcome. When adding methods for an imported generics, please first have general documentation that corresponds to nothing (NULL
). For example, in conos.R
, we create an empty as.Seurat
documentation for all as.Seurat
methods defined in SeuratWrappers. This dummy documentation inherits parameters from the as.Seurat
generic, sets the Rdocumentation name to something general using the @rdname
tag, and sets the name and alias to the name of the generic function for easy searching (?as.Seurat
will pull up both the Seurat and SeuratWrappers help pages)
#' Extra conversions to Seurat objects
#'
#' @inheritParams Seurat::as.Seurat
#'
#' @rdname as.Seurat.extras
#' @name as.Seurat
#'
#' @seealso \code{\link[Seurat]{as.Seurat}}
#'
#' @aliases as.Seurat
#'
NULL
All methods in SeuratWrappers for the same generic should use the same Rdocumentation name. For example, in velocity.R
, an as.Seurat
method is defined for lists objects. In conos.R
, another method for as.Seurat
is defined, but for Conos
objects. For both methods, the Rdocumentation name is as.Seurat.extras
, so the documentation for all methods gets assembled together.
When accessing data from a Seurat
object, please use Seurat's accessor functions to pull the required data. For slots that don't have an accessor, please use the slot
function. Use of the @
operator to access data is strongly discouraged.
For storing results into a Seurat
object, please use the standard places for storing data. For example, expression data should be stored as an Assay
object. Other places to store data include as a DimReduc
object, a nearest-neighbor Graph
, or object metadata. Data that doesn't correspond to one of these locations can be stored as a list in the tools
slot by using Tool<-
.
We encourage storing command call and parameters for each method. Storing command information can be accomplished with LogSeuratCommand
, which will automatically pick up function name, parameters, and exact call string and store the information in the Seurat
object properly. An example of using LogSeruatObject
can be found below
MyFunction <- function(object, ...) {
object <- LogSeuratCommand(object = object)
return(object)
}
For the most part, we encourage developers to not add dependencies to SeuratWrappers; exceptions can be made on a case-by-case basis. When adding your method, please use CheckPackage
to ensure that your dependent packages are installed and add them to the Suggests
field in DESCRIPTION
. As such, when calling a function from a non-imported, non-dependent package, please use the standard package::function
syntax. Devlopers are welcome to use functions from imported packages, such as Seurat
, so long as they're properly imported using the Roxygen @importFrom
syntax.
Note: Please be sure to add new packages, including for vignettes, to the the
DESCRIPTION
file. For any packages hosted on GitHub, please ensure that you add the GitHub repository to theRemotes
field; Bioconductor and CRAN packages do not need an entry in this field.
SeuratWrappers provides a number of internal helper functions that may come in handy. These functions are documented here:
Reimplemented from Hadley Wickham's answer on StackOverflow, %||%
is a binary operator that returns the value of the right-hand side if the left-hand side is NULL
> x <- NULL
> y <- 5
> x %||% Y
[1] 5
> x <- 2
> x %||% y
[1] 2
Inspired by a need for a reciprocal %||%
, %iff%
is a binary operator that returns the value of the right-hand side if the left-hand side is not NULL
> x <- 2
> y <- 5
> x %iff% y
[1] 5
> x <- NULL
> x %iff% y
[1] NULL
CheckPackage
will check to see if a package is installed and if not, attempt to install it. Installation attempts happen only when R is in interactive mode and only with user permission. Currently, CheckPackage
can install from CRAN (or any CRAN-like repo set in user options), Bioconductor through BiocManager::install
, or from GitHub through remotes::install_github
.
There are two parameters for CheckPackage
: package
and repository
-
package
is the name of the package to check and install. If a GitHub package, please pass the fulluser/repo
name (this requires that the GitHub repository is the same name as the package) -
repository
is eithercran
,bioconductor
, orgithub
IsMatrixEmpty
checks to see if a matrix, or S4 Matrix, has either no dimensionality (nrow
and ncol
are 0) or is a new matrix (nrow
and ncol
are 1, only value is NA
). This covers cases where a matrix is generated from either new(Class = 'matrix')
or matrix()
, as either are valid for empty slots in Seurat Assay
objects