Add subset function
authorPaul Hoffman <phoffman@nygenome.org>
Tue, 12 Dec 2017 23:57:18 +0000 (18:57 -0500)
committerPaul Hoffman <phoffman@nygenome.org>
Tue, 12 Dec 2017 23:57:18 +0000 (18:57 -0500)
NAMESPACE
R/loom.R
man/create.Rd
man/subset.loom.Rd [new file with mode: 0644]

index 209afd6a407c313d3c7d812543f1ef9d87d38032..8b91e8f47a77fe18e5a920c7173e9890b4b82bc0 100644 (file)
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -3,6 +3,7 @@
 export(connect)
 export(create)
 export(loom)
+export(subset.loom)
 import(hdf5r)
 importFrom(R6,R6Class)
 importFrom(iterators,nextElem)
index 23c952611c476f2482a52c3aa622747df9365b84..5bdded1bcdfb183f39af43f00a668d02e6988a14 100644 (file)
--- a/R/loom.R
+++ b/R/loom.R
@@ -838,6 +838,7 @@ loom <- R6Class(
 #' @param gene.attrs A named list of vectors with extra data for genes, each vector must be as long as the number of genes in \code{data}
 #' @param cell.attrs A named list of vectors with extra data for cells, each vector must be as long as the number of cells in \code{data}
 #' @param chunk.dims A one- or two-length integer vector of chunksizes for \code{/matrix}, defaults to 'auto' to automatically determine chunksize
+#' @param overwrite Overwrite an already existing loom file?
 #'
 #' @return A connection to a loom file
 #'
@@ -853,9 +854,11 @@ create <- function(
   gene.attrs = NULL,
   cell.attrs = NULL,
   layers = NULL,
-  chunk.dims = 'auto'
+  chunk.dims = 'auto',
+  overwrite = FALSE
 ) {
-  if (file.exists(filename)) {
+  mode <- ifelse(test = overwrite, yes = 'w', no = 'w-')
+  if (file.exists(filename) && !overwrite) {
     stop(paste('File', file, 'already exists!'))
   }
   if (!is.matrix(x = data)) {
@@ -870,7 +873,7 @@ create <- function(
   } else {
     chunk.dims <- as.integer(x = chunk.dims)
   }
-  new.loom <- loom$new(filename = filename, mode = 'w-')
+  new.loom <- loom$new(filename = filename, mode = mode)
   # Create the matrix
   new.loom$create_dataset(
     name = 'matrix',
@@ -995,6 +998,115 @@ connect <- function(filename, mode = "r", skip.validate = FALSE) {
   return(new.loom)
 }
 
+#' Subset a loom file
+#'
+#' @param x A loom object
+#' @param m Rows (genes) to subset
+#' @param n Columns (cells) to subset
+#' @param filename Filename for new loom object
+#' @param overwrite Overwrite \code{filename} if already exists?
+#' @param display.progress Display progress as we're copying over data
+#'
+#' @return A loom object connected to \code{filename}
+#'
+#' @importFrom utils txtProgressBar setTxtProgressBar
+#'
+#' @export subset.loom
+#' @method subset loom
+#'
+subset.loom <- function(
+  x,
+  m,
+  n,
+  filename,
+  overwrite = FALSE,
+  display.progress = TRUE,
+  ...
+) {
+  new.pb <- function() {return(txtProgressBar(style = 3, char = '='))}
+  # # Set mode based on
+  # mode <- ifelse(test = overwrite, yes = 'w', no = 'w-')
+  # Ensure that m and n are within the bounds of the loom file
+  if (max(m) > x$shape[1] || max(n) > x$shape[2]) {
+    stop(paste(
+      "'m' and 'n' must be less than",
+      self$shape[1],
+      "and",
+      self$shape[2],
+      "respectively"
+    ))
+  }
+  extension <- rev(x = unlist(x = strsplit(x = filename, split = '.', fixed = TRUE)))
+  # Ensure that we call our new file a loom file
+  if (extension != 'loom') {
+    filename <- paste0(filename, '.loom')
+  }
+  if (display.progress) {
+    cat("Writing new loom file to", filename, '\n')
+  }
+  # Make the loom file
+  new.loom <- create(
+    filename = filename,
+    data = t(x = x[['matrix']][n, m]),
+    overwrite = overwrite
+  )
+  # Add row attributes
+  row.attrs <- list.datasets(object = x, path = 'row_attrs', full.names = TRUE)
+  if (length(x = row.attrs) > 0) {
+    if (display.progress) {
+      cat("\nAdding", length(x = row.attrs), "row attributes\n")
+      pb <- new.pb()
+      counter <- 0
+    }
+    for (row.attr in row.attrs) {
+      new.loom$add.row.attribute(attribute = x[[row.attr]][m])
+      if (display.progress) {
+        counter <- counter + 1
+        setTxtProgressBar(pb = pb, value = counter / length(x = row.attrs))
+      }
+    }
+  } else {
+    warning("No row attributes found")
+  }
+  # Add col attributes
+  col.attrs <- list.datasets(object = x, path = 'col_attrs', full.names = TRUE)
+  if (length(x = col.attrs) > 0) {
+    if (display.progress) {
+      cat("\nAdding", length(x = col.attrs), "row attributes\n")
+      pb <- new.pb()
+      counter <- 0
+    }
+    for (col.attr in col.attrs) {
+      new.loom$add.col.attribute(attribute = x[[col.attr]][n])
+      if (display.progress) {
+        counter <- counter + 1
+        setTxtProgressBar(pb = pb, value = counter / length(x = col.attrs))
+      }
+    }
+  } else {
+    warning("No column attributes found")
+  }
+  # Add layers
+  layers <- list.datasets(object = x, path = 'layers', full.names = TRUE)
+  if (length(x = layers) > 0) {
+    if (display.progress) {
+      cat("\nAdding", length(x = layers), "row attributes\n")
+      pb <- new.pb()
+      counter <- 0
+    }
+    for (layer in layers) {
+      new.loom$add.layer(layers = x[[layer]][n, m])
+      if (display.progress) {
+        counter <- counter + 1
+        setTxtProgressBar(pb = pb, value = counter / length(x = layers))
+      }
+    }
+  } else {
+    warning("No layers found")
+  }
+  return(new.loom)
+}
+
 # Map a function or a series of functions over a loom file
 #
 # @param X A loom object
index 70e12b368b79c9cfe540931756ee0fc05f352c68..07e4bf6e47fb0fcce8b9675c2ea6fad282182874 100644 (file)
@@ -5,7 +5,7 @@
 \title{Create a loom object}
 \usage{
 create(filename, data, gene.attrs = NULL, cell.attrs = NULL,
-  layers = NULL, chunk.dims = "auto")
+  layers = NULL, chunk.dims = "auto", overwrite = FALSE)
 }
 \arguments{
 \item{filename}{The name of the new loom file}
@@ -17,6 +17,8 @@ create(filename, data, gene.attrs = NULL, cell.attrs = NULL,
 \item{cell.attrs}{A named list of vectors with extra data for cells, each vector must be as long as the number of cells in \code{data}}
 
 \item{chunk.dims}{A one- or two-length integer vector of chunksizes for \code{/matrix}, defaults to 'auto' to automatically determine chunksize}
+
+\item{overwrite}{Overwrite an already existing loom file?}
 }
 \value{
 A connection to a loom file
diff --git a/man/subset.loom.Rd b/man/subset.loom.Rd
new file mode 100644 (file)
index 0000000..5135e38
--- /dev/null
@@ -0,0 +1,28 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/loom.R
+\name{subset.loom}
+\alias{subset.loom}
+\title{Subset a loom file}
+\usage{
+\method{subset}{loom}(x, m, n, filename, overwrite = FALSE,
+  display.progress = TRUE, ...)
+}
+\arguments{
+\item{x}{A loom object}
+
+\item{m}{Rows (genes) to subset}
+
+\item{n}{Columns (cells) to subset}
+
+\item{filename}{Filename for new loom object}
+
+\item{overwrite}{Overwrite \code{filename} if already exists?}
+
+\item{display.progress}{Display progress as we're copying over data}
+}
+\value{
+A loom object connected to \code{filename}
+}
+\description{
+Subset a loom file
+}