scverse / spatialdata-plot

Static plotting for spatialdata
BSD 3-Clause "New" or "Revised" License
33 stars 13 forks source link

Unknown normalization when rendering crops from spatial samples. #290

Closed rushin682 closed 1 month ago

rushin682 commented 5 months ago

Hi developers,

Thanks for the amazing framework. I am using the framework to extract non-linear features from image patches of visium samples. When performing some QC on the data, I noticed that the image renders of cropped patches have some sort of normalization which doesn't exist in the original image when loaded in QuPath or Openslide (https://openslide.org/api/python/).

Please find attached images. I tried to find the normalization function in the plot code, but without success.

Can you please help? Knowing what kind of normalization is used is crucial to minimise batch-effect in SOTA Histopathology analysis methods. If possible it would be great also to disable normalization by default since for different tissue images, the rendered normalizations shows vast differences in how the different stains are represented.

spatialdata-render openslide-patch
Bioin-Mixologist commented 5 months ago

Not sure if it's an issue with matplotlib, the RGBA settings don't work when I'm doing gene expression plotting, too. The issue: scverse/spatialdata#554

melonora commented 5 months ago

This is indeed matplotlib specific. See this issue also on stackoverflow: https://stackoverflow.com/questions/49643907/clipping-input-data-to-the-valid-range-for-imshow-with-rgb-data-0-1-for-floa

LucaMarconato commented 3 months ago

Hi, this issue appears to be plotting related. No normalization is performed when a bounding box query is applied and it seems that the problem is due to clipping the data to [0, 1]. I will therefore move the issue to spatialdata-plot.

(interpolation is performed, as implemented in dask_image.ndinterp.affine_transform, when rasterize() or transform() is called, but this doesn't seem to be the case of this issue).

In this particular case, normalizing the image to [0, 1] by dividing by 255, or, if the data appears to be integers, converting the dtype to int, should fix the problem. Please let me know if this fixes the issue.

LucaMarconato commented 3 months ago

(no action needed form the spatialdata-plot developers.)

LucaMarconato commented 3 months ago

I actually dug more into this and it looks like that the behavior is due to a side effect of the normalization strategy used in spatialdata-plot.

I could reproduce this on the Visium HD notebook. The full resolution image has unit values in {0, ... 255}, and we have that in spatialdata_plot.pl.render._render_images(), in the piece of code highlighted in the screenshot, the problem arises.

image

Precisely, for the Visium_HD_Mouse_Small_Intestine_hires_image image and for c=1, we have that

layers[c].data.compute().min() == 0

but

render_params.cmap_params.norm(layers[c]).data.min() == -0.15

This leads to the warning

_log.warning(
    'Clipping input data to the valid range for imshow with '
    'RGB data ([0..1] for floats or [0..255] for integers).'
)

in matploptlib.image._ImageBase._normalize_image_array().

LucaMarconato commented 3 months ago

Can you please help? Knowing what kind of normalization is used is crucial to minimise batch-effect in SOTA Histopathology analysis methods. If possible it would be great also to disable normalization by default since for different tissue images, the rendered normalizations shows vast differences in how the different stains are represented.

On the positive side, @rushin682 I confirm that the downstream analysis would not be affected as this behavior only affects plotting, and the normalized data is never exposed outside the spatialdata-plot library.

timtreis commented 1 month ago

hey @rushin682, will merge the linked PR later this week. I think that should fix your issue. Would be happy for you to test with that branch 👍