scverse / spatialdata

An open and interoperable data framework for spatial omics data
https://spatialdata.scverse.org/
BSD 3-Clause "New" or "Revised" License
235 stars 43 forks source link

Question - distance measurements #334

Open wdg118 opened 1 year ago

wdg118 commented 1 year ago

Hi @giovp and @LucaMarconato,

I'm new to spatialdata and thinking about using it. Just wanted to know - does spatialdata have a way to take distance measurements from one point to another? If not how can this be done? We think there are morphological differences between certain parts of our tissue.

Thanks,

wdg118

LucaMarconato commented 1 year ago

Hi @wdg118, I can think of two ways to achieve this.

First way. Interactive/manual way.

If you want to interactively annotate the points, you can use napari, add a points layer, add the points, save them to the object (Shift+E shortcut), and then compute the distance with numpy.linalg.dist(a-b).

An advantage of this way is that no matter how many elements/spatialdata objects you have, the points saved from napari will be with respect to the same coordinate system (the one you select from using the napari widget). So you can simply compute the distance between the points.

A disadvantage of this method is that currently the saving back of the annotations with napari is broken. We are working on it to re-enable it. Therefore in the meanwhile you would have to manually note down the coordinates that are displayed in the bottom left of the napari interface. You can also use this old branch of napari-spatialdata, for which saving annotations works: https://github.com/scverse/napari-spatialdata/tree/spatialdata

Second way. Automatic way.

Alternatively you can select points directly in the images using pixel coordinates and then transform the points to a common coordinate system. I write the "pseudocode" for this, if you need I can write you a small runnable example from this.

my_image1, my_image2 # images

# point of interest, in pixels, from image1
yx_image1 = np.array([[10, 123]))

# point of interest, in pixels, from image2
yx_image2 = np.array([[23, 343]))

# create points elements from a 2D numpy tensor with columns x, y
point1 = spaitaldata.models.PointsModel.parse(np.fliplr(yx_image1))
point2 = spaitaldata.models.PointsModel.parse(np.fliplr(yx_image2))

t1 = spaitaldata.transformations.get_transformation(my_image1, 'my_common_coordinate_system')
t2 = spaitaldata.transformations.get_transformation(my_image2, 'my_common_coordinate_system')

aligned_point1 = spatialdata.transform(point1, t1)
aligned_point2 = spatialdata.transform(point2, t1)

xy1 = aligned_point1.compute().values.ravel()
xy2 = aligned_point2.compute().values.ravel()

# compute Euclidean distance