Skip to content

Commit

Permalink
Compatibility with xarray for #18 and R CMD check cleanup (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
dblodgett-usgs committed Jun 12, 2024
1 parent 6920e83 commit b4a3722
Show file tree
Hide file tree
Showing 620 changed files with 624 additions and 3,538 deletions.
2 changes: 0 additions & 2 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@
^vignettes$
^docs$
^index\.md$
^LICENSE\.md$
^LICENSE$
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ tests/testthat/test_data
.ipynb_checkpoints/
*.ipynb
.Renviron
pkgdown/favicon/
6 changes: 2 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
25 changes: 16 additions & 9 deletions R/array-nested.R
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
#' @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,
# 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
Expand All @@ -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)
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
34 changes: 26 additions & 8 deletions R/atomic.R
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# 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
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
Expand All @@ -19,47 +20,64 @@ 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)))
}
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)
Expand Down
6 changes: 5 additions & 1 deletion R/creation.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -678,6 +681,7 @@ zarr_open_group <- function(
#' @export
zarr_open_array <- function(
store = NA,
storage_options = NA,
mode = NA,
shape = NA,
chunks=TRUE,
Expand Down
12 changes: 7 additions & 5 deletions R/indexing.R
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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()

Expand Down Expand Up @@ -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()
Expand Down
14 changes: 9 additions & 5 deletions R/meta.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,38 @@ 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) {
return(charToRaw(jsonlite::toJSON(meta, auto_unbox = auto_unbox)))
},
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
9 changes: 5 additions & 4 deletions R/normalize.R
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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)
}
}
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit b4a3722

Please sign in to comment.