Skip to content

Commit 05becac

Browse files
dimension name setters (#170)
1 parent 9a317d2 commit 05becac

6 files changed

Lines changed: 141 additions & 10 deletions

File tree

‎R/creation.R‎

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ init_array_metadata <- function(
2727
filters=NA,
2828
object_codec=NA,
2929
dimension_separator=NA,
30-
zarr_format=2L
30+
zarr_format=2L,
31+
dimension_names=NULL
3132
) {
3233
# Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0e6cdc04c6413e14f57f61d389972ea937c/zarr/storage.py#L358
3334
if(is_na(compressor)) {
@@ -59,7 +60,11 @@ init_array_metadata <- function(
5960
# dtype = dtype.base
6061

6162
shape <- normalize_shape(shape)
62-
63+
64+
if (!is.null(dimension_names) && length(dimension_names) != length(shape)) {
65+
stop("DimensionNamesLengthError(length must match length(shape))")
66+
}
67+
6368
dtype_itemsize <- dtype$num_bytes
6469
chunks <- normalize_chunks(chunks, shape, dtype_itemsize)
6570
order <- normalize_order(order)
@@ -117,13 +122,17 @@ init_array_metadata <- function(
117122
compressor = compressor,
118123
fill_value = fill_value,
119124
order = order,
120-
filters = filters
125+
filters = filters,
126+
dimension_names = dimension_names
121127
)
122128
key <- paste0(path_to_prefix(path), ZARR_JSON)
123129
meta3 <- Metadata3$new()
124130
encoded_meta <- meta3$encode_array_metadata(v3_meta)
125131
store$set_item(key, encoded_meta)
126132
} else {
133+
if (!is.null(dimension_names)) {
134+
stop("DimensionNamesV2Error(dimension_names is only supported for zarr_format = 3L)")
135+
}
127136
zarray_meta <- create_zarray_meta(
128137
shape=shape,
129138
chunks=chunks,
@@ -250,7 +259,8 @@ init_array <- function(
250259
filters=NA,
251260
object_codec=NA,
252261
dimension_separator=NA,
253-
zarr_format=2L
262+
zarr_format=2L,
263+
dimension_names=NULL
254264
) {
255265
if(is_na(compressor)) {
256266
compressor <- "default"
@@ -279,7 +289,8 @@ init_array <- function(
279289
filters=filters,
280290
object_codec=object_codec,
281291
dimension_separator=dimension_separator,
282-
zarr_format=zarr_format
292+
zarr_format=zarr_format,
293+
dimension_names=dimension_names
283294
)
284295

285296
}
@@ -342,6 +353,10 @@ init_group <- function(
342353
#' @param zarr_format : int, optional
343354
#' Zarr format version. Use \code{2L} (default) for Zarr V2 or \code{3L}
344355
#' for Zarr V3.
356+
#' @param dimension_names : character vector, optional
357+
#' Named dimensions for V3 arrays. Length must equal \code{length(shape)}.
358+
#' V3 only -- passing a non-NULL value with \code{zarr_format = 2L} is an
359+
#' error. Default \code{NULL}.
345360
#' @returns ZarrArray
346361
#' @export
347362
zarr_create <- function(
@@ -363,7 +378,8 @@ zarr_create <- function(
363378
object_codec=NA,
364379
dimension_separator=NA,
365380
write_empty_chunks=TRUE,
366-
zarr_format=2L
381+
zarr_format=2L,
382+
dimension_names=NULL
367383
) {
368384
# Reference: https://github.com/zarr-developers/zarr-python/blob/5dd4a0e6cdc04c6413e14f57f61d389972ea937c/zarr/creation.py#L18
369385
if(is_na(compressor)) {
@@ -383,7 +399,8 @@ zarr_create <- function(
383399
init_array(store, shape=shape, chunks=chunks, dtype=dtype, compressor=compressor,
384400
fill_value=fill_value, order=order, overwrite=overwrite, path=path,
385401
chunk_store=chunk_store, filters=filters, object_codec=object_codec,
386-
dimension_separator=dimension_separator, zarr_format=zarr_format)
402+
dimension_separator=dimension_separator, zarr_format=zarr_format,
403+
dimension_names=dimension_names)
387404

388405

389406
# instantiate array

‎R/zarr-array.R‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,14 @@ ZarrArray <- R6::R6Class("ZarrArray",
246246
# V3 encodes NaN/Infinity/-Infinity as JSON strings; decode back to numeric.
247247
private$fill_value <- decode_fill_value_v3(meta$fill_value)
248248

249-
private$dimension_names <- meta$dimension_names # NULL if absent
249+
# JSON arrays of strings come back as lists under simplifyVector=FALSE;
250+
# coerce to a character vector so the public getter returns the type
251+
# users expect. NULL stays NULL when the field is absent from zarr.json.
252+
if (is.null(meta$dimension_names)) {
253+
private$dimension_names <- NULL
254+
} else {
255+
private$dimension_names <- as.character(unlist(meta$dimension_names))
256+
}
250257
},
251258
# method_description
252259
# Load or reload metadata from store.
@@ -1172,6 +1179,21 @@ ZarrArray <- R6::R6Class("ZarrArray",
11721179
private$flush_metadata_nosync()
11731180
},
11741181
#' @description
1182+
#' Set dimension names of the array (V3 only).
1183+
#' @param names Character vector of length equal to the number of array
1184+
#' dimensions, or `NULL` to clear.
1185+
#' @return `NULL` (called for side effects).
1186+
set_dimension_names = function(names) {
1187+
if (is.null(private$zarr_format) || private$zarr_format != 3L) {
1188+
stop("DimensionNamesV2Error(set_dimension_names is only supported for V3 arrays)")
1189+
}
1190+
if (!is.null(names) && length(names) != length(private$shape)) {
1191+
stop("DimensionNamesLengthError(length must match length(shape))")
1192+
}
1193+
private$dimension_names <- names
1194+
private$flush_metadata_nosync()
1195+
},
1196+
#' @description
11751197
#' get the storage order metadata of an array.
11761198
#' @return `character(1)`, `"C"` or `"F"`.
11771199
get_order = function() {

‎man/ZarrArray.Rd‎

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎man/init_array.Rd‎

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎man/zarr_create.Rd‎

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tests/testthat/test-v3.R‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,3 +841,66 @@ test_that("V3 vlen-utf8 string array loads correctly via load_metadata_v3_nosync
841841
skip("fixture not found")
842842
}
843843
})
844+
845+
# --- dimension_names threading (PR 0B) ---
846+
847+
test_that("V3 zarr_create with dimension_names round-trips on reopen", {
848+
store <- MemoryStore$new()
849+
z <- zarr_create(shape = c(2L, 3L), dtype = "<f8", zarr_format = 3L,
850+
compressor = NA, store = store,
851+
dimension_names = c("x", "y"))
852+
expect_equal(z$get_dimension_names(), c("x", "y"))
853+
854+
# Re-open from store and confirm dimension_names persisted in zarr.json.
855+
z2 <- ZarrArray$new(store)
856+
expect_equal(z2$get_dimension_names(), c("x", "y"))
857+
})
858+
859+
test_that("V3 set_dimension_names attaches names post-creation and round-trips", {
860+
store <- MemoryStore$new()
861+
z <- zarr_create(shape = c(2L, 3L), dtype = "<f8", zarr_format = 3L,
862+
compressor = NA, store = store)
863+
expect_null(z$get_dimension_names())
864+
865+
z$set_dimension_names(c("a", "b"))
866+
expect_equal(z$get_dimension_names(), c("a", "b"))
867+
868+
z2 <- ZarrArray$new(store)
869+
expect_equal(z2$get_dimension_names(), c("a", "b"))
870+
})
871+
872+
test_that("set_dimension_names errors on V2 arrays", {
873+
store <- MemoryStore$new()
874+
z <- zarr_create(shape = c(2L, 3L), dtype = "<f8", zarr_format = 2L,
875+
compressor = NA, store = store)
876+
expect_error(z$set_dimension_names(c("x", "y")), "DimensionNamesV2Error")
877+
})
878+
879+
test_that("zarr_create errors when dimension_names length != length(shape)", {
880+
store <- MemoryStore$new()
881+
expect_error(
882+
zarr_create(shape = c(4L, 5L), dtype = "<f8", zarr_format = 3L,
883+
compressor = NA, store = store,
884+
dimension_names = c("x")),
885+
"DimensionNamesLengthError"
886+
)
887+
})
888+
889+
test_that("zarr_create errors when dimension_names is passed with zarr_format = 2L", {
890+
store <- MemoryStore$new()
891+
expect_error(
892+
zarr_create(shape = c(4L, 5L), dtype = "<f8", zarr_format = 2L,
893+
compressor = NA, store = store,
894+
dimension_names = c("x", "y")),
895+
"DimensionNamesV2Error"
896+
)
897+
})
898+
899+
test_that("V3 group create_dataset threads dimension_names through ...", {
900+
store <- MemoryStore$new()
901+
g <- zarr_create_group(store = store, zarr_format = 3L)
902+
a <- g$create_dataset("data", shape = c(2L, 3L, 4L), dtype = "<f8",
903+
compressor = NA,
904+
dimension_names = c("x", "y", "t"))
905+
expect_equal(a$get_dimension_names(), c("x", "y", "t"))
906+
})

0 commit comments

Comments
 (0)