spatialdata-io icon indicating copy to clipboard operation
spatialdata-io copied to clipboard

Load Visium HD generated without microscopy image

Open cavenel opened this issue 10 months ago • 8 comments

Hi,

SpaceRanger can be run on Visium HD data without a full resolution microscopy image, and only the CytAssist image. This will create a metadata_json with "microscope_colrow_to_spot_colrow": null, which will then fail when reading with spatialdata_io.visium_hd:

https://github.com/scverse/spatialdata-io/blob/625c77c4ff371e3d23e44aac0706abbaa2cf705a/src/spatialdata_io/readers/visium_hd.py#L459

Traceback (most recent call last):
  File "read_data.py", line 57, in <module>
    spatialdata = spatialdata_io.visium_hd(
  File "spatialdata_io/readers/visium_hd.py", line 110, in visium_hd
    transform_matrices = _get_transform_matrices(metadata, hd_layout)
  File "spatialdata_io/readers/visium_hd.py", line 426, in _get_transform_matrices
    transform_matrices[key.value] = _get_affine(data)
  File "spatialdata_io/readers/visium_hd.py", line 398, in _get_affine
    matrix = np.array(coefficients).reshape(3, 3)
ValueError: cannot reshape array of size 1 into shape (3,3)

I am trying to build a subsample test dataset and would like to run without the microscopy image to win some space. Do you think it is possible to read without it?

Thanks!

cavenel avatar Jan 31 '25 15:01 cavenel

I am having the issue, commenting to follow possible solutions.

Thanks!

ishahakm avatar Jan 31 '25 20:01 ishahakm

Hi, thanks for reporting. Just to confirm, is SPOT_COLROW_TO_MICROSCOPE_COLROW also null?

LucaMarconato avatar Feb 03 '25 13:02 LucaMarconato

As a temporary workaround I would suggest to call visium_hd() with load_all_images=False, and then manually add the CytAssist image. You can use the code in visium_hd.py as a starting point to build the code to add the CytAssist image.

Last note, I am now working on a PR were the handling of the transformation to align the CytAssist image is being improved. In fact the CytAssist image requires a projective transformation instead that an affine transformation. The code is being developed here https://github.com/scverse/spatialdata-io/pull/247/files.

LucaMarconato avatar Feb 03 '25 13:02 LucaMarconato

Hi Luca,

Just to confirm, is SPOT_COLROW_TO_MICROSCOPE_COLROW also null?

Yes, sorry for taking so long, here is the transform_matrices I get in feature_slice.h5/metadata_json:

    "transform_matrices": {
        "spot_colrow_to_microscope_colrow": null,
        "microscope_colrow_to_spot_colrow": null,
        "spot_colrow_to_cytassist_colrow": [
            [ 0.43533954061653085, -0.0015909290933427778, 361.1081924084045 ],
            [ 0.0016526601757832409, 0.43588308733401127, 813.0159476547801 ],
            [ -1.5622128737399484e-7, 2.0118016811628844e-7, 1 ]
        ],
        "cytassist_colrow_to_spot_colrow": [
            [ 2.296163825673191, 0.008766752195787693, -836.291077906726 ],
            [ -0.009378545054697946, 2.2944586631833555, -1862.0448149506128 ],
            [ 3.6059644613905333e-7, -4.6023002628098706e-7, 1 ]
        ]
    }

Thanks for the workaround, I will use that for now and wait for the big PR on CytAssist projection!

cavenel avatar Feb 09 '25 09:02 cavenel

Thanks for the details. The matrices are very close to affine matrices, in the sense that the first two elements in the last rows are very close to zero. But they are not zero in machine precision. So the approach in the PR may be beneficial in the scenario reported by you and the other user (in the case above the difference in practice would be very small).

I would try replacing the code (current codebase)

# replace
set_transformation(image, Sequence([affine0, affine1]), "global")
# with
set_transformation(image, affine0, "global")

or the code (incoming PR on projective transformations)

# replace
projective = projective1 @ projective0
# with
projective = projective0

I haven't try the code above in my machine, but I think it should fix your problems. Please double check if the shapes and CytAssist images are aligned (you can for instance plot the data interactively and explore the various elements and coordinate system).

# show the data interactively
from napari_spatialdata import Interactive
Interactive(sdata)

Please let me know if it helps!

LucaMarconato avatar Feb 10 '25 14:02 LucaMarconato

Hi Luca,

For the nf-core pipeline spatialvi, the goal is to work for any Visium or Visium HD input, so the projective transformation will be a plus!

I would try replacing the code (current codebase)

# replace
set_transformation(image, Sequence([affine0, affine1]), "global")
# with
set_transformation(image, affine0, "global")

Yes, but note that right now the line before that fails (transform_matrices = _get_transform_matrices(metadata, hd_layout)) as the _get_affine functions expects a 3 value array. Do you think there is a way to add a check in the code to skip "spot_colrow_to_microscope_colrow" key and affine1 if the value is null?

cavenel avatar Feb 10 '25 20:02 cavenel

Do you think there is a way to add a check in the code to skip "spot_colrow_to_microscope_colrow" key and affine1 if the value is null?

Yes, I'd add this check. Could you make a PR to try this approach out on your data?

LucaMarconato avatar Feb 10 '25 21:02 LucaMarconato

Hi, I appreciate the helpful discussions! I'm following up on this ValueError issue. I'm still experiencing it with the latest development version downloaded from Github (spatialdata-io-0.1.8.dev40+g4cf0f63). Is there any update or timeframe for a possible fix? Thanks!

fy711 avatar Mar 03 '25 16:03 fy711