You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Document how to perform on-the-fly normalization for channels. #460
normalization of channels: see differences between the two notebooks when plotting all channels but DAPI. I guess it is intentional that no normalization is performed by default, and it should be possible to normalize channels using the “norm” argument, but the documentation isn’t very clear on how to do this properly.
import spatialdata as sd
import spatialdata_plot
from spatialdata.datasets import blobs
from matplotlib.colors import Normalize
sdata_blobs = blobs()
# making the first (red) channel have a different range (0-0.05) than the other two (0-1)
img = sdata_blobs.images['blobs_image'].values.copy()
img[0] /= 20
image = sd.models.Image2DModel.parse(
img, transformations=None, dims=("c", "x", "y"), c_coords=[0, 1, 2]
)
sdata = sd.SpatialData(images={"image": image})
fig, ax = plt.subplots(1, 3)
sdata_blobs.pl.render_images(channel=[0, 1, 2]).pl.show(ax=ax[0])
sdata.pl.render_images(channel=[0, 1, 2]).pl.show(ax=ax[1])
# global normalization
sdata.pl.render_images(channel=[0, 1, 2], norm=Normalize(vmin=img.min(), vmax=img.max())).pl.show(ax=ax[2])
# TODO: what about channel-wise normalization?
It would be nice to have the option to normalize so that the final plot for sdata looks the same as for sdata_blobs.
I would also be very much interested in normalization per channel.
Protein data is super noisy and has vastly different ranges.
This could maybe be done by supplying a dictionary of channel names and norms?
I would also like to have an option to specify percentiles a la ("p20","p98") per channel similar to scanpy.pl.umap()
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
# pick channels and compute per-channel percentiles from the data
channels = [0, 1, 2]
arr = sdata.images["image"] # xarray DataArray with dims ("c", "x", "y")
norms = []
for c in channels:
a = arr.sel(c=c).values
lo = np.nanpercentile(a, 2)
hi = np.nanpercentile(a, 98)
norms.append(Normalize(vmin=lo, vmax=hi, clip=True))
sdata.pl.render_images(channel=channels, norm=norms, cmap=[plt.cm.gray]*len(channels)).pl.show()
I think this should work, it's just less elegant since the order of the normalisation objects is only implicitly aligned with the order of the channels, not by name or anything like that
Activity
MeyerBender commentedon May 14, 2025
Example code snippet:
It would be nice to have the option to normalize so that the final plot for
sdatalooks the same as forsdata_blobs.pakiessling commentedon Jul 26, 2025
I would also be very much interested in normalization per channel.
Protein data is super noisy and has vastly different ranges.
This could maybe be done by supplying a dictionary of channel names and norms?
I would also like to have an option to specify percentiles a la ("p20","p98") per channel similar to scanpy.pl.umap()
I will try to see if I can get this to work
timtreis commentedon Jul 28, 2025
Would something like this help for your usecase?
I think this should work, it's just less elegant since the order of the normalisation objects is only implicitly aligned with the order of the channels, not by name or anything like that
pakiessling commentedon Aug 4, 2025
Thanks @timtreis ,
however this does not seem to be currently supported:
Add per-channel norm support for render_images (#460)