diff --git a/.Rbuildignore b/.Rbuildignore index 9b04b07..2c31b3e 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -7,5 +7,3 @@ ^vignettes$ ^docs$ ^index\.md$ -^LICENSE\.md$ -^LICENSE$ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2e041f3..36b87c1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ tests/testthat/test_data .ipynb_checkpoints/ *.ipynb .Renviron +pkgdown/favicon/ \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index a8c555b..498e484 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -18,15 +18,13 @@ BugReports: https://github.com/keller-mark/pizzarr/issues URL: https://github.com/keller-mark/pizzarr Depends: R (>= 4.0.0) Imports: - Matrix, - rjson, jsonlite, stats, - methods, R6, qs, stringr, - memoise + memoise, + utils Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index ed7c1f6..b2ba27d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -27,6 +27,7 @@ export(is_key_error) export(is_scalar) export(is_slice) export(obj_list) +export(pizzarr_sample) export(slice) export(zarr_create) export(zarr_create_array) @@ -38,3 +39,10 @@ export(zarr_open_array) export(zarr_open_group) export(zarr_save_array) export(zb_slice) +importFrom(R6,R6Class) +importFrom(memoise,memoise) +importFrom(memoise,timeout) +importFrom(qs,lz4_compress_raw) +importFrom(qs,lz4_decompress_raw) +importFrom(qs,zstd_compress_raw) +importFrom(qs,zstd_decompress_raw) diff --git a/R/array-nested.R b/R/array-nested.R index 0250ac3..4fa92a4 100644 --- a/R/array-nested.R +++ b/R/array-nested.R @@ -1,6 +1,11 @@ #' @keywords internal zero_based_to_one_based <- function(selection, shape) { + + if(!all(vapply(selection, is_slice, logical(length = 1)))) + stop("selection must be a list of slices") + selection_list <- list() + for(i in seq_len(length(selection))) { sel <- selection[[i]] # We assume the selection uses zero-based indexing, @@ -8,6 +13,8 @@ zero_based_to_one_based <- function(selection, shape) { # before accessing data on the internal self$data. sel_start <- sel$start + 1 # Add one, since R indexing is zero-based. sel_stop <- sel$stop # Do not subtract one, since R indexing is inclusive. + sel_step <- sel$step + if(is.na(sel_step)) sel_step <- 1 # TODO: convert these warnings to errors once we know internals do indexing correctly if(sel_start < 1) { sel_start <- 1 @@ -25,7 +32,9 @@ zero_based_to_one_based <- function(selection, shape) { sel_stop <- shape[i] message("IndexError: NestedArray$get() received slice with stop index out of bounds - too high") } - selection_list <- append(selection_list, list(c(sel_start:sel_stop))) # TODO: support non-1 step + selection_list <- append(selection_list, list(seq(from = sel_start, + to = sel_stop, + by = sel_step))) } return(selection_list) } @@ -106,7 +115,7 @@ NestedArray <- R6::R6Class("NestedArray", # Create array from R atomic vector or array(). num_shape_elements <- compute_size(shape) # Check that data array has same shape as expected - if(!is.null(dim(data)) && all(ensure_vec(dim(data)) == ensure_vec(shape))) { + if(!is.null(dim(data)) && all(ensure_integer_vec(dim(data)) == ensure_integer_vec(shape))) { self$data <- data } else { astype_func <- self$dtype_obj$get_asrtype() @@ -222,17 +231,15 @@ NestedArray <- R6::R6Class("NestedArray", # value should be a NestedArray. selection_list <- zero_based_to_one_based(selection, self$shape) - value_data <- value$data - if("NestedArray" %in% class(value)) { value_data <- value$data - } else if(is_scalar(value)) { + } else if(is_scalar(value) | is.array(value)) { value_data <- value } else { message(value) stop("Got unexpected type for value in NestedArray$set()") } - + # Cannot figure out how to dynamically set values in an array # of arbitrary dimensions. # Tried: abind::afill <- but it doesn't seem to work with arbitrary dims or do.call @@ -319,9 +326,9 @@ NestedArray <- R6::R6Class("NestedArray", #' S3 method for as.array #' -#' @param obj +#' @param x #' @keywords internal #' @export -as.array.NestedArray = function(obj) { - obj$as.array() +as.array.NestedArray = function(x, ...) { + x$as.array() } diff --git a/R/atomic.R b/R/atomic.R index fcda149..da721a1 100644 --- a/R/atomic.R +++ b/R/atomic.R @@ -1,6 +1,7 @@ # Reference: https://github.com/jeroen/jsonlite/blob/6a30ac/R/unbox.R #' Convert a value to a scalar to opt-out of R default vector casting behavior. +#' This uses the `jsonlite::unbox` function to "tag" the value as a scalar. #' @param obj The value to convert. #' @return The value wrapped as a scalar. #' @export @@ -8,7 +9,7 @@ as_scalar <- function(obj) { return(jsonlite::unbox(obj)) } -#' Check if a value is a scalar. +#' Check if a value is a scalar (i.e., a one-element vector that was converted with as_scalar). #' @param s The value to check. #' @return TRUE if the value is a scalar, FALSE otherwise. #' @export @@ -19,35 +20,50 @@ is_scalar <- function(s) { return(FALSE) } +#' Check if a value is an integer R vector or scalar. #' @keywords internal is_integer <- function(s) { - if(is_scalar(s) && is.numeric(s)) { + if(is.atomic(s) && is.numeric(s) && all(s %% 1 == 0)) { return(TRUE) } return(FALSE) } +#' Check if a value is both a scalar (tagged by as_scalar) and an integer. +#' @keywords internal +is_integer_scalar <- function(s) { + if(is_scalar(s) && is_integer(s)) { + return(TRUE) + } + return(FALSE) +} + +#' Check that a value is a vector of one or more integers and has not been +#' explicitly tagged as a scalar. #' @keywords internal is_integer_vec <- function(s) { - if(!is_scalar(s) && is.numeric(s)) { + if(!is_scalar(s) && is_integer(s)) { return(TRUE) } return(FALSE) } +#' Check that a value is a list of one or more integers. #' @keywords internal is_integer_list <- function(s) { - if(is.list(s) && is.numeric(unlist(s))) { + if(is.list(s) && is_integer_vec(unlist(s))) { return(TRUE) } return(FALSE) } +#' Ensure that scalars and lists of integers are converted to +#' an R vector of integers. #' @keywords internal -ensure_vec <- function(selection) { - if(is_integer(selection)) { +ensure_integer_vec <- function(selection) { + if(is_integer_scalar(selection)) { return(as.numeric(selection)) - } else if(is.numeric(selection)) { + } else if(is_integer_vec(selection)) { return(selection) } else if(is.list(selection)) { return(as.numeric(unlist(selection))) @@ -55,11 +71,13 @@ ensure_vec <- function(selection) { return(as.numeric(selection)) } +#' Ensure that scalars, single slices, and R integer vectors are converted +#' to a list containing either R integer vectors or slice instances as values. #' @keywords internal ensure_list <- function(selection) { if(is_slice(selection)) { return(list(selection)) - } else if(is_integer(selection)) { + } else if(is_integer_scalar(selection)) { return(as.list(as.numeric(selection))) } else if(is.list(selection)) { return(selection) diff --git a/R/creation.R b/R/creation.R index b3d96f3..30f3ec6 100644 --- a/R/creation.R +++ b/R/creation.R @@ -338,7 +338,7 @@ init_group <- function( } -#' Create an array +#' Create an empty array #' @param shape : int or tuple of ints #' Array shape. #' @param chunks : int or tuple of ints, optional @@ -619,6 +619,9 @@ zarr_open_group <- function( #' Open an array using file-mode-like semantics. #' @param store : MutableMapping or string, optional #' Store or path to directory in file system or name of zip file. +#' @param storage_options : dict +#' If using an fsspec URL to create the store, these will be passed to +#' the backend implementation. Ignored otherwise. #' @param mode : {'r', 'r+', 'a', 'w', 'w-'}, optional #' Persistence mode: 'r' means read only (must exist); 'r+' means #' read/write (must exist); 'a' means read/write (create if doesn't @@ -678,6 +681,7 @@ zarr_open_group <- function( #' @export zarr_open_array <- function( store = NA, + storage_options = NA, mode = NA, shape = NA, chunks=TRUE, diff --git a/R/indexing.R b/R/indexing.R index 3e6d4e7..cf3072c 100644 --- a/R/indexing.R +++ b/R/indexing.R @@ -226,7 +226,10 @@ SliceDimIndexer <- R6::R6Class("SliceDimIndexer", #' @title BasicIndexer Class #' @docType class #' @description -#' TODO +#' An indexer class to normalize a selection of an array and provide an iterator +#' of indexes over the dimensions of an array. +#' @param selection selection as with ZarrArray, scalar, string, or Slice. "..." and ":" supported for string +#' @param array ZarrArray object that will be indexed #' @rdname BasicIndexer #' @keywords internal BasicIndexer <- R6::R6Class("BasicIndexer", @@ -237,10 +240,9 @@ BasicIndexer <- R6::R6Class("BasicIndexer", dim_indexers = NULL, #' @description #' Create a new VIndex instance. - #' @param selection selection TODO - #' @param array array TODO #' @return A `VIndex` instance. initialize = function(selection, array) { + shape <- array$get_shape() chunks <- array$get_chunks() @@ -277,8 +279,8 @@ BasicIndexer <- R6::R6Class("BasicIndexer", self$dim_indexers <- dim_indexers }, #' @description - #' TODO - #' @return TODO + #' An iterator over the dimensions of an array + #' @return A list of ChunkProjection objects iter = function() { # TODO: use generator/yield features from async package result <- list() diff --git a/R/meta.R b/R/meta.R index adf068b..8c88913 100644 --- a/R/meta.R +++ b/R/meta.R @@ -11,7 +11,7 @@ Metadata2 <- R6::R6Class("Metadata2", if(is.list(s)) { return(s) } else { - return(jsonlite::fromJSON(rawToChar(s), simplifyVector = FALSE, auto_unbox = auto_unbox)) + return(try_fromJSON(rawToChar(s), simplifyVector = FALSE)) } }, encode_metadata = function(meta, auto_unbox=FALSE) { @@ -19,26 +19,30 @@ Metadata2 <- R6::R6Class("Metadata2", }, decode_array_metadata = function(s) { meta <- self$decode_metadata(s) - # TODO: check zarr format is v2 + validate_v2_meta(meta) return(meta) }, decode_group_metadata = function(s) { meta <- self$decode_metadata(s) - # TODO: check zarr format is v2 + validate_v2_meta(meta) return(meta) }, encode_array_metadata = function(meta) { clean_meta <- meta - clean_meta[['zarr_format']] <- private$ZARR_FORMAT + clean_meta[['zarr_format']] <- jsonlite::unbox(private$ZARR_FORMAT) # TODO: clean up meta even further return(self$encode_metadata(clean_meta)) }, encode_group_metadata = function(meta = NA) { meta <- obj_list() - meta[['zarr_format']] <- private$ZARR_FORMAT + meta[['zarr_format']] <- jsonlite::unbox(private$ZARR_FORMAT) return(self$encode_metadata(meta)) } ) ) +validate_v2_meta <- function(meta) { + if(meta$zarr_format != 2) stop("unsupported zarr format ", meta$zarr_format) +} + # TODO: v3 metadata \ No newline at end of file diff --git a/R/normalize.R b/R/normalize.R index 9833de2..a1759f0 100644 --- a/R/normalize.R +++ b/R/normalize.R @@ -1,10 +1,10 @@ #' @keywords internal -normalize_list_selection <- function(selection, shape, convert_integer_selection_to_slices = FALSE) { +normalize_list_selection <- function(selection, shape, convert_integer_selection_to_slices = TRUE) { # Reference: https://github.com/gzuidhof/zarr.js/blob/292804/src/core/indexing.ts#L45 selection <- replace_ellipsis(selection, shape) for(i in seq_along(selection)) { - dim_sel <- selection[i] + dim_sel <- selection[[i]] if(is_integer(dim_sel)) { if(convert_integer_selection_to_slices) { selection[[i]] <- zb_slice(dim_sel, dim_sel + 1, 1) @@ -13,7 +13,8 @@ normalize_list_selection <- function(selection, shape, convert_integer_selection } } else if(is_integer_list(dim_sel)) { # TODO: should this be is_integer_vec? stop('TypeError(Integer array selections are not supported (yet))') - } else if(is.na(dim_sel) || dim_sel == ":") { + } else if(!is.null(dim_sel) && !is.environment(dim_sel) && + (is.na(dim_sel) || dim_sel == ":")) { selection[[i]] <- zb_slice(NA, NA, 1) } } @@ -96,7 +97,7 @@ normalize_storage_path <- function(path) { normalize_shape <- function(shape) { # Reference: https://github.com/gzuidhof/zarr.js/blob/292804/src/util.ts#L69 if(!is.null(shape)) { - shape <- ensure_vec(shape) + shape <- ensure_integer_vec(shape) return(floor(shape)) } return(shape) diff --git a/R/numcodecs.R b/R/numcodecs.R index 99e1845..d39e6b6 100644 --- a/R/numcodecs.R +++ b/R/numcodecs.R @@ -36,6 +36,7 @@ Codec <- R6::R6Class("Codec", #' ZSTD compressor for Zarr #' @title ZstdCodec Class #' @docType class +#' @importFrom qs zstd_compress_raw zstd_decompress_raw #' @description #' Class representing a ZSTD compressor @@ -61,7 +62,7 @@ ZstdCodec <- R6::R6Class("ZstdCodec", #' @return Compressed data. encode = function(buf, zarr_arr) { # Reference: https://github.com/traversc/qs/blob/84e30f4/R/RcppExports.R#L16 - result <- qs::zstd_compress_raw(buf, self$level) + result <- zstd_compress_raw(buf, self$level) return(result) }, #' @description @@ -70,7 +71,7 @@ ZstdCodec <- R6::R6Class("ZstdCodec", #' @param zarr_arr The ZarrArray instance. #' @return Un-compressed data. decode = function(buf, zarr_arr) { - result <- qs::zstd_decompress_raw(buf) + result <- zstd_decompress_raw(buf) return(result) }, #' @description @@ -88,6 +89,7 @@ ZstdCodec <- R6::R6Class("ZstdCodec", #' LZ4 compressor for Zarr #' @title Lz4Codec Class #' @docType class +#' @importFrom qs lz4_compress_raw lz4_decompress_raw #' @description #' Class representing a LZ4 compressor #' @@ -113,7 +115,7 @@ Lz4Codec <- R6::R6Class("Lz4Codec", #' @return Compressed data. encode = function(buf, zarr_arr) { # Reference: https://github.com/traversc/qs/blob/84e30f4/R/RcppExports.R#L24 - body <- qs::lz4_compress_raw(buf, self$acceleration) + body <- lz4_compress_raw(buf, self$acceleration) # The compressed output includes a 4-byte header storing the original size # of the decompressed data as a little-endian 32-bit integer. @@ -133,7 +135,7 @@ Lz4Codec <- R6::R6Class("Lz4Codec", decode = function(buf, zarr_arr) { body <- buf[5:length(buf)] - result <- qs::lz4_decompress_raw(body) + result <- lz4_decompress_raw(body) return(result) }, #' @description diff --git a/R/slicing.R b/R/slicing.R index 2d083e6..5f114e6 100644 --- a/R/slicing.R +++ b/R/slicing.R @@ -94,7 +94,7 @@ Slice <- R6::R6Class("Slice", ) ) -#' Shortcut for Slice$new() constructor. +#' Convenience function for the internal Slice class constructor. #' @param start The start index. #' @param stop The stop index. #' @param step The step size. @@ -119,7 +119,8 @@ slice <- function(start, stop = NA, step = NA, zero_based = FALSE) { )) } -#' Shortcut for Slice$new() constructor with zero-based indexing and exclusive stop index. +#' Convenience function for the internal Sliceclass constructor +#' with zero-based indexing and exclusive stop index. #' @param start The start index. #' @param stop The stop index. #' @param step The step size. diff --git a/R/stores.R b/R/stores.R index 292e228..bebdfb0 100644 --- a/R/stores.R +++ b/R/stores.R @@ -346,6 +346,7 @@ MemoryStore <- R6::R6Class("MemoryStore", #' HttpStore for Zarr #' @title HttpStore Class #' @docType class +#' @importFrom memoise memoise timeout #' @description #' Store class that uses HTTP requests. #' Read-only. Depends on the `crul` package. @@ -377,12 +378,7 @@ HttpStore <- R6::R6Class("HttpStore", res <- private$make_request(".zmetadata") if(res$status_code == 200) { - out <- tryCatch({ - jsonlite::fromJSON(res$parse("UTF-8")) - }, error = \(e) { - warning("\n\nError parsing .zmetadata:\n\n", e) - NULL - }) + out <- try_fromJSON(res$parse("UTF-8")) } else out <- NULL return(out) @@ -417,8 +413,8 @@ HttpStore <- R6::R6Class("HttpStore", headers = private$headers ) - private$mem_get <- memoise::memoise(function(client, path) client$get(path), - ~memoise::timeout(private$cache_time_seconds)) + private$mem_get <- memoise(function(client, path) client$get(path), + ~timeout(private$cache_time_seconds)) private$zmetadata <- private$get_zmetadata() }, diff --git a/R/utils.R b/R/utils.R index 28beeef..f5fd7d6 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,3 +1,57 @@ +#' pizzarr demo data +#' @details +#' For directory stores, unzips the store to a temporary directory +#' and returns the resulting path. +#' +#' @param dataset character defining which demo dataset is desired, +#' If NULL, all are returned +#' @param outdir character directory path to store sample zarr stores +#' +#' @return path to ready to use zarr store +#' @export +#' @examples +#' zarr_samples <- pizzarr_sample() +#' +#' #printing without system path for example +#' gsub(tempdir(), "...", zarr_samples, fixed = TRUE) +#' +pizzarr_sample <- function(dataset = NULL, + outdir = file.path(tempdir(TRUE), "pizzarr_sample")) { + # will unzip here + tdir <- outdir + dir.create(tdir, showWarnings = FALSE, recursive = TRUE) + + # source data + sdir <- system.file("extdata", package = "pizzarr") + zarr_zips <- list.files(sdir, pattern = ".zarr.zip", + full.names = TRUE, recursive = TRUE) + + avail <- gsub(paste0(sdir, "/"), "", gsub(".zip", "", zarr_zips)) + + # if dataset is specified select it + if(!is.null(dataset)) { + f <- grepl(dataset, zarr_zips, fixed = TRUE) + zarr_zips <- zarr_zips[f] + + # if dataset not found, stop and print available datasets + if(length(zarr_zips) == 0) { + stop("Dataset not found\n\tMust be one of:\n\t \"", + paste(avail, collapse = "\"\n\t \""), "\"") + } + + avail <- avail[f] + } + + # in case zarr_zips is all, loop over them and unzip + for(z in seq_along(zarr_zips)) { + utils::unzip(zarr_zips[z], + exdir = file.path(tdir, dirname(avail[z]))) + } + + return(file.path(tdir, avail)) + +} + #' Convert a string into a character vector. #' #' @param s The string. @@ -297,4 +351,23 @@ item_to_key <- function(item) { try_from_zmeta <- function(key, store) { store$get_consolidated_metadata()$metadata[[key]] -} \ No newline at end of file +} + +try_fromJSON <- function(json, warn_message = "Error parsing json was", + simplifyVector = FALSE) { + out <- tryCatch({ + jsonlite::fromJSON(json, simplifyVector) + }, error = \(e) { + if(grepl("NaN", e)) { + tryCatch({ + jsonlite::fromJSON(gsub("NaN", "null", json), simplifyVector) + }, error = \(e) { + warning("\n\n", warn_message, "\n\n", e) + NULL + }) + } else { + warning("\n\n", warn_message, "\n\n", e) + NULL + } + }) +} diff --git a/R/zarr-array.R b/R/zarr-array.R index 190b41d..c7570b5 100644 --- a/R/zarr-array.R +++ b/R/zarr-array.R @@ -3,8 +3,12 @@ #' The Zarr Array class. #' @title ZarrArray Class #' @docType class +#' @importFrom R6 R6Class #' @description #' Instantiate an array from an initialized store. +#' @param selection Selections are lists containing either scalars, strings, or Slice objects. Two character +#' literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +#' array dimension. #' #' @rdname ZarrArray #' @export @@ -415,7 +419,7 @@ ZarrArray <- R6::R6Class("ZarrArray", # // the selection. This minimises the number of iterations in the main for loop. selection_shape <- indexer$shape - selection_shape_vec <- ensure_vec(indexer$shape) + selection_shape_vec <- ensure_integer_vec(indexer$shape) # Check value shape if (length(selection_shape) == 0) { @@ -423,12 +427,12 @@ ZarrArray <- R6::R6Class("ZarrArray", } else if (is_scalar(value)) { # Setting a scalar value } else if("array" %in% class(value)) { - if (!all(ensure_vec(dim(value)) == selection_shape_vec)) { + if (!all(ensure_integer_vec(dim(value)) == selection_shape_vec)) { stop("Shape mismatch in source array and set selection: ${dim(value)} and ${selectionShape}") } value <- NestedArray$new(value, shape = selection_shape_vec, dtype=private$dtype, order = private$order) } else if ("NestedArray" %in% class(value)) { - if (!all(ensure_vec(value$shape) == selection_shape_vec)) { + if (!all(ensure_integer_vec(value$shape) == selection_shape_vec)) { stop("Shape mismatch in source NestedArray and set selection: ${value.shape} and ${selectionShape}") } } else { @@ -961,7 +965,6 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' Subset the array. - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. #' @returns A subset of the array, as a NestedArray instance. get_item = function(selection) { # Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0/zarr/core.py#L580 @@ -970,7 +973,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param out TODO #' @param fields TODO get_basic_selection = function(selection = NA, out = NA, fields = NA) { @@ -986,7 +989,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param out TODO #' @param fields TODO get_orthogonal_selection = function(selection = NA, out = NA, fields = NA) { @@ -994,7 +997,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param out TODO #' @param fields TODO get_coordinate_selection = function(selection = NA, out = NA, fields = NA) { @@ -1002,7 +1005,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param out TODO #' @param fields TODO get_mask_selection = function(selection = NA, out = NA, fields = NA) { @@ -1010,14 +1013,14 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' Set a subset of the array. - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param value The value to set, as an R array() or a Zarr NestedArray instance. set_item = function(selection, value) { self$set_basic_selection(selection, value) }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param value TODO #' @param fields TODO set_basic_selection = function(selection, value, fields = NA) { @@ -1029,7 +1032,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param value TODO #' @param fields TODO set_orthogonal_selection = function(selection, value, fields = NA) { @@ -1037,7 +1040,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param value TODO #' @param fields TODO set_coordinate_selection = function(selection, value, fields = NA) { @@ -1045,7 +1048,7 @@ ZarrArray <- R6::R6Class("ZarrArray", }, #' @description #' TODO - #' @param selection Selections are lists containing either scalars, strings, or Slice objects. + #' @param value TODO #' @param fields TODO set_mask_selection = function(selection, value, fields = NA) { @@ -1105,7 +1108,7 @@ ZarrArray <- R6::R6Class("ZarrArray", #' Set values for a selection using bracket notation (for S3 method). #' #' @param ... Contains the slicing parameters, one for each dimension. - #' Use empty space to get whole dimension e.g. [1:5,,] + #' Use empty space to get whole dimension e.g. \code{[1:5,,]} #' #' @return Sliced Zarr object #' @keywords internal @@ -1158,7 +1161,7 @@ ZarrArray <- R6::R6Class("ZarrArray", #' @description #' Assign values for a selection using bracket notation (for S3 method). #' @param ... Contains the slicing parameters, one for each dimension. - #' Use empty space to get whole dimension e.g. [1:5,,] + #' Use empty space to get whole dimension e.g. \code{[1:5,,]} #' @keywords internal `[<-` = function(...) { stop("Assignment using bracket notation is not yet supported - use set_item() directly") @@ -1173,7 +1176,6 @@ ZarrArray <- R6::R6Class("ZarrArray", ) ) - #' S3 method for custom bracket subsetting #' #' @param obj object @@ -1186,19 +1188,19 @@ ZarrArray <- R6::R6Class("ZarrArray", #' S3 method for custom bracket assignment #' -#' @param obj object -#' @param ... dots +#' @param value array or ZarrArray #' @keywords internal #' @export -`[<-.ZarrArray` <- function(obj, ...) { - obj$`[<-`(...) +`[<-.ZarrArray` <- function(obj, ..., value) { + obj$`[<-`(value) } #' S3 method for as.array #' #' @param obj object +#' @param ... not used #' @keywords internal #' @export -as.array.ZarrArray = function(obj) { - obj$as.array() +as.array.ZarrArray = function(x, ...) { + x$as.array() } diff --git a/README.md b/README.md index 43bd809..1b232b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - +# pizzarr pizzarr website # pizzarr diff --git a/inst/extdata/bcsd.zarr.zip b/inst/extdata/bcsd.zarr.zip new file mode 100644 index 0000000..1f0f95a Binary files /dev/null and b/inst/extdata/bcsd.zarr.zip differ diff --git a/inst/extdata/bcsd.zarr/.zattrs b/inst/extdata/bcsd.zarr/.zattrs deleted file mode 100644 index 95fe89a..0000000 --- a/inst/extdata/bcsd.zarr/.zattrs +++ /dev/null @@ -1,32 +0,0 @@ -{ - "CDI": "Climate Data Interface version 1.5.6 (http://code.zmaw.de/projects/cdi)", - "CDO": "Climate Data Operators version 1.5.6.1 (http://code.zmaw.de/projects/cdo)", - "Conventions": "CF-1.0", - "History": "Translated to CF-1.0 Conventions by Netcdf-Java CDM (CFGridWriter2)\nOriginal Dataset = bcsd_obs; Translation Date = 2019-01-03T20:03:59.756Z", - "Metadata_Conventions": "Unidata Dataset Discovery v1.0", - "NCO": "netCDF Operators version 4.7.6 (Homepage = http://nco.sf.net, Code = http://github.com/nco/nco)", - "acknowledgment": "Maurer, E.P., A.W. Wood, J.C. Adam, D.P. Lettenmaier, and B. Nijssen, 2002, A Long-Term Hydrologically-Based Data Set of Land Surface Fluxes and States for the Conterminous United States, J. Climate 15(22), 3237-3251", - "cdm_data_type": "Grid", - "date_created": "2014", - "date_issued": "2015-11-01", - "geospatial_lat_max": 37.0625, - "geospatial_lat_min": 33.0625, - "geospatial_lon_max": -74.9375, - "geospatial_lon_min": -84.9375, - "history": "Mon Jan 7 18:59:08 2019: ncks -4 -L3 bcsd_obs_1999_two_var.nc bcsd_obs_1999_two_var.nc.comp\nThu May 08 12:07:18 2014: cdo monsum gridded_obs/daily/gridded_obs.daily.Prcp.1950.nc gridded_obs/monthly/gridded_obs.monthly.pr.1950.nc", - "id": "cida.usgs.gov/bcsd_obs", - "institution": "Varies, see http://gdo-dcp.ucllnl.org/downscaled_cmip_projections/", - "keywords": "Atmospheric Temperature, Air Temperature Atmosphere, Precipitation, Rain, Maximum Daily Temperature, Minimum Daily Temperature", - "keywords_vocabulary": "GCMD Science Keywords", - "license": "Freely available", - "naming_authority": "cida.usgs.gov", - "processing_level": "Gridded meteorological observations", - "publisher_email": "dblodgett@usgs.gov", - "publisher_name": "Center for Integrated Data Analytics", - "publisher_url": "https://www.cida.usgs.gov/", - "summary": "These are the monthly observational data used for BCSD downscaling. See: http://gdo-dcp.ucllnl.org/downscaled_cmip_projections/dcpInterface.html#About for more information.", - "time_coverage_end": "1999-12-15T00:00", - "time_coverage_resolution": "P1M", - "time_coverage_start": "1950-01-15T00:00", - "title": "Monthly Gridded Meteorological Observations" -} \ No newline at end of file diff --git a/inst/extdata/bcsd.zarr/.zgroup b/inst/extdata/bcsd.zarr/.zgroup deleted file mode 100644 index 3b7daf2..0000000 --- a/inst/extdata/bcsd.zarr/.zgroup +++ /dev/null @@ -1,3 +0,0 @@ -{ - "zarr_format": 2 -} \ No newline at end of file diff --git a/inst/extdata/bcsd.zarr/.zmetadata b/inst/extdata/bcsd.zarr/.zmetadata deleted file mode 100644 index ccecfd2..0000000 --- a/inst/extdata/bcsd.zarr/.zmetadata +++ /dev/null @@ -1,187 +0,0 @@ -{ - "metadata": { - ".zattrs": { - "CDI": "Climate Data Interface version 1.5.6 (http://code.zmaw.de/projects/cdi)", - "CDO": "Climate Data Operators version 1.5.6.1 (http://code.zmaw.de/projects/cdo)", - "Conventions": "CF-1.0", - "History": "Translated to CF-1.0 Conventions by Netcdf-Java CDM (CFGridWriter2)\nOriginal Dataset = bcsd_obs; Translation Date = 2019-01-03T20:03:59.756Z", - "Metadata_Conventions": "Unidata Dataset Discovery v1.0", - "NCO": "netCDF Operators version 4.7.6 (Homepage = http://nco.sf.net, Code = http://github.com/nco/nco)", - "acknowledgment": "Maurer, E.P., A.W. Wood, J.C. Adam, D.P. Lettenmaier, and B. Nijssen, 2002, A Long-Term Hydrologically-Based Data Set of Land Surface Fluxes and States for the Conterminous United States, J. Climate 15(22), 3237-3251", - "cdm_data_type": "Grid", - "date_created": "2014", - "date_issued": "2015-11-01", - "geospatial_lat_max": 37.0625, - "geospatial_lat_min": 33.0625, - "geospatial_lon_max": -74.9375, - "geospatial_lon_min": -84.9375, - "history": "Mon Jan 7 18:59:08 2019: ncks -4 -L3 bcsd_obs_1999_two_var.nc bcsd_obs_1999_two_var.nc.comp\nThu May 08 12:07:18 2014: cdo monsum gridded_obs/daily/gridded_obs.daily.Prcp.1950.nc gridded_obs/monthly/gridded_obs.monthly.pr.1950.nc", - "id": "cida.usgs.gov/bcsd_obs", - "institution": "Varies, see http://gdo-dcp.ucllnl.org/downscaled_cmip_projections/", - "keywords": "Atmospheric Temperature, Air Temperature Atmosphere, Precipitation, Rain, Maximum Daily Temperature, Minimum Daily Temperature", - "keywords_vocabulary": "GCMD Science Keywords", - "license": "Freely available", - "naming_authority": "cida.usgs.gov", - "processing_level": "Gridded meteorological observations", - "publisher_email": "dblodgett@usgs.gov", - "publisher_name": "Center for Integrated Data Analytics", - "publisher_url": "https://www.cida.usgs.gov/", - "summary": "These are the monthly observational data used for BCSD downscaling. See: http://gdo-dcp.ucllnl.org/downscaled_cmip_projections/dcpInterface.html#About for more information.", - "time_coverage_end": "1999-12-15T00:00", - "time_coverage_resolution": "P1M", - "time_coverage_start": "1950-01-15T00:00", - "title": "Monthly Gridded Meteorological Observations" - }, - ".zgroup": { - "zarr_format": 2 - }, - "latitude/.zarray": { - "chunks": [ - 33 - ], - "compressor": { - "id": "zstd", - "level": 1 - }, - "dtype": "U13", - "fill_value": "", - "filters": null, - "order": "C", - "shape": [ - 4 - ], - "zarr_format": 2 -} \ No newline at end of file diff --git a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.U13.be/0 b/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.U13.be/0 deleted file mode 100644 index 6f5d690..0000000 Binary files a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.U13.be/0 and /dev/null differ diff --git a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.U13.le/.zarray b/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.U13.le/.zarray deleted file mode 100644 index 3ac3e4b..0000000 --- a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.U13.le/.zarray +++ /dev/null @@ -1,20 +0,0 @@ -{ - "chunks": [ - 4 - ], - "compressor": { - "blocksize": 0, - "clevel": 5, - "cname": "lz4", - "id": "blosc", - "shuffle": 1 - }, - "dtype": "f4", - "fill_value": 0.0, - "filters": null, - "order": "C", - "shape": [ - 4 - ], - "zarr_format": 2 -} \ No newline at end of file diff --git a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.f4.be/0 b/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.f4.be/0 deleted file mode 100644 index 5956432..0000000 Binary files a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.f4.be/0 and /dev/null differ diff --git a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.f4.le/.zarray b/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.f4.le/.zarray deleted file mode 100644 index ae5e6de..0000000 --- a/inst/extdata/fixtures/v2/data.zarr/1d.contiguous.f4.le/.zarray +++ /dev/null @@ -1,20 +0,0 @@ -{ - "chunks": [ - 4 - ], - "compressor": { - "blocksize": 0, - "clevel": 5, - "cname": "lz4", - "id": "blosc", - "shuffle": 1 - }, - "dtype": "}} \describe{ -\item{\code{selection}}{selection TODO} +\item{\code{selection}}{selection as with ZarrArray, scalar, string, or Slice. "..." and ":" supported for string} -\item{\code{array}}{array TODO} +\item{\code{array}}{ZarrArray object that will be indexed} } \if{html}{\out{}} } @@ -55,13 +56,13 @@ A \code{VIndex} instance. \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-BasicIndexer-iter}{}}} \subsection{Method \code{iter()}}{ -TODO +An iterator over the dimensions of an array \subsection{Usage}{ \if{html}{\out{
}}\preformatted{BasicIndexer$iter()}\if{html}{\out{
}} } \subsection{Returns}{ -TODO +A list of ChunkProjection objects } } \if{html}{\out{
}} diff --git a/man/ZarrArray.Rd b/man/ZarrArray.Rd index d541b68..df4d60f 100644 --- a/man/ZarrArray.Rd +++ b/man/ZarrArray.Rd @@ -686,7 +686,9 @@ Subset the array. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} } \if{html}{\out{
}} } @@ -703,7 +705,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{out}}{TODO} @@ -724,7 +728,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{out}}{TODO} @@ -745,7 +751,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{out}}{TODO} @@ -766,7 +774,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{out}}{TODO} @@ -787,7 +797,9 @@ Set a subset of the array. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{value}}{The value to set, as an R array() or a Zarr NestedArray instance.} } @@ -806,7 +818,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{value}}{TODO} @@ -827,7 +841,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{value}}{TODO} @@ -848,7 +864,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{value}}{TODO} @@ -869,7 +887,9 @@ TODO \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects.} +\item{\code{selection}}{Selections are lists containing either scalars, strings, or Slice objects. Two character +literals are supported: "..." selects all remaining array dimensions and ":" selects all of a specific +array dimension.} \item{\code{value}}{TODO} @@ -1018,7 +1038,7 @@ Set values for a selection using bracket notation (for S3 method). \if{html}{\out{
}} \describe{ \item{\code{...}}{Contains the slicing parameters, one for each dimension. -Use empty space to get whole dimension e.g. \link{1:5,,}} +Use empty space to get whole dimension e.g. \code{[1:5,,]}} } \if{html}{\out{
}} } @@ -1039,7 +1059,7 @@ Assign values for a selection using bracket notation (for S3 method). \if{html}{\out{
}} \describe{ \item{\code{...}}{Contains the slicing parameters, one for each dimension. -Use empty space to get whole dimension e.g. \link{1:5,,}} +Use empty space to get whole dimension e.g. \code{[1:5,,]}} } \if{html}{\out{
}} } diff --git a/man/as.array.NestedArray.Rd b/man/as.array.NestedArray.Rd index 02b44f3..0c6ee64 100644 --- a/man/as.array.NestedArray.Rd +++ b/man/as.array.NestedArray.Rd @@ -4,10 +4,10 @@ \alias{as.array.NestedArray} \title{S3 method for as.array} \usage{ -\method{as.array}{NestedArray}(obj) +\method{as.array}{NestedArray}(x, ...) } \arguments{ -\item{obj}{} +\item{x}{} } \description{ S3 method for as.array diff --git a/man/as.array.ZarrArray.Rd b/man/as.array.ZarrArray.Rd index 6164fd1..2a8c3e6 100644 --- a/man/as.array.ZarrArray.Rd +++ b/man/as.array.ZarrArray.Rd @@ -4,9 +4,11 @@ \alias{as.array.ZarrArray} \title{S3 method for as.array} \usage{ -\method{as.array}{ZarrArray}(obj) +\method{as.array}{ZarrArray}(x, ...) } \arguments{ +\item{...}{not used} + \item{obj}{object} } \description{ diff --git a/man/figures/logo.png b/man/figures/logo.png new file mode 100644 index 0000000..5173ffc Binary files /dev/null and b/man/figures/logo.png differ diff --git a/man/pizzarr_sample.Rd b/man/pizzarr_sample.Rd new file mode 100644 index 0000000..3a85c2c --- /dev/null +++ b/man/pizzarr_sample.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{pizzarr_sample} +\alias{pizzarr_sample} +\title{pizzarr demo data} +\usage{ +pizzarr_sample( + dataset = NULL, + outdir = file.path(tempdir(TRUE), "pizzarr_sample") +) +} +\arguments{ +\item{dataset}{character defining which demo dataset is desired, +If NULL, all are returned} + +\item{outdir}{character directory path to store sample zarr stores} +} +\value{ +path to ready to use zarr store +} +\description{ +pizzarr demo data +} +\details{ +For directory stores, unzips the store to a temporary directory +and returns the resulting path. +} +\examples{ +zarr_samples <- pizzarr_sample() + +#printing without system path for example +gsub(tempdir(), "...", zarr_samples, fixed = TRUE) + +} diff --git a/man/slice.Rd b/man/slice.Rd index 4fc4109..fc2e974 100644 --- a/man/slice.Rd +++ b/man/slice.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/slicing.R \name{slice} \alias{slice} -\title{Shortcut for Slice$new() constructor.} +\title{Convenience function for the internal Slice class constructor.} \usage{ slice(start, stop = NA, step = NA, zero_based = FALSE) } @@ -19,5 +19,5 @@ slice(start, stop = NA, step = NA, zero_based = FALSE) A Slice instance with the specified parameters. } \description{ -Shortcut for Slice$new() constructor. +Convenience function for the internal Slice class constructor. } diff --git a/man/subset-.ZarrArray.Rd b/man/subset-.ZarrArray.Rd index e5e5b15..95a410a 100644 --- a/man/subset-.ZarrArray.Rd +++ b/man/subset-.ZarrArray.Rd @@ -7,9 +7,7 @@ \method{[}{ZarrArray}(obj, ...) <- value } \arguments{ -\item{obj}{object} - -\item{...}{dots} +\item{value}{array or ZarrArray} } \description{ S3 method for custom bracket assignment diff --git a/man/zarr_create.Rd b/man/zarr_create.Rd index 014f954..1508544 100644 --- a/man/zarr_create.Rd +++ b/man/zarr_create.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/creation.R \name{zarr_create} \alias{zarr_create} -\title{Create an array} +\title{Create an empty array} \usage{ zarr_create( shape, @@ -99,5 +99,5 @@ with checking the data of each chunk.} ZarrArray } \description{ -Create an array +Create an empty array } diff --git a/man/zarr_open_array.Rd b/man/zarr_open_array.Rd index 18a4277..01c1e70 100644 --- a/man/zarr_open_array.Rd +++ b/man/zarr_open_array.Rd @@ -6,6 +6,7 @@ \usage{ zarr_open_array( store = NA, + storage_options = NA, mode = NA, shape = NA, chunks = TRUE, @@ -29,6 +30,10 @@ zarr_open_array( \item{store}{: MutableMapping or string Store or path to directory in file system or name of zip file.} +\item{storage_options}{: dict +If using an fsspec URL to create the store, these will be passed to +the backend implementation. Ignored otherwise.} + \item{mode}{: {'r', 'r+', 'a', 'w', 'w-'}, optional Persistence mode: 'r' means read only (must exist); 'r+' means read/write (must exist); 'a' means read/write (create if doesn't diff --git a/man/zb_slice.Rd b/man/zb_slice.Rd index 21093b6..f32517c 100644 --- a/man/zb_slice.Rd +++ b/man/zb_slice.Rd @@ -2,7 +2,8 @@ % Please edit documentation in R/slicing.R \name{zb_slice} \alias{zb_slice} -\title{Shortcut for Slice$new() constructor with zero-based indexing and exclusive stop index.} +\title{Convenience function for the internal Sliceclass constructor +with zero-based indexing and exclusive stop index.} \usage{ zb_slice(start, stop = NA, step = NA) } @@ -14,5 +15,6 @@ zb_slice(start, stop = NA, step = NA) \item{step}{The step size.} } \description{ -Shortcut for Slice$new() constructor with zero-based indexing and exclusive stop index. +Convenience function for the internal Sliceclass constructor +with zero-based indexing and exclusive stop index. } diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 357781c..79db12e 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -76,6 +76,7 @@ reference: - as_scalar - is_scalar - is_key_error + - pizzarr_sample - Dtype diff --git a/tests/testthat/setup-utils.R b/tests/testthat/setup-utils.R index d775204..26eda5a 100644 --- a/tests/testthat/setup-utils.R +++ b/tests/testthat/setup-utils.R @@ -4,3 +4,23 @@ setup({ teardown({ }) + +zarr_volcano <- function() { + dir <- file.path(tempdir(TRUE), "volcano.zarr") + + unlink(dir, recursive = TRUE, force = TRUE) + + z <- DirectoryStore$new(dir) + + a <- volcano + + za <- zarr_create(dim(volcano), path = "volcano", store = z, overwrite = TRUE) + + za$set_item("...", a) + + g <- zarr_open_group(z) + + g$get_attrs()$set_item("tile", "volcano") + + g +} diff --git a/tests/testthat/test-compat.R b/tests/testthat/test-compat.R index 8c62ef1..bb08796 100644 --- a/tests/testthat/test-compat.R +++ b/tests/testthat/test-compat.R @@ -2,7 +2,7 @@ library(pizzarr) test_that("Can open Zarr group using convenience function", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample(file.path("fixtures", "v2", "data.zarr")) g <- zarr_open_group(root) a <- g$get_item("1d.contiguous.lz4.i2") @@ -12,7 +12,7 @@ test_that("Can open Zarr group using convenience function", { test_that("Can open Zarr group or array using convenience function", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") g <- zarr_open(root) a <- zarr_open(root, path="1d.contiguous.lz4.i2") @@ -22,7 +22,7 @@ test_that("Can open Zarr group or array using convenience function", { test_that("Can open Zarr group and read a 1D 2-byte integer array with LZ4 compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -41,7 +41,7 @@ test_that("Can open Zarr group and read a 1D 2-byte integer array with LZ4 compr test_that("Can open Zarr group and read a 1D 2-byte integer array with Zstd compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -60,7 +60,7 @@ test_that("Can open Zarr group and read a 1D 2-byte integer array with Zstd comp test_that("Can open Zarr group and read a 1D 2-byte integer array with Blosc compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -88,7 +88,7 @@ test_that("Can open Zarr group and read a 1D 2-byte integer array with Blosc com test_that("Can open Zarr group and read a 1D 2-byte integer array with Zlib compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -107,7 +107,7 @@ test_that("Can open Zarr group and read a 1D 2-byte integer array with Zlib comp test_that("Can open Zarr group and read a 1D 2-byte integer array with no compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -126,7 +126,7 @@ test_that("Can open Zarr group and read a 1D 2-byte integer array with no compre test_that("Can open Zarr group and read a 1D 4-byte integer array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -143,7 +143,7 @@ test_that("Can open Zarr group and read a 1D 4-byte integer array", { test_that("Can open Zarr group and read a 1D 1-byte unsigned integer array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -160,7 +160,7 @@ test_that("Can open Zarr group and read a 1D 1-byte unsigned integer array", { test_that("Can open Zarr group and read a 1D 4-byte float array, little endian", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -177,7 +177,7 @@ test_that("Can open Zarr group and read a 1D 4-byte float array, little endian", test_that("Can open Zarr group and read a 1D 4-byte float array, big endian", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -194,7 +194,7 @@ test_that("Can open Zarr group and read a 1D 4-byte float array, big endian", { test_that("Can open Zarr group and read a 1D 8-byte float array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -211,7 +211,7 @@ test_that("Can open Zarr group and read a 1D 8-byte float array", { test_that("Can open Zarr group and read a 1D 2-byte float array, 2 chunks", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -228,7 +228,7 @@ test_that("Can open Zarr group and read a 1D 2-byte float array, 2 chunks", { test_that("Can open Zarr group and read a 1D 2-byte float array, 2 chunks, ragged", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -245,7 +245,7 @@ test_that("Can open Zarr group and read a 1D 2-byte float array, 2 chunks, ragge test_that("Can open Zarr group and read a 2D 2-byte integer array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -263,7 +263,7 @@ test_that("Can open Zarr group and read a 2D 2-byte integer array", { test_that("Can open Zarr group and read a 2D 2-byte integer array, 2 chunks", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -281,7 +281,7 @@ test_that("Can open Zarr group and read a 2D 2-byte integer array, 2 chunks", { test_that("Can open Zarr group and read a 2D 2-byte integer array, 2 chunks, ragged", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -301,7 +301,7 @@ test_that("Can open Zarr group and read a 2D 2-byte integer array, 2 chunks, rag test_that("Can open Zarr group and read a 1D 1-byte boolean array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -318,7 +318,7 @@ test_that("Can open Zarr group and read a 1D 1-byte boolean array", { test_that("Can open Zarr group and read a 1D S7 string array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -335,7 +335,7 @@ test_that("Can open Zarr group and read a 1D S7 string array", { test_that("Can open Zarr group and read a 1D U7 string array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -352,7 +352,7 @@ test_that("Can open Zarr group and read a 1D U7 string array", { test_that("Can open Zarr group and read a 1D U13 little endian string array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -369,7 +369,7 @@ test_that("Can open Zarr group and read a 1D U13 little endian string array", { test_that("Can open Zarr group and read a 1D U13 big endian string array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -386,7 +386,7 @@ test_that("Can open Zarr group and read a 1D U13 big endian string array", { test_that("Can open Zarr group and read a 2D U7 string array", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -403,7 +403,7 @@ test_that("Can open Zarr group and read a 2D U7 string array", { test_that("Can open Zarr group and read a 1D VLen-UTF8 string array with no compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -420,7 +420,7 @@ test_that("Can open Zarr group and read a 1D VLen-UTF8 string array with no comp test_that("Can open Zarr group and read a 1D VLen-UTF8 string array with Blosc compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -436,7 +436,7 @@ test_that("Can open Zarr group and read a 1D VLen-UTF8 string array with Blosc c }) test_that("Can open Zarr group and read a 2D VLen-UTF8 string array with no compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -452,7 +452,7 @@ test_that("Can open Zarr group and read a 2D VLen-UTF8 string array with no comp }) test_that("Can open Zarr group and read a 2D VLen-UTF8 string array with Blosc compression", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -468,9 +468,9 @@ test_that("Can open Zarr group and read a 2D VLen-UTF8 string array with Blosc c }) test_that("DirectoryStore can listdir", { - root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) expect_equal(store$listdir("1d.chunked.i2"), c(".zarray", "0", "1")) -}) \ No newline at end of file +}) diff --git a/tests/testthat/test-get.R b/tests/testthat/test-get.R index 2f0a9cc..85dc935 100644 --- a/tests/testthat/test-get.R +++ b/tests/testthat/test-get.R @@ -16,7 +16,7 @@ test_that("get_basic_selection_zd", { }) test_that("get_basic_selection_zd with anndataR IntScalar fixture", { - root <- system.file("extdata", "fixtures", "v2", "example.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/example.zarr") store <- DirectoryStore$new(root) z <- zarr_open_array(store, path = "uns/IntScalar") @@ -30,7 +30,7 @@ test_that("get_basic_selection_zd with anndataR IntScalar fixture", { }) test_that("get_basic_selection_zd with anndataR StringScalar fixture", { - root <- system.file("extdata", "fixtures", "v2", "example.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/example.zarr") store <- DirectoryStore$new(root) z <- zarr_open_array(store, path = "uns/StringScalar") @@ -256,7 +256,7 @@ test_that("get_basic_selection_3d(one-based) - can get_item for three-dimensiona }) test_that("Can read 2D string array", { - root <- system.file("extdata", "fixtures", "v2", "example.zarr", package="pizzarr") + root <- pizzarr_sample("fixtures/v2/example.zarr") store <- DirectoryStore$new(root) z <- zarr_open_array(store, path = "uns/String2D") nested_arr <- z$get_item("...") diff --git a/tests/testthat/test-indexing-basic.R b/tests/testthat/test-indexing-basic.R index 2fdf00c..e63b6b7 100644 --- a/tests/testthat/test-indexing-basic.R +++ b/tests/testthat/test-indexing-basic.R @@ -117,4 +117,26 @@ test_that("basic indexer for array that spans multiple chunks where shape is not expect_equal(sdi2$dim_chunk_len, 3) expect_equal(sdi2$num_items, 5) expect_equal(sdi2$num_chunks, 4) +}) + +test_that("selection functionality", { + + a <- zarr_volcano()$get_item("volcano") + + sub_a <- a$get_item(list(slice(1, 10), "...")) + + expect_equal(sub_a$shape, c(10, a$get_shape()[2])) + + sub_a <- a$get_item(list(":", slice(1, 10))) + + expect_equal(sub_a$shape, c(a$get_shape()[1], 10)) + + sub_a <- a$get_item(list(1, "...")) + + expect_equal(sub_a$shape, c(1, a$get_shape()[2])) + + sub_a <- a$get_item(list("...", slice(1, 10))) + + expect_equal(sub_a$shape, c(a$get_shape()[1], 10)) + }) \ No newline at end of file diff --git a/tests/testthat/test-nested-array.R b/tests/testthat/test-nested-array.R index cff115d..5532745 100644 --- a/tests/testthat/test-nested-array.R +++ b/tests/testthat/test-nested-array.R @@ -52,4 +52,50 @@ test_that("NestedArray can be set using list of zb_slices", { python_sel <- na$get(list(zb_slice(0, 2), zb_slice(0, 3))) expect_equal(python_sel$data, new_a) +}) + +test_that("zero_based_to_one_based", { + + s <- list(slice(1, 11, 1)) + + expect_equal(zero_based_to_one_based(s, shape = c(20, 20)), + list(c(1:11))) + + s <- list(slice(1, 11, 2)) + + expect_equal(zero_based_to_one_based(s, shape = c(20, 20)), + list(seq(1, 11, 2))) +}) + +test_that("set array values", { + + d <- zarr_volcano() + + a <- d$get_item("volcano") + + vals <- a[1:10, 1:20]$as.array() + + new_vals <- vals * 10 + + sub <- a[1:10, 1:20] + + sub$set(list(slice(1,10), slice(1,20)), new_vals) + + expect_equal(sub$as.array(), + new_vals) + + # Should this be the case?!? + expect_error(a[1:10, 1:20]$set("...", new_vals), + "selection must be a list of slices") + + a[1:10, 1:20]$set(list(slice(1,10), slice(1,20)), new_vals) + + # it does not update the original array -- should it? + expect_equal(a[1:10, 1:20]$as.array(), + vals) + + a$set_item(list(slice(1,10), slice(1,20)), new_vals) + + expect_equal(a[1:10, 1:20]$as.array(), + new_vals) }) \ No newline at end of file diff --git a/tests/testthat/test-slice-indices.R b/tests/testthat/test-slice-indices.R index ff5c515..3988df1 100644 --- a/tests/testthat/test-slice-indices.R +++ b/tests/testthat/test-slice-indices.R @@ -36,4 +36,14 @@ test_that("slice gets converted to zb_slice", { expect_equal(s1$start, s2$start) expect_equal(s1$stop, s2$stop) expect_equal(s1$step, s2$step) +}) + +test_that("step size greater than 1", { + g <- zarr_volcano() + + s <- slice(1, 21, 2) + + d <- g$get_item("volcano")$get_item(list(s, s))$data + + expect_equal(dim(d), c(11, 11)) }) \ No newline at end of file diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index c0b1897..3a92b79 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -1,5 +1,19 @@ library(pizzarr) +test_that("demo data", { + + demo_data <- pizzarr_sample() + + expect_true(all(dir.exists(demo_data))) + + expect_true(all(grepl("zarr$", demo_data))) + + expect_error(pizzarr_sample("borked"), "Dataset not found") + + expect_true(grepl("bcsd.zarr", pizzarr_sample("bcsd"))) + +}) + test_that("create_zarray_meta does not throw error when simple dtype is valid", { res <- create_zarray_meta(dtype = Dtype$new("|u1"), order = "C", fill_value = 0, dimension_separator = ".") expect_equal(class(res$dtype)[[1]], "scalar") @@ -193,4 +207,12 @@ test_that("get_list_product", { list('C', 'y'), list('D', 'y') )) +}) + +test_that("NaN in json", { + check <- try_fromJSON('{"name": NaN}') + + expect_equal(check, list(name = NULL)) + + expect_warning(try_fromJSON("borked", "test warning"), "test warning") }) \ No newline at end of file diff --git a/vignettes/basics.Rmd b/vignettes/basics.Rmd index 55c49d8..4e47eb3 100644 --- a/vignettes/basics.Rmd +++ b/vignettes/basics.Rmd @@ -64,7 +64,7 @@ print(a$get_shape()) ## List arrays in a zarr root group ```{r} -root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") +root <- pizzarr_sample("fixtures/v2/data.zarr") z <- zarr_open(root) @@ -80,7 +80,7 @@ print(store$listdir()) ## Open a ZarrArray from a DirectoryStore (convenience) ```{r} -root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") +root <- pizzarr_sample("fixtures/v2/data.zarr") g <- zarr_open_group(root) a <- g$get_item("1d.contiguous.lz4.i2") @@ -91,7 +91,7 @@ print(a$get_shape()) ## Open a ZarrArray from a DirectoryStore ```{r} -root <- system.file("extdata", "fixtures", "v2", "data.zarr", package="pizzarr") +root <- pizzarr_sample("fixtures/v2/data.zarr") store <- DirectoryStore$new(root) g <- ZarrGroup$new(store) @@ -103,7 +103,7 @@ print(a$get_shape()) ## Get attributes from a root group and ZarrArray ```{r} -root <- system.file("extdata", "dog.ome.zarr", package="pizzarr") +root <- pizzarr_sample("dog.ome.zarr") z <- zarr_open(root) @@ -122,4 +122,4 @@ a <- z$get_item("4") class(a) a$get_attrs()$to_list() -``` \ No newline at end of file +``` diff --git a/vignettes/ome-ngff.Rmd b/vignettes/ome-ngff.Rmd index cf5068f..08dee7e 100644 --- a/vignettes/ome-ngff.Rmd +++ b/vignettes/ome-ngff.Rmd @@ -21,7 +21,7 @@ install.packages("raster") library(pizzarr) # The path to the root of the OME-NGFF Zarr store. -root <- system.file("extdata", "dog.ome.zarr", package="pizzarr") +root <- pizzarr_sample("dog.ome.zarr") # Open the OME-NGFF as a DirectoryStore. store <- DirectoryStore$new(root) diff --git a/vignettes/pizzarr.Rmd b/vignettes/pizzarr.Rmd new file mode 100644 index 0000000..43e24e1 --- /dev/null +++ b/vignettes/pizzarr.Rmd @@ -0,0 +1,183 @@ +--- +title: "Getting Started" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Getting Started} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} + knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + out.width = "100%" +) +``` + +# Introduction + +Pizzarr implements an object oriented zarr client library that represents zarr stores, groups, attributes, and arrays. + +For those not familiar with zarr, a "store" implies how the entire zarr dataset is... stored. e.g. in memory, on disk, or on the internet. A group is a container that may be in a hierarchy, it can contain group level attributes, arrays, and / or child groups. Attributes are key value pairs carried by both groups and attributes. Arrays are where the actual data reside and can be chunked and compressed in a variety of ways. + +When you encounter a zarr store, you would usually first look in the "root group" metadata and list the groups and arrays recursively to figure out what the store contains. From there, you might look at metadata associated with arrays and any child groups the store contains to figure out what they are or how you might want to work with them. + +Some zarr stores include what's known as "consolidated metadata". It is consolidated because all the metadata from all the groups and arrays in the store are consolidated into a single json file contained in the root group. This can be super convenient or even required if the store doesn't support "listing" like you do with `ls` at a terminal (http stores for example). The problem with consolidated metadata is that it can get out of sync with what the dataset actually contains, so it is usually created once a dataset is done and ready to be made "read only". + +# pizzarr classes: + +`Store` class: Implements a variety of ways to store zarr data. Is the container for all groups and arrays in a zarr dataset. +`ZarrGroup` class: Supports getting and setting attributes of a group and creating groups and arrays within a group. +`ZarrArray` class: Supports a variety of operations for getting and setting attributes and data from an array. +`Attributes` class: Supports access to attributes carried by groups and arrays. +`Codec`class: Supports encoding and decoding arrays according to the implemented compressor. +`Dtype` class: Supports handling R data types as zarr codec compatible data types. + +# Core use cases: + +## Create stores, groups, and arrays + +An empty store can be created with one of the store implementations or by specifying +the store type when creating a group or an array. + +```{r} +library(pizzarr) + +# get an empty store to add to later +mem_store <- MemoryStore$new() + +class(mem_store) + +# create a store in line when creating an empty array +demo_array <- zarr_create(c(1,2,3), store = NA) + +demo_array_store <- demo_array$get_store() + +class(demo_array_store) + +demo_array_store$listdir() + +# or create a store when creating a group to contain arrays +# notice that passing a path creates a directory store +store_path <- file.path(tempdir(), "demo.zarr") + +demo_group <- zarr_create_group(store = store_path) + +demo_group_store <- demo_group$get_store() + +basename(demo_group_store$root) + +class(demo_group_store) + +demo_group_store$listdir() + +``` +## Set and get attributes + +We now have 1) an empty memory store, 2) an empty array in a memory store, and 3) a group defined within a directory store. Now we'll create a group using our existing empty memory store and add some attributes to it, retrieve them, and delete them. + +```{r} + +demo_mem_store_group <- zarr_create_group(mem_store) + +demo_mem_store_group$get_attrs()$key + +demo_mem_store_group$get_attrs()$set_item("this is", "an attribute") + +demo_mem_store_group$get_attrs()$to_list() + +demo_mem_store_group$get_attrs()$del_item("this is") + +demo_mem_store_group$get_attrs()$to_list() + +``` +Notice that we can do the same thing on arrays -- which can also carry attributes. + +```{r} + +demo_array_store$listdir() + +demo_array$get_attrs()$set_item("this is", "array metadata") + +demo_array$get_attrs()$to_list() + +# notice that when we added the item, our demo array store got a .zattrs +demo_array_store$listdir() + +``` +## Set values of an array + +Now that we have the ability to create stores, groups, and arrays and know how to add attributes to groups and arrays, let's look at how to add data. For this, we'll use the directory store we created above. + +```{r} + +zarr_volcano <- zarr_create_array(volcano, # the R array classic + shape = dim(volcano), + store = demo_group_store, # the store we want the array in + path = "volcano") # the path we want the array stored in + +demo_group_store$listdir() + +zarr_volcano$get_shape() + +all.equal(zarr_volcano$as.array(), + volcano) + +``` + +Now that we have an array in a zarr store, we can pull out subsets of it with pizzarr R6 methods or with the `S3` method for `[`. + +```{r} +sub_zarr_volcano <- zarr_volcano$get_item(list(slice(1, 10), slice(1, 20))) + +all.equal(sub_zarr_volcano$as.array(), + volcano[1:10, 1:20]) + +sub_zarr_volcano <- zarr_volcano[1:10, 1:20] + +class(sub_zarr_volcano) + +sub_zarr_volcano$shape + +all.equal(sub_zarr_volcano$as.array(), + volcano[1:10, 1:20]) + +``` + +Notice that we can also update the values of an array with the `set_item()` method. + +```{r} + +# this woll work once implemented? +# zarr_volcano[1:10, 1:20] <- zarr_volcano[1:10, 1:20] * 10 + +zarr_volcano$set_item(list(slice(1, 10), slice(1, 20)), + zarr_volcano[1:10, 1:20]$as.array() * 10) + +``` + +The `slice()` function is great but the `selection` input to the `get_item()` and `set_item()` methods can also accept other kinds of inputs. Namely, scalars to select single indices and a couple of special character strings. + +`"..."` selects everything else. It can be used to the left, right, or in the middle of the selection list but can only be used once. +`":"` selects everything along a single dimension and can be used as many times as needed. + +```{r} + +sub_zarr_volcano <- zarr_volcano$get_item(list(1, "...")) + +sub_zarr_volcano$shape + +sub_zarr_volcano <- zarr_volcano$get_item(list(":", 1)) + +sub_zarr_volcano$shape + +sub_zarr_volcano <- zarr_volcano$get_item(list("...")) + +sub_zarr_volcano$shape + +sub_zarr_volcano <- zarr_volcano$get_item(list(slice(1, 20, 2), slice(1, 10, 1))) + +sub_zarr_volcano$shape + +``` \ No newline at end of file