When a table annotating a shape element is attached, .sync_shapes_on_drop() subsets the element with
y <- y[match(instances(t), instances(y), nomatch = 0)]
(R/utils.R, line 45, at 58ec915). For a shape element without an instance_key attribute, instances(y) returns seq_len(nrow(y)), so the table's instance values end up matched against row positions. With ids that start at 0, the last shape goes missing.
A reprex with the example store, on spatialdataR 0.99.44:
library(spatialdataR)
x <- readSpatialData(system.file("extdata", "blobs.zarr", package = "spatialdataR"))
nrow(shape(x, "blobs_circles"))
#> [1] 5
t <- table(x)[, 1:5]
regions(t) <- "blobs_circles"
instances(t) <- 0:4
table(x, "circles") <- t
nrow(shape(x, "blobs_circles"))
#> [1] 4
With a two-column table and instances(t) <- c(4L, 5L), the element ends up with no rows at all, although shape(x, "blobs_circles")[c(4, 5)] on its own returns two.
The same happens when reading two of the example stores in the BiocSpatialData OSN bucket. In merfish.zarr.zip, cells has 2,389 rows in shapes.parquet and 2,389 columns in the table, but 2,388 rows after readSpatialData(); in visium_associated_xenium_io_aligned.zip the spots go from 4,992 to 4,991. Both number their instances from 0. With tables = FALSE every row is there, and xenium_rep1_io_aligned.zip, whose ids start at 1, keeps all of them.
In these stores the ids sit in a column named after the table's instance key (cell_id, spot_id), which is what .sync_tables_on_crop() already looks for with if (ik %in% names(e)) e[[ik]], so the same lookup would probably fix it here. Something else I noticed along the way: [ on a shape element keeps rows in their stored order, so circles[c(3, 1)] returns rows 1 and 3.
This may fit with #195. Happy to put together a PR with a test if that helps.
When a table annotating a shape element is attached,
.sync_shapes_on_drop()subsets the element with(
R/utils.R, line 45, at 58ec915). For a shape element without aninstance_keyattribute,instances(y)returnsseq_len(nrow(y)), so the table's instance values end up matched against row positions. With ids that start at 0, the last shape goes missing.A reprex with the example store, on spatialdataR 0.99.44:
With a two-column table and
instances(t) <- c(4L, 5L), the element ends up with no rows at all, althoughshape(x, "blobs_circles")[c(4, 5)]on its own returns two.The same happens when reading two of the example stores in the BiocSpatialData OSN bucket. In
merfish.zarr.zip,cellshas 2,389 rows inshapes.parquetand 2,389 columns in the table, but 2,388 rows afterreadSpatialData(); invisium_associated_xenium_io_aligned.zipthe spots go from 4,992 to 4,991. Both number their instances from 0. Withtables = FALSEevery row is there, andxenium_rep1_io_aligned.zip, whose ids start at 1, keeps all of them.In these stores the ids sit in a column named after the table's instance key (
cell_id,spot_id), which is what.sync_tables_on_crop()already looks for withif (ik %in% names(e)) e[[ik]], so the same lookup would probably fix it here. Something else I noticed along the way:[on a shape element keeps rows in their stored order, socircles[c(3, 1)]returns rows 1 and 3.This may fit with #195. Happy to put together a PR with a test if that helps.