Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions R/read_h5ad_helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ read_h5ad_element <- function(

read_fun <- switch(
type,
"null" = read_h5ad_null,
"array" = read_h5ad_dense_array,
"rec-array" = read_h5ad_rec_array,
"csr_matrix" = read_h5ad_csr_matrix,
Expand Down Expand Up @@ -100,6 +101,22 @@ read_h5ad_element <- function(
)
}

#' Read H5AD null
#'
#' Read a null value from an H5AD file
#'
#' @param file Path to a H5AD file or an open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param version Encoding version of the element to read
#'
#' @return `NULL`
#' @noRd
read_h5ad_null <- function(file, name, version = "0.1.0") {
version <- match.arg(version)

NULL
}

#' Read H5AD dense array
#'
#' Read a dense array from an H5AD file
Expand All @@ -122,7 +139,7 @@ read_h5ad_dense_array <- function(file, name, version = "0.2.0") {
dim(data) <- length(data)
}

# transpose the matrix if need be
# Transpose the matrix if need be
if (is.matrix(data)) {
data <- t(data)
} else if (is.array(data) && length(dim(data)) > 1) {
Expand All @@ -131,8 +148,9 @@ read_h5ad_dense_array <- function(file, name, version = "0.2.0") {

# Reverse {rhdf5} coercion to factors
if (is.factor(data) && all(levels(data) %in% c("TRUE", "FALSE"))) {
dims <- dim(data)
data <- as.logical(data)
dim(data) <- length(data)
dim(data) <- dims
}

data
Expand Down
66 changes: 52 additions & 14 deletions R/write_h5ad_helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#' Write an element to an H5AD file
#'
#' @param value The value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand All @@ -31,11 +31,11 @@ write_h5ad_element <- function(
) {
compression <- match.arg(compression)

# cli::cli_alert_info("Writing {.path {name}} with {.pkg rhdf5}")

# Sparse matrices
write_fun <-
if (inherits(value, "sparseMatrix")) {
if (is.null(value)) {
write_h5ad_null
} else if (inherits(value, "sparseMatrix")) {
# Sparse matrices
write_h5ad_sparse_array
} else if (is.factor(value)) {
Expand Down Expand Up @@ -148,12 +148,42 @@ write_h5ad_encoding <- function(file, name, encoding, version) {
)
}

#' Write H5AD null
#'
#' Write a null dataset to an H5AD file
#'
#' @param value Value to write, not used
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression Not used as there is no value
#' @param version Encoding version of the element to write
#'
#' @noRd
write_h5ad_null <- function(value, file, name, compression, version = "0.1.0") {
if (isFALSE(getOption("anndataR.write_null", "TRUE"))) {
return(invisible(NULL))
}

h5s <- rhdf5::H5Screate("H5S_NULL")
on.exit(rhdf5::H5Sclose(h5s), add = TRUE)

h5d <- rhdf5::H5Dcreate(
file,
name = name,
dtype_id = "H5T_IEEE_F32LE",
h5space = h5s
)
on.exit(rhdf5::H5Dclose(h5d), add = TRUE)

write_h5ad_encoding(file, name, "null", version)
}

#' Write H5AD dense array
#'
#' Write a dense array to an H5AD file
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -222,7 +252,7 @@ write_h5ad_dense_array <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -295,7 +325,7 @@ write_h5ad_sparse_array <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -339,7 +369,7 @@ write_h5ad_nullable_boolean <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -382,7 +412,7 @@ write_h5ad_nullable_integer <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand All @@ -394,6 +424,14 @@ write_h5ad_string_array <- function(
compression,
version = "0.2.0"
) {
if (!is.vector(value)) {
if (is.matrix(value)) {
value <- t(value)
} else if (is.array(value)) {
value <- aperm(value)
}
}

hdf5_write_dataset(
file = file,
name = name,
Expand All @@ -411,7 +449,7 @@ write_h5ad_string_array <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -467,7 +505,7 @@ write_h5ad_categorical <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -496,7 +534,7 @@ write_h5ad_string_scalar <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -535,7 +573,7 @@ write_h5ad_numeric_scalar <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down Expand Up @@ -569,7 +607,7 @@ write_h5ad_mapping <- function(
#' @noRd
#'
#' @param value Value to write
#' @param file Path to a H5AD file or an open H5AD handle
#' @param file An open H5AD handle
#' @param name Name of the element within the H5AD file
#' @param compression The compression to use when writing the element. Can be
#' one of `"none"`, `"gzip"` or `"lzf"`. Defaults to `"none"`.
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/helper-skip_if_no_anndata.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ skip_if_no_anndata <- function() {
testthat::skip_if_not_installed("reticulate")
testthat::skip_if_not_installed("anndata")
requireNamespace("reticulate")
reticulate::py_require("anndata<=0.11.4")
reticulate::py_require("anndata")
testthat::skip_if_not(
reticulate::py_module_available("anndata"),
message = "Python anndata module not available for testing"
Expand Down
10 changes: 2 additions & 8 deletions tests/testthat/test-roundtrip-uns-nested.R
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,9 @@ for (name in test_names) {
skip_if(!is.null(msg), message = msg)

adata_r <- read_h5ad(file_py, as = "HDF5AnnData")
nested_keys <- if (name == "none") {
list()
} else {
names(adata_r$uns$nested)
}

expect_equal(
nested_keys,
names(adata_r$uns$nested),
bi$list(adata_py$uns$nested$keys())
)

Expand Down Expand Up @@ -101,8 +97,6 @@ for (name in test_names) {
gc()

test_that(paste0("Writing an AnnData with uns_nested '", name, "' works"), {
skip_if(name == "none", message = "No value to test for 'none'")

msg <- message_if_known(
backend = "HDF5AnnData",
slot = c("uns_nested"),
Expand Down
11 changes: 2 additions & 9 deletions tests/testthat/test-roundtrip-uns.R
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,9 @@ for (name in test_names) {
skip_if(!is.null(msg), message = msg)

adata_r <- read_h5ad(file_py, as = "HDF5AnnData")
uns_keys <- if (name == "none") {
list()
} else {
names(adata_r$uns)
}

expect_equal(
uns_keys,
names(adata_r$uns),
bi$list(adata_py$uns$keys())
)

Expand All @@ -74,7 +70,6 @@ for (name in test_names) {
test_that(
paste0("Comparing an anndata with uns '", name, "' with reticulate works"),
{
skip_if(name == "none", message = "No value to test for 'none'")
msg <- message_if_known(
backend = "HDF5AnnData",
slot = c("uns"),
Expand All @@ -98,8 +93,6 @@ for (name in test_names) {
gc()

test_that(paste0("Writing an AnnData with uns '", name, "' works"), {
skip_if(name == "none", message = "No value to test for 'none'")

msg <- message_if_known(
backend = "HDF5AnnData",
slot = c("uns"),
Expand Down
Loading