diff --git a/DESCRIPTION b/DESCRIPTION index 912c9eb..0e1b59f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: schard Title: Reticulate-free single cell object conversion -Version: 0.0.0.9000 +Version: 0.0.1 Authors@R: person(given = "Pavel", family = "Mazin", @@ -14,8 +14,8 @@ Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 Imports: Matrix, - rhdf5 Suggests: SingleCellExperiment, - Seurat + Seurat, + rhdf5 diff --git a/NAMESPACE b/NAMESPACE index 4de9a36..512f38b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,9 @@ # Generated by roxygen2: do not edit by hand +export(h5ad2Matrix) export(h5ad2data.frame) export(h5ad2list) export(h5ad2sce) -export(h5ad2seurat_l_spatial) +export(h5ad2seurat) +export(h5ad2seurat_spatial) import(Matrix) diff --git a/R/functions.R b/R/functions.R index 673d223..0d54bf6 100644 --- a/R/functions.R +++ b/R/functions.R @@ -1,67 +1,52 @@ -#' Loads h5ad file as ordinary R list +#' Loads main parts of h5ad file as ordinary R list #' #' @param filename path to h5ad file -#' @param load.raw character, either 'no' (do not load raw), 'both' (load both adata.raw nad adata.X), or 'replace' (load raw only if exists) +#' @param load.raw logical, whether to load adata.raw.X instead of adata.X +#' @param load.obsm logical, whether to load adata.obsm. #' #' @return list with following elements: #' obs - data.frame #' var - data.frame #' X - matrix (dense or sparse - as it was in X) -#' reducedDim - list of matrices with reduced dimmensions -#' raw - list, eitehr empty (if load.raw is false or if raw is not present) +#' obsm - list of matrices from obsm (presumably reduced dimensions) #' @export -h5ad2list = function(filename,load.raw='no'){ - a = rhdf5::H5Fopen(filename,flags = 'H5F_ACC_RDONLY') - - tryCatch({ - obs = h5ad2data.frame(a,'obs') - var = h5ad2data.frame(a,'var') - raw = list() - X = NULL - - if(load.raw %in% c('no','both') || !rhdf5::H5Lexists(a,'raw/X')){ - X = pasreH5ADMatrix(a,'X') - rownames(X) = rownames(var) - colnames(X) = rownames(obs) +h5ad2list = function(filename,use.raw=FALSE,load.obsm=FALSE){ + h5struct = rhdf5::h5ls(filename) + res = list() + res$obs = h5ad2data.frame(filename,'obs') + if(use.raw){ + if(!any(h5struct$group=='/raw/X')){ + stop(paste0('There is not raw slot in "',filename,'" please set "use.raw" to FALSE')) } - if(load.raw %in% c('both','replace')){ - if(rhdf5::H5Lexists(a,'raw/X')){ - raw$X = pasreH5ADMatrix(a,'raw/X') - raw$var = h5ad2data.frame(a,'raw/var') - rownames(raw$X) = rownames(raw$var) - colnames(raw$X) = rownames(obs) - }else{ - warning('adata.raw is not found, will use adata.X instead') - } - } - if(load.raw == 'replace'){ - X = raw$X - var = raw$var - raw = list() - } - # reduced dims - reducedDim = list() - for(n in names(a$obsm)){ - if(is.array(a$obsm[[n]])) - reducedDim[[n]] = t(a$obsm[[n]]) + res$X = h5ad2Matrix(filename,'raw/X') + res$var = h5ad2data.frame(filename,'raw/var') + }else{ + res$X = h5ad2Matrix(filename,'X') + res$var = h5ad2data.frame(filename,'var') + } + rownames(res$X) = rownames(res$var) + colnames(res$X) = rownames(res$obs) + + res$obsm = list() + if(load.obsm){ + for(n in h5struct$name[h5struct$group=='/obsm']){ + obsm = t(h5ad2Matrix(filename,paste0('obsm/',n))) # they are transposed for some reason... + if(is.array(obsm)) + res$obsm[[n]] = obsm } - rhdf5::H5Fclose(a) - },error=function(e){ - rhdf5::H5Fclose(a) - stop(e) - }) - list(obs=obs,var=var,X=X,reducedDim = reducedDim, - raw=raw) + } + res } -#' Loads h5ad scanpy single cell file as SingleCellExperiment +#' Loads h5ad as SingleCellExperiment object #' #' functions exports X,obs,var and obsm #' it is very experimental and comes with no warranty #' #' @param filename path to h5ad file #' @param use.raw logical, whether to attempt to get data from adata.raw. Throws warning (not exception!) if adata.raw is not present and proceeds with adata.X. +#' @param load.obsm logical, whether to load adata.obsm. All matrix-like objects from there will be added as reducedDim to the output object. #' #' @return SingleCellExperiment object #' @export @@ -69,143 +54,172 @@ h5ad2list = function(filename,load.raw='no'){ #' @import Matrix #' @examples #' sce = h5ad2sce('adata.h5ad') -h5ad2sce = function(filename,use.raw=FALSE){ +h5ad2sce = function(filename,use.raw=FALSE,load.obsm=TRUE){ loadRequiredPackages('SingleCellExperiment') - data = h5ad2list(filename,load.raw = ifelse(use.raw,'replace','no')) + data = h5ad2list(filename,use.raw = use.raw,load.obsm=load.obsm) sce = SingleCellExperiment(list(X=data$X), colData=data$obs, rowData=data$var ) # reduced dims - for(n in names(data$reducedDim)){ - reducedDim(sce,n) = data$reducedDim[[n]] + for(n in names(data$obsm)){ + reducedDim(sce,n) = data$obsm[[n]] } sce } -#' Loads scanpy h5ad file with Visium data into list of Seurat objects +#' Loads h5ad as Seurat object +#' +#' For non-spatial data only, use h5ad2seurat_spatial for Visium +#' +#' @param filename path to h5ad file +#' @param use.raw logical, whether to use adata.raw instead of adata.X +#' @param load.obsm logical, whether to load adata.obsm. All matrix-like objects from there will be added as DimReduc to the output object with names coerced to Seurat style (that is not underscores in the middle, single underscore at the end). +#' @param assay what assay to put data it (RNA by default) +#' +#' @return Seurat object +#' @export +#' +#' @import Matrix +#' @examples +#' seu = h5ad2seurat('adata.h5ad') +h5ad2seurat = function(filename,use.raw=FALSE,load.obsm=TRUE,assay='RNA'){ + loadRequiredPackages('Seurat') + data = h5ad2list(filename,use.raw = use.raw,load.obsm = load.obsm) + + seu = CreateSeuratObject(counts = data$X,assay = assay) + seu@meta.data = data$obs + seu@assays[[assay]]@meta.features = data$var + + # reduced dims + # move spatial to X_spatial (that is Xspatial_ in Seurat) to a) do not interact with Seurat[['spatial_']] b) consistency between adata versions + names(data$obsm)[names(data$obsm) == 'spatial'] = 'X_spatial' + + for(n in names(data$obsm)){ + nn = paste0(gsub('_','',n),'_') # Seurat naming requirements + colnames(data$obsm[[n]]) = paste0(nn,1:ncol(data$obsm[[n]])) # Seurat wants to have colnames + rownames(data$obsm[[n]]) = rownames(data$obs) + seu[[nn]] <- CreateDimReducObject(embeddings = data$obsm[[n]], key = nn, assay = assay) + } + seu +} + + +#' Loads scanpy h5ad file with Visium data into Seurat object #' -#' simplifies to single Seurat object if there is just one sample (see simplify parameter) #' #' @param filename character, path to h5ad file -#' @param library_id_field name of adata.obs that specifies visium library. Function trys to guess it if set to NULL (default). -#' @param simplify logical, whether return just seurat object (instead of list) if there is only one sample #' @param use.raw logical, whether to attempt to get data from adata.raw. Throws warning (not exception!) if adata.raw is not present and proceeds with adata.X. +#' @param load.obsm logical, whether to load adata.obsm. All matrix-like objects from there will be added as DimReduc to the output object with names coerced to Seurat style (that is not underscores in the middle, single underscore at the end). +#' @param simplify logical, whether to merge loaded samples into single object, return list otherwise. +#' @param img.res which of lowres' or 'hires' image to be loaded #' #' @return list of Seurat object #' @import Matrix #' @export -h5ad2seurat_l_spatial = function (filename,library_id_field=NULL,simplify=TRUE,use.raw=FALSE){ +#' @examples +#' vs = h5ad2seurat_spatial('adata.h5ad') +h5ad2seurat_spatial = function(filename,use.raw=FALSE,load.obsm=TRUE,simplify=TRUE,img.res = 'lowres'){ loadRequiredPackages('Seurat') - data = h5ad2list(filename,load.raw = ifelse(use.raw,'replace','no')) - - a = rhdf5::H5Fopen(filename,flags = 'H5F_ACC_RDONLY') - tryCatch({ - obs = data$obs - var = data$var - X = data$X - - # find column in obs all values of each has spatial data in a$uns$spatial - if(is.null(library_id_field)){ - imglibs = names(a$uns$spatial) - for(obsf in colnames(obs)){ - if(all(obs[,obsf] %in% imglibs)){ - library_id_field = obsf - break - } - } - # if there is not library field in obs we will only be able to proceed if the h5ad contains single samples: - if(is.null(library_id_field)){ - if(length(imglibs) == 1){ - # generate filed name that is not already in use - library_id_field = 'library_id' - repeat{ - if(!(library_id_field %in% colnames(obs))) break - library_id_field = paste0(library_id_field,'_') - } - obs[,library_id_field] = imglibs - }else{ - stop("The h5ad seems to contain multiple visium samples but library is not specified correctly in adata.obs. There should be a column that matches keys is adata.uns.spatial.") - } + data = h5ad2list(filename,use.raw = use.raw,load.obsm = TRUE) # load obsm in any case - we need spatial info + images = h5ad2images(filename) + results = list() + + # find column all values of each has images + library_id_field = NULL + for(col in colnames(data$obs)){ + if(all(data$obs[,col] %in% names(images))){ + library_id_field = col + break + } + } + # if there is not library field in obs we will only be able to proceed if the h5ad contains single samples: + if(is.null(library_id_field)){ + if(length(images) == 1){ + # generate filed name that is not already in use + library_id_field = 'library_id' + repeat{ + if(!(library_id_field %in% colnames(data$obs))) break + library_id_field = paste0(library_id_field,'_') } + data$obs[,library_id_field] = names(images) + }else{ + stop("The h5ad seems to contain multiple visium samples but library is not specified correctly in adata.obs. There should be a column that matches keys is adata.uns.spatial.") } - # load images and assemble Seurat objects - # coordinates can be either in spatial or in X_spatial - coor.names = 'spatial' - if(!(coor.names %in% names(a$obsm))) - coor.names = 'X_spatial' - res = list() - for(lid in unique(obs[[library_id_field]])){ - # subset obs - f = obs[[library_id_field]] == lid - obs_ = obs[f,] - if(!is.null(obs_$barcode)){ - rownames(obs_) = obs_$barcode + } + # rename spatial to X_spatial + names(data$obsm)[names(data$obsm)=='spatial'] = 'X_spatial' + + # create per sample Seurats + for(lid in unique(data$obs[,library_id_field])){ + f = data$obs[,library_id_field] == lid + obs_ = data$obs[f,] + x_spatial_ = data$obsm$X_spatial[f,2:1] # manually discovered that coordinates are transposed + + seu = CreateSeuratObject(counts = data$X[,rownames(obs_)], assay = 'Spatial') + seu@meta.data = cbind(seu@meta.data,obs_) + seu@assays$Spatial@meta.features = data$var + + # add dim reductions (if any) + if(load.obsm){ + for(n in setdiff(names(data$obsm),'X_spatial')){ + nn = paste0(gsub('_','',n),'_') # Seurat naming requirements + obsm_ = data$obsm[[n]][f,] + colnames(obsm_) = paste0(nn,1:ncol(obsm_)) # Seurat wants to have colnames + rownames(obsm_) = rownames(obs_) + seu[[nn]] = CreateDimReducObject(embeddings = obsm_, key = nn, assay = 'Spatial') } - # subset counts - X_ = X[,which(f)] - colnames(X_) = rownames(obs_) - object = CreateSeuratObject(counts = X_, assay = 'Spatial') - - # extract image - image = loadImageFromH5ad(a,lid,obs_,t(a$obsm[[coor.names]][,f])[,2:1]) - - image = image[Cells(x = object)] - DefaultAssay(object = image) = 'Spatial' - object[['slice1']] = image - - object@meta.data = cbind(object@meta.data,obs_) - rownames(object@meta.data) = rownames(obs_) + } - object@assays$Spatial@meta.features = var - res[[lid]] = object + # prepare image + # set to mock if mesh coordinaates are not in obs + tissue.positions = obs_ + if(is.null(tissue.positions$in_tissue)) tissue.positions$in_tissue = 1 + if(is.null(tissue.positions$array_row)) tissue.positions$array_row = 0 + if(is.null(tissue.positions$array_col)) tissue.positions$array_col = 0 + + tissue.positions = cbind(tissue.positions[,c('in_tissue','array_row','array_col')], x_spatial_) + colnames(tissue.positions) = c("tissue", "row", "col", "imagerow", "imagecol") + rownames(tissue.positions) = rownames(obs_) + + scale.factors = images[[lid]]$scale.factors + # if specified resolution is not in h5ad, try another + if(!(img.res %in% names(images[[lid]]))){ + warning(paste0("'",img.res,"' is not avaliable, trying another resolution",)) + img.res = setdiff(c('hires','lowres'),img.res) + } + if(!(img.res %in% names(images[[lid]]))){ + stop('No image avaliable in h5ad') } - },error=function(e){ - rhdf5::H5Fclose(a) - stop(e) - }) - if(simplify & length(res)==1) - res = res[[1]] + if(img.res == 'hires'){ + scale.factors$tissue_lowres_scalef = scale.factors$tissue_hires_scalef + } - rhdf5::H5Fclose(a) - return(res) + image = images[[lid]][[img.res]] + + # just copied from Seurat::Read10X_Image + unnormalized.radius = scale.factors$fiducial_diameter_fullres * scale.factors$tissue_lowres_scalef + spot.radius = unnormalized.radius/max(dim(x = image)) + image = new(Class = "VisiumV1", image = image, scale.factors = scalefactors(spot = scale.factors$tissue_hires_scalef, + fiducial = scale.factors$fiducial_diameter_fullres, + hires = scale.factors$tissue_hires_scalef, + scale.factors$tissue_lowres_scalef), + coordinates = tissue.positions, spot.radius = spot.radius) + + image = image[Cells(x = seu)] + DefaultAssay(object = image) = 'Spatial' + seu[[lid]] = image + results[[lid]] = seu + } + if(simplify){ + if(length(results)==1) + results = results[[1]] + else{ + results = merge(results[[1]],results[-1]) + } + } + results } - -#' Loads Seurat VisiumV1 object from visium h5ad -#' -#' there is some magic in this function, I'm not sure why and how it works (but it works). -#' the function is not supposed to be used for its own, only from h5ad2seurat_l_spatial -#' -#' @param a H5IdComponent (for whole h5ad file) -#' @param lid library_id, the key in a.uns.spatia -#' @param obs_ subset of adata.obs for this particular object -#' -#' @return VisiumV1 object -loadImageFromH5ad = function(a,lid,obs_,obsm_){ - # extract image - ires = 'hires' - if(!(ires %in% names(a$uns$spatial[[lid]]$images))) - ires = 'lowres' - image <- aperm(a$uns$spatial[[lid]]$images[[ires]],3:1) - - scale.factors <- a$uns$spatial[[lid]]$scalefactors - # looks like in scanpy both images are hires actually (at least they were identical for example I tried) - scale.factors$tissue_lowres_scalef = scale.factors$tissue_hires_scalef - - tissue.positions = cbind(obs_[,c('in_tissue','array_row','array_col')], obsm_) - colnames(tissue.positions) = c("tissue", "row", "col", "imagerow", "imagecol") - - rownames(tissue.positions) = rownames(obs_) - - unnormalized.radius = scale.factors$fiducial_diameter_fullres * scale.factors$tissue_lowres_scalef - spot.radius = unnormalized.radius/max(dim(x = image)) - image = new(Class = "VisiumV1", image = image, scale.factors = scalefactors(spot = scale.factors$tissue_hires_scalef, - fiducial = scale.factors$fiducial_diameter_fullres, - hires = scale.factors$tissue_hires_scalef, - scale.factors$tissue_lowres_scalef), - coordinates = tissue.positions, spot.radius = spot.radius) - image -} diff --git a/R/h5ad_util.R b/R/h5ad_util.R new file mode 100644 index 0000000..af181d1 --- /dev/null +++ b/R/h5ad_util.R @@ -0,0 +1,114 @@ +loadRequiredPackages = function(pkgs){ + for(pkg in pkgs){ + if(!require(pkg,character.only =TRUE)) + stop(paste0('Please install package "',pkg,'"')) + } +} + +#' Extracts data.frame from h5ad file +#' +#' @param filename file name or H5IdComponent to read data.frame from +#' @param name name of group that contains data.frame to be loaded +#' +#' @return a data.frame +#' @export +#' @examples +#' obs = h5ad2data.frame('adata.h5ad','obs') +h5ad2data.frame = function(filename,name){ + collist = rhdf5::h5read(filename,name,read.attributes = TRUE) + attr = attributes(collist) + # slashes in names leads to nested structure, lets fix it + ll = sapply(collist,length) + for(i in which(ll==1)){ + n = names(collist)[[i]] + repeat{ + if(length(collist[[i]])>1) + break + n = paste0(n,'/',names(collist[[i]])) + collist[[i]] = collist[[i]][[1]] + } + names(collist)[i] = n + } + + # factors are stored as list of categories and names, other types are stored as vectors + # take them first + ll = sapply(collist,length) + res = as.data.frame(collist[ll==max(ll)],check.names=FALSE) + + # first way to store factors + for(fn in names(collist[['__categories']])){ + res[[fn]] = as.vector(collist[['__categories']][[fn]][res[[fn]]+1]) + } + # another way to store factors + for(fn in names(ll)[ll==2 & ll != max(ll)]){ + if(all(names(collist[[fn]]) %in% c("categories","codes"))){ + res[[fn]] = as.vector(collist[[fn]]$categories[collist[[fn]]$codes+1]) + } + } + if('_index' %in% names(attr)) + rownames(res) = collist[[attr$`_index`]] + if('index' %in% colnames(res)) + rownames(res) = res$index + if(all(c('_index','column-order') %in% colnames(res))) + res = res[,c(attr$`_index`,attr$`column-order`),drop=FALSE] + res +} + + + + +#' Parse matrix from h5ad file +#' +#' @param filename file name or H5IdComponent to read data.frame from +#' @param name name of group that contains matrix to be loaded +#' +#' @return R matrix, dense or sparse - in dependence on input +#' @export +#' @examples +#' obs = h5ad2data.frame('adata.h5ad','X') +h5ad2Matrix = function(filename,name){ + m = rhdf5::h5read(filename,name,read.attributes = TRUE) + attr = attributes(m) + format = attr$`encoding-type` + if(is.null(format)) + format = attr$h5sparse_format + shape = attr$shape + if(is.null(shape)) + shape = attr$h5sparse_shape + if(is.array(m)){ + mtx = m + }else{ + if(startsWith(format,'csr')){ + mtx = Matrix::sparseMatrix(i=m$indices+1, p=m$indptr,x = as.numeric(m$data),dims = rev(shape)) + }else{ + mtx = Matrix::sparseMatrix(i=m$indices+1, p=m$indptr,x = as.numeric(m$data),dims = shape) + mtx = Matrix::t(mtx) + } + } + mtx +} + + + +#' Load visium images from h5ad +#' +#' +#' @param filename path 2 visium h5ad +#' +#' @return list of slides. Each slide is list with scale.fctors, hires and lowres images +#' +#' @examples +#' imgs = h5ad2images('adata.h5ad') +h5ad2images = function(filename){ + h5struct = rhdf5::h5ls(filename) + library_ids = h5struct$name[h5struct$group=='/uns/spatial'] + result = list() + + for(lid in library_ids){ + result[[lid]] = list() + result[[lid]]$scale.factors = rhdf5::h5read(filename,paste0('/uns/spatial/',lid,'/scalefactors')) + for(res in h5struct$name[h5struct$group==paste0('/uns/spatial/',lid,'/images')]) + result[[lid]][[res]] = aperm(rhdf5::h5read(filename,paste0('/uns/spatial/',lid,'/images/',res)),3:1) + } + result +} diff --git a/README.md b/README.md index f00159d..71dad65 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,65 @@ # schard -This package is intended to be pure R, reticulate-free replacement of sceasy. It is based on rhdf5 for h5ad manipulation. Just two functions are available right now (load visium h5ad into list of Seurat objects and load h5ad into SingleCellExperiment) and their functionality is limited, that is, they do not load full content of input h5ad. +This package allows one to load scanpy h5ad into R as list, SingleCellExperiment or Seurat object. For now it only loads `X`, `obs`, `var`, `obsm` (as reduced dimensions) if requested and `images` for visium data. +The package is based on rhdf5 for h5ad manipulation and is pure R (that is reticulate-free). + # Installation -```devtools::install_github("cellgeni/schard")``` +schard depends on some Bioconductor packages that should be installed manually: +``` +if (!require("BiocManager", quietly = TRUE)) + install.packages("BiocManager") + +BiocManager::install(c("rhdf5","Seurat", "SingleCellExperiment")) +``` + +Then install schard from github +``` +devtools::install_github("cellgeni/schard") +``` # Usage -```sce = schard::h5ad2sce('adata.h5ad')``` +Download some public h5ad and load them to R: +``` +download.file('https://covid19.cog.sanger.ac.uk/baron16.processed.h5ad','ba16.h5ad') # old data from 2016 +# visium and single nuclei datasets from cziscience: https://cellxgene.cziscience.com/collections/3116d060-0a8e-4767-99bb-e866badea1ed +download.file('https://datasets.cellxgene.cziscience.com/c5ac5c36-f60c-4680-8018-2d6cb65c0a37.h5ad','vis.heart.h5ad') +download.file('https://datasets.cellxgene.cziscience.com/8cc521c8-c4ff-4cba-a07b-cae67a9dcba9.h5ad','sn.heart.h5ad') + +# load h5ad as Single Cell Experiment +ba16.sce = schard::h5ad2sce('ba16.h5ad') +# load h5ad as Seurat +snhx = schard::h5ad2seurat('sn.heart.h5ad') +# load all visium samples as single Seurat object +visx = schard::h5ad2seurat_spatial('vis.heart.h5ad') +# or load as list of visium objects +visl = schard::h5ad2seurat_spatial('vis.heart.h5ad',simplify = FALSE) +# or load raw counts +snhr = schard::h5ad2seurat('sn.heart.h5ad',use.raw = TRUE) +# raw counts for visium +visr = schard::h5ad2seurat_spatial('vis.heart.h5ad',use.raw = TRUE) + + +# check that it works +Seurat::SpatialPlot(visx,features = 'total_counts') +Seurat::SpatialPlot(visx,features = 'total_counts',images = 'HCAHeartST11702009') +Seurat::SpatialPlot(visl$HCAHeartST11702010,features = 'total_counts') +plot(colSums(visx),colSums(visr),pch=16) # raw counts are different from normolized ones +Seurat::DimPlot(snhx,group.by = 'cell_state') # the name of reduction is 'Xumap_' (autotranslated from scanpy to Seurat), somehow DimPlot manages to find it, but probably safier to specify it manually with reduction = 'Xumap_' +``` + +There is not need to load whole object if you only need cell metadata: +``` +obs = schard::h5ad2data.frame('sn.heart.h5ad','obs') +# one can load umap in the same way. +# not sure about the name? lets see into h5ad: +ls = rhdf5::h5ls('sn.heart.h5ad') +ls[ls$group=='/obsm',] # so we have 'X_umap' here +umap = t(schard::h5ad2Matrix('sn.heart.h5ad','/obsm/X_umap')) # I like it more transposed +plot(umap[,1:2],pch=16,cex=0.4,col=factor(obs$cell_state)) +``` + +# Alternatives +There are two known alternatives: +1. [sceasy](https://github.com/cellgeni/sceasy) uses reticulate and thus depends on python environment. Proved to be unstable and hard to use. +2. [SeuratDisk](https://github.com/mojaveazure/seurat-disk) also uses rhdf5, but uses h5-based Seurat format as an intermediate that looks like overcomplication. Additionally, SeuratDisk seems to be almost not supported and it fails even on examples from its own tutorial. + +Despite all problems of both packages above they have clear advantage over schard: they allow not only to read h5ad into R but also to write it. diff --git a/man/h5ad2Matrix.Rd b/man/h5ad2Matrix.Rd new file mode 100644 index 0000000..cb42e81 --- /dev/null +++ b/man/h5ad2Matrix.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/h5ad_util.R +\name{h5ad2Matrix} +\alias{h5ad2Matrix} +\title{Parse matrix from h5ad file} +\usage{ +h5ad2Matrix(filename, name) +} +\arguments{ +\item{filename}{file name or H5IdComponent to read data.frame from} + +\item{name}{name of group that contains matrix to be loaded} +} +\value{ +R matrix, dense or sparse - in dependence on input +} +\description{ +Parse matrix from h5ad file +} +\examples{ +obs = h5ad2data.frame('adata.h5ad','X') +} diff --git a/man/h5ad2data.frame.Rd b/man/h5ad2data.frame.Rd new file mode 100644 index 0000000..1d91547 --- /dev/null +++ b/man/h5ad2data.frame.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/h5ad_util.R +\name{h5ad2data.frame} +\alias{h5ad2data.frame} +\title{Extracts data.frame from h5ad file} +\usage{ +h5ad2data.frame(filename, name) +} +\arguments{ +\item{filename}{file name or H5IdComponent to read data.frame from} + +\item{name}{name of group that contains data.frame to be loaded} +} +\value{ +a data.frame +} +\description{ +Extracts data.frame from h5ad file +} +\examples{ +obs = h5ad2data.frame('adata.h5ad','obs') +} diff --git a/man/h5ad2images.Rd b/man/h5ad2images.Rd new file mode 100644 index 0000000..236b6c4 --- /dev/null +++ b/man/h5ad2images.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/h5ad_util.R +\name{h5ad2images} +\alias{h5ad2images} +\title{Load visium images from h5ad} +\usage{ +h5ad2images(filename) +} +\arguments{ +\item{filename}{path 2 visium h5ad} +} +\value{ +list of slides. Each slide is list with scale.fctors, hires and lowres images +} +\description{ +Load visium images from h5ad +} +\examples{ +imgs = h5ad2images('adata.h5ad') +} diff --git a/man/h5ad2list.Rd b/man/h5ad2list.Rd new file mode 100644 index 0000000..5cd9fe6 --- /dev/null +++ b/man/h5ad2list.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/functions.R +\name{h5ad2list} +\alias{h5ad2list} +\title{Loads main parts of h5ad file as ordinary R list} +\usage{ +h5ad2list(filename, use.raw = FALSE, load.obsm = FALSE) +} +\arguments{ +\item{filename}{path to h5ad file} + +\item{load.obsm}{logical, whether to load adata.obsm.} + +\item{load.raw}{logical, whether to load adata.raw.X instead of adata.X} +} +\value{ +list with following elements: +obs - data.frame +var - data.frame +X - matrix (dense or sparse - as it was in X) +obsm - list of matrices from obsm (presumably reduced dimensions) +} +\description{ +Loads main parts of h5ad file as ordinary R list +} diff --git a/man/h5ad2sce.Rd b/man/h5ad2sce.Rd index 7bbc447..66249ff 100644 --- a/man/h5ad2sce.Rd +++ b/man/h5ad2sce.Rd @@ -2,14 +2,16 @@ % Please edit documentation in R/functions.R \name{h5ad2sce} \alias{h5ad2sce} -\title{Loads h5ad scanpy single cell file as SingleCellExperiment} +\title{Loads h5ad as SingleCellExperiment object} \usage{ -h5ad2sce(filename, use.raw = FALSE) +h5ad2sce(filename, use.raw = FALSE, load.obsm = TRUE) } \arguments{ \item{filename}{path to h5ad file} \item{use.raw}{logical, whether to attempt to get data from adata.raw. Throws warning (not exception!) if adata.raw is not present and proceeds with adata.X.} + +\item{load.obsm}{logical, whether to load adata.obsm. All matrix-like objects from there will be added as reducedDim to the output object.} } \value{ SingleCellExperiment object diff --git a/man/h5ad2seurat.Rd b/man/h5ad2seurat.Rd new file mode 100644 index 0000000..ace889f --- /dev/null +++ b/man/h5ad2seurat.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/functions.R +\name{h5ad2seurat} +\alias{h5ad2seurat} +\title{Loads h5ad as Seurat object} +\usage{ +h5ad2seurat(filename, use.raw = FALSE, load.obsm = TRUE, assay = "RNA") +} +\arguments{ +\item{filename}{path to h5ad file} + +\item{use.raw}{logical, whether to use adata.raw instead of adata.X} + +\item{load.obsm}{logical, whether to load adata.obsm. All matrix-like objects from there will be added as DimReduc to the output object with names coerced to Seurat style (that is not underscores in the middle, single underscore at the end).} + +\item{assay}{what assay to put data it (RNA by default)} +} +\value{ +Seurat object +} +\description{ +For non-spatial data only, use h5ad2seurat_spatial for Visium +} +\examples{ +seu = h5ad2seurat('adata.h5ad') +} diff --git a/man/h5ad2seurat_l_spatial.Rd b/man/h5ad2seurat_l_spatial.Rd deleted file mode 100644 index f983901..0000000 --- a/man/h5ad2seurat_l_spatial.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/functions.R -\name{h5ad2seurat_l_spatial} -\alias{h5ad2seurat_l_spatial} -\title{Loads scanpy h5ad file with Visium data into list of Seurat objects} -\usage{ -h5ad2seurat_l_spatial( - filename, - library_id_field = NULL, - simplify = TRUE, - use.raw = FALSE -) -} -\arguments{ -\item{filename}{character, path to h5ad file} - -\item{library_id_field}{name of adata.obs that specifies visium library. Function trys to guess it if set to NULL (default).} - -\item{simplify}{logical, whether return just seurat object (instead of list) if there is only one sample} - -\item{use.raw}{logical, whether to attempt to get data from adata.raw. Throws warning (not exception!) if adata.raw is not present and proceeds with adata.X.} -} -\value{ -list of Seurat object -} -\description{ -simplifies to single Seurat object if there is just one sample (see simplify parameter) -} diff --git a/man/h5ad2seurat_spatial.Rd b/man/h5ad2seurat_spatial.Rd new file mode 100644 index 0000000..738579d --- /dev/null +++ b/man/h5ad2seurat_spatial.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/functions.R +\name{h5ad2seurat_spatial} +\alias{h5ad2seurat_spatial} +\title{Loads scanpy h5ad file with Visium data into Seurat object} +\usage{ +h5ad2seurat_spatial( + filename, + use.raw = FALSE, + load.obsm = TRUE, + simplify = TRUE, + img.res = "lowres" +) +} +\arguments{ +\item{filename}{character, path to h5ad file} + +\item{use.raw}{logical, whether to attempt to get data from adata.raw. Throws warning (not exception!) if adata.raw is not present and proceeds with adata.X.} + +\item{load.obsm}{logical, whether to load adata.obsm. All matrix-like objects from there will be added as DimReduc to the output object with names coerced to Seurat style (that is not underscores in the middle, single underscore at the end).} + +\item{simplify}{logical, whether to merge loaded samples into single object, return list otherwise.} + +\item{img.res}{which of lowres' or 'hires' image to be loaded} +} +\value{ +list of Seurat object +} +\description{ +Loads scanpy h5ad file with Visium data into Seurat object +} +\examples{ +vs = h5ad2seurat_spatial('adata.h5ad') +}