diff --git a/DESCRIPTION b/DESCRIPTION index 3646faa..27de6b4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,7 +28,7 @@ Imports: Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Suggests: testthat, knitr, diff --git a/NAMESPACE b/NAMESPACE index 2e33938..16d9a0f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,6 +23,7 @@ export(ZarrGroup) export(ZlibCodec) export(ZstdCodec) export(as_scalar) +export(int) export(is_key_error) export(is_scalar) export(is_slice) @@ -39,4 +40,5 @@ export(zarr_open) export(zarr_open_array) export(zarr_open_group) export(zarr_save_array) +export(zb_int) export(zb_slice) diff --git a/R/array-nested.R b/R/array-nested.R index 02145e5..79ee933 100644 --- a/R/array-nested.R +++ b/R/array-nested.R @@ -1,40 +1,53 @@ #' @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") + # drop this since we could do it for arbitrary indices + # 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))) { + + # get selection sel <- selection[[i]] - # We assume the selection uses zero-based indexing, - # and internally convert to R-based / 1-based indexing - # 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 - message("IndexError: NestedArray$get() received slice with start index out of bounds - too low") - } - if(sel_start > shape[i]) { - sel_start <- shape[i] - message("IndexError: NestedArray$get() received slice with start index out of bounds - too high") - } - if(sel_stop < 1) { - sel_stop <- 1 - message("IndexError: NestedArray$get() received slice with stop index out of bounds - too low") - } - if(sel_stop > shape[i]) { - sel_stop <- shape[i] - message("IndexError: NestedArray$get() received slice with stop index out of bounds - too high") + + # for slice + if(inherits(sel, "Slice")){ + + # We assume the selection uses zero-based indexing, + # and internally convert to R-based / 1-based indexing + # 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 + message("IndexError: NestedArray$get() received slice with start index out of bounds - too low") + } + if(sel_start > shape[i]) { + sel_start <- shape[i] + message("IndexError: NestedArray$get() received slice with start index out of bounds - too high") + } + if(sel_stop < 1) { + sel_stop <- 1 + message("IndexError: NestedArray$get() received slice with stop index out of bounds - too low") + } + if(sel_stop > shape[i]) { + sel_stop <- shape[i] + message("IndexError: NestedArray$get() received slice with stop index out of bounds - too high") + } + selection_list <- append(selection_list, list(seq(from = sel_start, + to = sel_stop, + by = sel_step))) + } else if(is.numeric(sel)) { + sel <- sel + 1 + selection_list <- append(selection_list, list(sel)) + } else { + stop("Unsupported selection type") } - selection_list <- append(selection_list, list(seq(from = sel_start, - to = sel_stop, - by = sel_step))) } return(selection_list) } diff --git a/R/atomic.R b/R/atomic.R index da721a1..c6fc68a 100644 --- a/R/atomic.R +++ b/R/atomic.R @@ -23,7 +23,7 @@ is_scalar <- function(s) { #' Check if a value is an integer R vector or scalar. #' @keywords internal is_integer <- function(s) { - if(is.atomic(s) && is.numeric(s) && all(s %% 1 == 0)) { + if(is.atomic(s) && is.numeric(s) && all(s %% 1 == 0) && length(s) == 1) { return(TRUE) } return(FALSE) @@ -42,8 +42,10 @@ is_integer_scalar <- function(s) { #' explicitly tagged as a scalar. #' @keywords internal is_integer_vec <- function(s) { - if(!is_scalar(s) && is_integer(s)) { - return(TRUE) + if(!is_scalar(s) && is.vector(s) && !is.list(s) && all(sapply(s,is_integer))) { + if(length(s) > 1){ + return(TRUE) + } } return(FALSE) } diff --git a/R/filters.R b/R/filters.R new file mode 100644 index 0000000..b226980 --- /dev/null +++ b/R/filters.R @@ -0,0 +1,52 @@ +# transforming filters to be passed to ZarrArray$get_orthogonal_selection() +# +# a:b => slice(a,b) +# seq(from, to, by) => slice(start, stop, step) ? for now indices of seq(from, to, by) are passed to get_orthogonal_selection (check below, TODO) +# c(a,b,c) => c(a,b,c), combine elements are passed as indices +# empty dimension => return everything +# +manage_filters <- function(filters) { + lapply(filters, function(x) { + # Proceed based on type of filter + if(typeof(x) == "symbol") { + # When empty dimension, return everything + if(x == "") { + return(NULL) + } else { + stop("Unsupported filter '", as.character(x), "' supplied") + } + } else if(typeof(x) == "double") { + # Return single value for dimension + return(slice(x, x)) + } else if(typeof(x) == "language") { + x <- as.list(x) + # Return a range (supplied via : or seq()) + if(x[[1]] == ":") { + return(slice(x[[2]], x[[3]])) + } else if(x[[1]] == "seq") { + # TODO: do we need slicing for this case ? otherwise implement slice(start, stop, step) + arg_names <- names(x) + from <- ifelse("from" %in% arg_names, x[[which("from" == arg_names)]], x[[2]]) + to <- ifelse("to" %in% arg_names, x[[which("to" == arg_names)]], x[[3]]) + if(length(x) > 3) { + by <- ifelse("by" %in% arg_names, x[[which("by" == arg_names)]], x[[4]]) + return(int(seq(from, to, by))) + } else { + by <- NA + return(int(seq(from, to))) + } + return(int(seq(from, to, by))) + } else if(x[[1]] == "c") { + # return elements of the combine function as indices + check_func <- sapply(x, function(y) { + !is.function(eval(y)) + }) + return(int(floor(unlist(x[check_func])))) + } else { + stop("Unsupported filter '", as.character(x), "' supplied") + } + } else { + stop("Unsupported filter '", as.character(x), "' supplied") + } + }) +} \ No newline at end of file diff --git a/R/indexing.R b/R/indexing.R index cf3072c..d0d530d 100644 --- a/R/indexing.R +++ b/R/indexing.R @@ -1,3 +1,33 @@ +# Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0/zarr/indexing.py#L61 + +# Check whether a selection contains only integer array-likes +# This is used to determine whether zarr.array$get_item() calls vectorized (inner) indexing +is_pure_fancy_indexing <- function(selection, ndim = length(selection)) { + + # one dimensions case + if(ndim == 1){ + if(is_integer_vec(selection) | is_integer_list(selection)){ + return(TRUE) + } + } + + # check if there are any slice objects + no_slicing <- (length(selection) == ndim) & !(any(sapply(selection, function(s) inherits(s, "Slice")))) + + # check for integer vectors + all_integer <- all(sapply(selection, function(sel){ + (is_integer(sel) | is_integer_list(sel)) | is_integer_vec(sel) + })) + any_integer <- any(sapply(selection, function(sel){ + # is_integer_list(sel) | is_integer_vec(sel) + is_integer_list(sel) | is_integer_vec(sel) | is_integer(sel) + })) + + # return + return((no_slicing & all_integer) & any_integer) +} + + # Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0/zarr/indexing.py#L655 #' The Zarr OIndex class. @@ -18,6 +48,14 @@ OIndex <- R6::R6Class("OIndex", #' @return An `OIndex` instance. initialize = function(array) { self$array <- array + }, + #' @description + #' get method for the Oindex instance + #' @param selection selection + #' @return An `OIndex` instance. + get_item = function(selection) { + # self$array <- array$get + self$array$get_orthogonal_selection(selection) } ) ) @@ -322,3 +360,306 @@ BasicIndexer <- R6::R6Class("BasicIndexer", } ) ) + +# Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0e6cdc04c6413e14f57f61d389972ea937c/zarr/indexing.py#L585 + +#' The Zarr OrthogonalIndexer class. +#' @title OrthogonalIndexer Class +#' @docType class +#' @description +#' 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 OrthogonalIndexer +#' @keywords internal +OrthogonalIndexer <- R6::R6Class("OrthogonalIndexer", + inherit = Indexer, + public = list( + #' @field dim_indexers TODO + #' @keywords internal + dim_indexers = NULL, + #' @description + #' Create a new VIndex instance. + #' @return A `VIndex` instance. + initialize = function(selection, array) { + + shape <- array$get_shape() + chunks <- array$get_chunks() + + # Normalize + selection <- normalize_list_selection(selection, shape) + + # Setup per-dimension indexers + dim_indexers <- list() + for(i in seq_along(selection)) { + dim_sel <- selection[[i]] + dim_len <- shape[i] + dim_chunk_len <- chunks[i] + + if(is.null(dim_sel)) { + dim_sel <- zb_slice(NA) + } + + # TODO: for now, normalize_list_selection will get SliceDimIndexer for single integer + if(length(dim_sel) == 1) { + dim_indexer <- IntDimIndexer$new(dim_sel, dim_len, dim_chunk_len) + } else if(is_slice(dim_sel)) { + dim_indexer <- SliceDimIndexer$new(dim_sel, dim_len, dim_chunk_len) + } else if(length(dim_sel) > 1) { + dim_indexer <- IntArrayDimIndexer$new(dim_sel, dim_len, dim_chunk_len) + # TODO: implement BoolArrayDimIndexer and fix if condition here (is_bool_vec) + # } else if(is_bool_vec(dim_sel)) { + # dim_indexer <- BoolArrayDimIndexer$new(dim_sel, dim_len, dim_chunk_len) + } else { + stop('Unsupported selection item for basic indexing, expected integer, slice, vector of integer or boolean') + } + dim_indexers <- append(dim_indexers, dim_indexer) + } + self$shape <- list() + for(d in dim_indexers) { + if(class(d)[[1]] != "IntDimIndexer") { + self$shape <- append(self$shape, d$num_items) + } + } + self$drop_axes <- NA + + self$dim_indexers <- dim_indexers + + }, + #' @description + #' 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() + + # dim_indexers is a list of DimIndexer objects. + # dim_indexer_iterables is a list (one per dimension) + # of lists of IntDimIndexer or SliceDimIndexer objects. + dim_indexer_iterables <- lapply(self$dim_indexers, function(di) di$iter()) + dim_indexer_product <- get_list_product(dim_indexer_iterables) + + + for(row_i in seq_len(length(dim_indexer_product))) { + dim_proj <- dim_indexer_product[[row_i]] + + chunk_coords <- list() + chunk_sel <- list() + out_sel <- list() + + if(!is.list(dim_proj)) { + dim_proj <- list(dim_proj) + } + + for(p in dim_proj) { + chunk_coords <- append(chunk_coords, p$dim_chunk_index) + # chunk_sel <- append(chunk_sel, p$dim_chunk_sel) + chunk_sel <- append(chunk_sel, list(p$dim_chunk_sel)) + if(!is_na(p$dim_out_sel)) { + # out_sel <- append(out_sel, p$dim_out_sel) + out_sel <- append(out_sel, list(p$dim_out_sel)) + } + } + + result <- append(result, ChunkProjection$new( + chunk_coords, + chunk_sel, + out_sel + )) + } + + return(result) + } + ) +) + +# Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0e6cdc04c6413e14f57f61d389972ea937c/zarr/indexing.py#L424 + +#' The Order class. +#' @title Order Class +#' @docType class +#' @description +#' TODO +#' @rdname Order +#' @keywords internal +Order <- R6::R6Class("Order", + public = list( + #' @field UNKNOWN UNKNOWN + #' @keywords internal + UNKNOWN = 0, + #' @field INCREASING INCREASING + #' @keywords internal + INCREASING = 1, + #' @field DECREASING DECREASING + #' @keywords internal + DECREASING = 2, + #' @field UNORDERED UNORDERED + #' @keywords internal + UNORDERED = 3, + #' @description + #' checking order of numbers + #' @param a vector of numbers + check = function(a){ + diff_a <- diff(a) + diff_positive <- diff_a >= 0 + n_diff_positive <- sum(diff_positive) + all_increasing <- n_diff_positive == length(diff_positive) + any_increasing <- n_diff_positive > 0 + if(all_increasing){ + return(Order$public_fields$INCREASING) + } else if(any_increasing) { + return(Order$public_fields$UNORDERED) + } else{ + return(Order$public_fields$DECREASING) + } + }) + ) + +# Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0e6cdc04c6413e14f57f61d389972ea937c/zarr/indexing.py#L457 + +#' The Zarr IntArrayDimIndexer class. +#' @title IntArrayDimIndexer Class +#' @docType class +#' @description +#' TODO +#' @rdname IntArrayDimIndexer +#' @keywords internal +IntArrayDimIndexer <- R6::R6Class("IntArrayDimIndexer", + inherit = DimIndexer, + public = list( + #' @field dim_len dimension length + #' @keywords internal + dim_len = NULL, + #' @field dim_chunk_len dimension chunk length + #' @keywords internal + dim_chunk_len = NULL, + #' @field num_chunks number of chunks + #' @keywords internal + num_chunks = NULL, + #' @field dim_sel selection on dimension + #' @keywords internal + dim_sel = NULL, + #' @field dim_out_sel TODO + #' @keywords internal + dim_out_sel = NULL, + #' @field order order + #' @keywords internal + order = NULL, + #' @field chunk_nitems number of items per chunk + #' @keywords internal + chunk_nitems = NULL, + #' @field dim_chunk_ixs chunks that should be visited + #' @keywords internal + dim_chunk_ixs = NULL, + #' @field chunk_nitems_cumsum offsets into the output array + #' @keywords internal + chunk_nitems_cumsum = NULL, + #' @description + #' Create a new IntArrayDimIndexer instance. + #' @param dim_sel integer dimention selection + #' @param dim_len integer dimension length + #' @param dim_chunk_len integer dimension chunk length + #' @param sel_order order + #' @return A `IntArrayDimIndexer` instance. + initialize = function(dim_sel, dim_len, dim_chunk_len, sel_order = Order$public_fields$UNKNOWN) { + + # Normalize + dim_sel <- sapply(dim_sel, normalize_integer_selection, dim_len = dim_len) + self$dim_sel <- dim_sel + + # store attributes + self$dim_len <- dim_len + self$dim_chunk_len <- dim_chunk_len + self$num_items <- length(dim_sel) + self$num_chunks <- ceiling(self$dim_len / self$dim_chunk_len) + + # dim_sel_chunk <- ceiling(dim_sel / dim_chunk_len) # pre zb_int() implementation + dim_sel_chunk <- floor(dim_sel / dim_chunk_len) + + # determine order of indices + if(sel_order == Order$public_fields$UNKNOWN) + sel_order <- Order$public_methods$check(dim_sel) + self$order <- sel_order + + if(self$order == Order$public_fields$INCREASING){ + self$dim_sel <- dim_sel + } else if(self$order == Order$public_fields$DECREASING) { + self$dim_sel = rev(dim_sel) + self$dim_out_sel = rev(seq(1,self$num_items)) + # self$dim_out_sel = rev(seq(0,self$num_items-1)) # Python based indexing + } else { + # sort indices to group by chunk + self$dim_out_sel = order(dim_sel_chunk) + self$dim_sel <- dim_sel[self$dim_out_sel] + # self$dim_out_sel <- self$dim_out_sel - 1 # Python based indexing + } + + # precompute number of selected items for each chunk + # self$chunk_nitems <- tabulate(dim_sel_chunk, nbins = self$num_chunks) # pre zb_int() implementation + self$chunk_nitems <- tabulate(dim_sel_chunk + 1, nbins = self$num_chunks) + + # find chunks that we need to visit + self$dim_chunk_ixs = which(self$chunk_nitems != 0) + + # compute offsets into the output array + self$chunk_nitems_cumsum = cumsum(self$chunk_nitems) + + }, + #' @description + #' An iterator over the dimensions of an array + #' @return A list of ChunkProjection objects + iter = function() { + + # Iterate over chunks in range + result <- list() + for(dim_chunk_ix in self$dim_chunk_ixs) { + + # find region in output + # if (dim_chunk_ix == 0) { + if (dim_chunk_ix == 1) { + start <- 0 + } else { + start <- self$chunk_nitems_cumsum[dim_chunk_ix - 1] + } + stop <- self$chunk_nitems_cumsum[dim_chunk_ix] + + # START R-SPECIFIC + if(start == stop) { + stop <- stop + 1 + } + # END R-SPECIFIC + + if (self$order == Order$public_fields$INCREASING) { + dim_out_sel <- seq(start, stop - 1) + } else { + dim_out_sel <- self$dim_out_sel[(start + 1):stop] + # START R-SPECIFIC + dim_out_sel <- dim_out_sel - 1 + # END R-SPECIFIC + } + + # START R-SPECIFIC + dim_chunk_ix <- dim_chunk_ix - 1 + # END R-SPECIFIC + + # find region in chunk + dim_offset <- dim_chunk_ix * self$dim_chunk_len + # dim_chunk_sel <- self$dim_sel[(start + 1):stop] - dim_offset - 1 # pre zb_int implementation() + dim_chunk_sel <- self$dim_sel[(start + 1):stop] - dim_offset + + # # START R-SPECIFIC + # dim_chunk_ix <- dim_chunk_ix - 1 + # # END R-SPECIFIC + + result <- append(result, ChunkDimProjection$new( + dim_chunk_ix, + dim_chunk_sel, + dim_out_sel + )) + } + return(result) + } + ) +) diff --git a/R/int.R b/R/int.R new file mode 100644 index 0000000..6649c97 --- /dev/null +++ b/R/int.R @@ -0,0 +1,61 @@ +# TODO: int() and zb_int() now being used but do we need 'Int' Class ? + +#' Abstract Int object +#' @title Int Class +#' @docType class +#' @description +#' Class representing an indexing of a ZARR store +#' @noRd +#' @keywords internal +Int <- R6::R6Class("Int", + public = list( + #' @field start start index + index = NULL, + #' @description Create a new `Int` object + #' @param index integer index + initialize = function(index) { + self$index <- index + }, + #' @description + #' This method takes a single integer argument `length_param` and computes information about the + #' slice that the slice object would describe if applied to a sequence of `length_param` items. + #' It returns a tuple of three integers; respectively these are the start and stop indices + # and the step or stride length of the slice. Missing or out-of-bounds indices are handled + # in a manner consistent with regular slices. + #' @param length_param integer length parameter for calculation of integer indices + indices = function(length_param) { + + # check length_param + index <- self$index[self$index <= length_param] + + # return + return(c(index, length_param)) + } + ) +) + +#' Convenience function for the internal Int class constructor. +#' @param index The integer index. +#' @param zero_based The index of the dimension. By default, FALSE for R-like behavior. +#' @return A Int instance with the specified parameters. +#' @export +int <- function(index, zero_based = FALSE) { + index_offset <- ifelse(zero_based, 0, -1) + if(!is_na(index) && is.numeric(index)) { + index <- index + index_offset + } + # Assumed to be zero-based + # and stop-inclusive + # return(Int$new( + # index = index + # )) + index +} + +#' Convenience function for the internal Int class constructor +#' with zero-based indexing +#' @param index integer index +#' @export +zb_int <- function(index) { + return(int(index, zero_based = TRUE)) +} \ No newline at end of file diff --git a/R/normalize.R b/R/normalize.R index 91060af..9bfebec 100644 --- a/R/normalize.R +++ b/R/normalize.R @@ -5,14 +5,14 @@ normalize_list_selection <- function(selection, shape, convert_integer_selection for(i in seq_along(selection)) { dim_sel <- selection[[i]] - if(is_integer(dim_sel)) { + if(is_integer(dim_sel)){ if(convert_integer_selection_to_slices) { selection[[i]] <- zb_slice(dim_sel, dim_sel + 1, 1) } else { selection[[i]] <- normalize_integer_selection(dim_sel, shape[i]) } - } 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_integer_vec(dim_sel)) { + selection[[i]] <- sapply(dim_sel, normalize_integer_selection, dim_len = shape[i]) } else if(!is.null(dim_sel) && !is.environment(dim_sel) && (is.na(dim_sel) || dim_sel == ":")) { selection[[i]] <- zb_slice(NA, NA, 1) @@ -28,13 +28,16 @@ normalize_integer_selection <- function(dim_sel, dim_len) { # Normalize type to int dim_sel <- as_scalar(dim_sel) + # TODO: do we really need this for R type array indexing ? # handle wraparound if(dim_sel < 0) { dim_sel <- dim_len + dim_sel } - # Handle out of bounds + # TODO: do we need to normalize R indexing or Python indexing here ? + # handle out of bounds if(dim_sel >= dim_len || dim_sel < 0) { + # if(dim_sel > dim_len || dim_sel < 1) { # pre zb_int implementation stop('BoundsCheckError(dim_len)') } diff --git a/R/zarr-array.R b/R/zarr-array.R index 6879488..965500d 100644 --- a/R/zarr-array.R +++ b/R/zarr-array.R @@ -1067,7 +1067,14 @@ ZarrArray <- R6::R6Class("ZarrArray", get_item = function(selection) { # Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0/zarr/core.py#L580 # Reference: https://github.com/gzuidhof/zarr.js/blob/master/src/core/index.ts#L266 - return(self$get_basic_selection(selection)) + + if(is_pure_fancy_indexing(selection)){ + # TODO: implement vindex further for vectorized indexing + stop("vectorized indexing is not supported yet") + # return(self$get_vindex()$get_item(selection)) + } else { + return(self$get_basic_selection(selection)) + } }, #' @description #' TODO @@ -1091,7 +1098,14 @@ ZarrArray <- R6::R6Class("ZarrArray", #' @param out TODO #' @param fields TODO get_orthogonal_selection = function(selection = NA, out = NA, fields = NA) { - # TODO + + # Refresh metadata + if(!private$cache_metadata) { + private$load_metadata() + } + + indexer <- OrthogonalIndexer$new(selection, self) + return(private$get_selection(indexer, out = out, fields = fields)) }, #' @description #' TODO @@ -1215,46 +1229,12 @@ ZarrArray <- R6::R6Class("ZarrArray", if(length(filters) != length(private$shape)) { stop("This Zarr object has ", length(private$shape), " dimensions, ", length(filters), " were supplied") } - filters <- lapply(filters, function(x) { - # Proceed based on type of filter - if(typeof(x) == "symbol") { - # When empty dimension, return everything - if(x == "") { - return(NULL) - } else { - stop("Unsupported filter '", as.character(x), "' supplied") - } - - } else if(typeof(x) == "double") { - # Return single value for dimension - return(slice(x, x)) - } else if(typeof(x) == "language") { - x <- as.list(x) - # Return a range (supplied via : or seq()) - if(x[[1]] == ":") { - return(slice(x[[2]], x[[3]])) - } else if(x[[1]] == "seq") { - arg_names <- names(x) - from <- ifelse("from" %in% arg_names, x[[which("from" == arg_names)]], x[[2]]) - to <- ifelse("to" %in% arg_names, x[[which("to" == arg_names)]], x[[3]]) - if(length(x) > 3) { - stop("Slicing with step size is not supported yet") - by <- ifelse("by" %in% arg_names, x[[which("by" == arg_names)]], x[[4]]) - } else { - by <- NA - } - return(slice(from, to, by)) - } else if(x[[1]] == "c") { - stop("Custom vector slicing is not yet supported") - # return(eval(y)) - } else { - stop("Unsupported filter '", as.character(x), "' supplied") - } - } else { - stop("Unsupported filter '", as.character(x), "' supplied") - } - }) - return(self$get_item(filters)) + + # update filters for orthogonal_selection + filters <- manage_filters(filters) + + # return orthogonal selection upon `[.ZarrArray` + return(self$get_orthogonal_selection(filters)) }, #' @description #' Assign values for a selection using bracket notation (for S3 method). diff --git a/man/IntArrayDimIndexer.Rd b/man/IntArrayDimIndexer.Rd new file mode 100644 index 0000000..4189593 --- /dev/null +++ b/man/IntArrayDimIndexer.Rd @@ -0,0 +1,109 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/indexing.R +\docType{class} +\name{IntArrayDimIndexer} +\alias{IntArrayDimIndexer} +\title{IntArrayDimIndexer Class} +\description{ +TODO +} +\details{ +The Zarr IntArrayDimIndexer class. +} +\keyword{internal} +\section{Super class}{ +\code{pizzarr::DimIndexer} -> \code{IntArrayDimIndexer} +} +\section{Public fields}{ +\if{html}{\out{