#' @name read10xRaw
#'
#' @title Read 10x Space Ranger output data
#'
#' @description \code{read10xRaw()} is a one-line handy function for reading
#' the raw expression data from 10x Space Ranger outputs and producing a count
#' matrix as an R object.
#'
#' \code{read10xRawH5()} is for reading 10x Space Ranger
#' output HDF5 file (ended with .h5).
#'
#' \code{read10xSlide()} is for reading slide
#' information (e.g. spot positions) and the tissue image from 10x
#' Space Ranger outputs. This function is developed based on 10x's secondary
#' analysis pipeline
#' https://support.10xgenomics.com/spatial-gene-expression/software/pipelines/latest/rkit.
#'
#' @param count_dir (chr) The directory of 10x output matrix data.
#' The directory should include
#' three files: barcodes.tsv.gz, features.tsv.gz, matrix.mtx.gz.
#'
#' @param h5_file (chr) The path of 10x output matrix HDF5 file
#' (ended with .h5).
#'
#' @param tissue_csv_file (chr) The path of 10x output CSV file of
#' spot positions, usually named \code{tissue_positions_list.csv} for
#' Space Ranger V1 and \code{tissue_positions.csv} for Space Ranger V2.
#'
#' @param tissue_img_file (chr) The path of the 10x output low resolution
#' tissue image in PNG format,
#' usually named \code{tissue_lowres_image.png}. If \code{NULL},
#' the returned slide data does not contain image
#' information. Please do provide this file if you could find it.
#' Default: \code{NULL}
#'
#' @param scale_factor_file (chr) The path of the 10x output scale factor
#' file in json format, usually named \code{scalefactors_json.json}.
#' If \code{NULL}, spot positions in image will
#' not be corrected by the scale factor. Please do provide this file
#' if you could find it. Default: \code{NULL}
#'
#' @param row_name (chr) Specify either using gene symbols
#' (\code{row_name = "symbol"}) or gene Ensembl IDs (\code{row_name = "id"})
#' as row names of the count matrix.
#' Default: \code{row_name = "symbol"}
#'
#' @param meta (logical) If \code{TRUE}, \code{read10xRaw} or
#' \code{read10xRawH5} returns a list containing both the
#' count matrix and metadata of genes (features). Metadata includes feature
#' names, IDs and other additional information depending on Space Ranger
#' output. If \code{FALSE}, only returns the count matrix.
#' Default: \code{FALSE}
#'
#' @return If \code{meta = TRUE}, \code{read10xRaw()} or \code{read10xRawH5()}
#' returns a list of two elements: a
#' "dgCMatrix" sparse matrix containing expression counts and a data
#' frame containing metadata of genes (features). For the count matrix,
#' each row is a gene (feature) and each column is a spot barcode. If
#' \code{meta = FALSE}, only returns the count matrix.
#'
#' \code{read10xSlide()} returns a list of two objects. The first object, slide,
#' is a data.frame where each row corresponds to a spot
#' and each column corresponds to slide information such as row and column
#' positions on the slide. The second object, grob, is a Grid Graphical Object
#' of the tissue image when specifying \code{tissue_img_file}.
#'
#' @examples
#'
#' # simulate 10x output files of count matrix
#' data(mbrain_raw)
#' data_dir <- file.path(tempdir(),"sim_example")
#' dir.create(data_dir)
#' matrix_dir <- file.path(data_dir,"matrix.mtx")
#' barcode_dir <- gzfile(file.path(data_dir, "barcodes.tsv.gz"), open="wb")
#' gene_dir <- gzfile(file.path(data_dir, "features.tsv.gz"), open="wb")
#'
#' # For simplicity, use gene names to generate gene IDs to fit the format.
#' gene_name <- rownames(mbrain_raw)
#' gene_id <- paste0("ENSG_fake_",gene_name)
#' barcode_id <- colnames(mbrain_raw)
#'
#' Matrix::writeMM(mbrain_raw,file = matrix_dir)
#' write(barcode_id,file = barcode_dir)
#' write.table(cbind(gene_id,gene_name,"type"),file = gene_dir,
#' sep = "\t", quote = FALSE, col.names = FALSE, row.names = FALSE)
#' R.utils::gzip(matrix_dir)
#' close(barcode_dir)
#' close(gene_dir)
#'
#'
#' # read expression count matrix
#' list.files(data_dir)
#' mbrain_raw_new <- read10xRaw(data_dir)
#' str(mbrain_raw_new)
#' identical(mbrain_raw, mbrain_raw_new)
#'
#' # read slide metadata
#' spatial_dir <- system.file(file.path("extdata",
#' "V1_Adult_Mouse_Brain_spatial"),
#' package = "SpotClean")
#' list.files(spatial_dir)
#' mbrain_slide_info <- read10xSlide(tissue_csv_file=file.path(spatial_dir,
#' "tissue_positions_list.csv"),
#' tissue_img_file = file.path(spatial_dir,
#' "tissue_lowres_image.png"),
#' scale_factor_file = file.path(spatial_dir,
#' "scalefactors_json.json"))
#' str(mbrain_slide_info)
#' @rdname Read10x
#' @importFrom utils read.delim
#' @importFrom Matrix readMM
#' @importFrom Matrix sparseMatrix
#'
#'
#' @export
read10xRaw <- function(count_dir = NULL,
row_name = "symbol",
meta = FALSE) {
if(is.null(count_dir)){
count_dir <- getwd()
}
if (!row_name %in% c("symbol", "id"))
stop("row_name should be either \"symbol\" or \"id\".")
if (!dir.exists(count_dir))
stop("Directory does not exist.")
count_dir <- gsub("/$", "", count_dir)
fname <- list.files(count_dir)
# Path to files
if(!all(c("barcodes.tsv.gz","features.tsv.gz",
"matrix.mtx.gz")%in%fname)){
stop("No 10x output file detected.")
}
Barcode <- file.path(count_dir, "barcodes.tsv.gz")
Gene <- file.path(count_dir, "features.tsv.gz")
CountMat <- file.path(count_dir, "matrix.mtx.gz")
# Read gene and barcode info
barcode <- readLines(Barcode)
gene.meta <- read.delim(Gene, header = FALSE, colClasses = "character")
colnames(gene.meta) <- c("id", "symbol", "type")
if (row_name == "symbol") {
#gene names as row names of count matrix
gene <- gene.meta$symbol
} else{
#gene ids as row names of count matrix
gene <- gene.meta$id
}
# Read count matrix
countmat <- as(readMM(CountMat), "CsparseMatrix")
colnames(countmat) <- barcode
rownames(countmat) <- make.unique(gene)
if (meta) {
#return a list including count matrix and gene metadata
return(list(CountMatrix = countmat, Metadata = gene.meta))
} else{
#only return count matrix
return(countmat)
}
}
#' @rdname Read10x
#' @importFrom rhdf5 h5ls
#' @importFrom rhdf5 h5read
#'
#' @export
read10xRawH5 <- function(h5_file,
row_name = "symbol",
meta = FALSE) {
if (!row_name %in% c("symbol", "id"))
stop("row_name should be either \"symbol\" or \"id\".")
if (!file.exists(h5_file))
stop("File does not exist.")
fname <- h5ls(h5_file)
data.temp <- h5read(h5_file, "/matrix")
barcode <- data.temp$barcodes
gene.meta <- data.temp$features
if (row_name == "symbol") {
#gene names as row names of count matrix
gene <- gene.meta$name
} else{
#gene ids as row names of count matrix
gene <- gene.meta$id
}
countmat <-
sparseMatrix(
i = data.temp$indices,
p = data.temp$indptr,
x = as.numeric(data.temp$data),
index1 = FALSE,
dims = data.temp$shape
)
colnames(countmat) <- as.vector(barcode)
rownames(countmat) <- make.unique(gene)
if (meta) {
#return a list including count matrix and gene metadata
return(list(CountMatrix = countmat, Metadata = gene.meta))
} else{
#only return count matrix
return(countmat)
}
}
#' @rdname Read10x
#' @importFrom utils read.csv
#' @importFrom readbitmap read.bitmap
#' @import grid
#' @importFrom rjson fromJSON
#' @importFrom methods as
#'
#' @export
read10xSlide <- function(tissue_csv_file,
tissue_img_file = NULL,
scale_factor_file = NULL){
# Load tissue information
slide <- read.csv(tissue_csv_file,
col.names=c("barcode","tissue","row",
"col","imagerow","imagecol"),
header = FALSE)
# For Space Ranger V2, re-read CSV with header=TRUE
if(inherits(slide$tissue,"character")){
slide <- read.csv(tissue_csv_file,
col.names=c("barcode","tissue","row",
"col","imagerow","imagecol"),
header = TRUE)
}
slide$tissue <- as.factor(slide$tissue)
grob <- NULL
# Load tissue image
if(!is.null(tissue_img_file)){
# Load downsampled image
tissue_img_file <- read.bitmap(tissue_img_file)
grob <- rasterGrob(tissue_img_file,
width=unit(1,"npc"),
height=unit(1,"npc"))
slide$height <- nrow(tissue_img_file)
slide$width <- ncol(tissue_img_file)
}
# Load scale factor
if(!is.null(scale_factor_file)){
scales <- rjson::fromJSON(file = scale_factor_file)
slide$imagerow <- slide$imagerow * scales$tissue_lowres_scalef
slide$imagecol <- slide$imagecol * scales$tissue_lowres_scalef
}
return(list(slide=slide, grob=grob))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.