Hi, I am attempting to use Spatiadata's pl.render_images to recreate a Xenium Explorer-style plot for Xenium with the multi-stain segmentation panel. See the example here:

I've processed the data so far as:
importspatialdataassdimportspatialdata_plotfromspatialdata_ioimportxeniumfromspatialdata.modelsimportget_channel_namesimportscanpyasscfrompathlibimportPathimportshutilimportosimportnumpyasnpimportpandasaspdimportmatplotlibimportmatplotlib.patchesaspatchesfrommatplotlibimportpyplotaspltpath=Path().resolve()
# Set root directoryroot_dir= ... # Skipping# Set figure output directoryfigdir=os.path.join(
root_dir,
'figures'
)
# Set directory to raw Xenium output bundlesraw_data_dir=os.path.join(
root_dir,
'data/raw/xenium'
)
# Set path to reference NicheCompass Anndata fileadata_file=os.path.join(
root_dir,
'output/nichecompass',
'FB_SPI_mouse_filt_cells_NicheCompass_annotated__30012026.h5ad'
)
# Mapping Xenium slide names to Xenium output directoriesxenium_output_dir= {
'7dpi-C': 'output-XETG00155__0043039__7dpi-C__20240725__115033',
'Sham-A': 'output-XETG00155__0043039__Sham-A__20240725__115033',
'1dpi-C': 'output-XETG00155__0043039__1dpi-C__20240725__115033',
'3dpi-A': 'output-XETG00155__0043042__3dpi-A__20240725__115033',
'7dpi-B': 'output-XETG00335__0027406__7dpi-B__20240725__114550',
'14dpi-B': 'output-XETG00335__0027281__14dpi-B__20240725__114550',
'28dpi-A': 'output-XETG00155__0043039__28dpi-A__20240725__115033',
}
slide_xenium_data_dir= {}
forslideinxenium_output_dir.keys():
slide_xenium_data_dir[slide] =os.path.join(
raw_data_dir,
xenium_output_dir[slide]
)
# Load NicheCompass resultsadata_nc=sc.read_h5ad(adata_file)
# Load Xenium data as SpatialDataslide='7dpi-C'sdata=xenium(
path=slide_xenium_data_dir[slide],
n_jobs=8,
cell_boundaries=True,
nucleus_boundaries=False,
morphology_focus=True,
cells_as_circles=False,
)
# Subset NicheCompass to slideadata_nc_subset=adata_nc[adata_nc.obs['regionName']==slide,:].copy()
# Fix 8-digit hex-codes to 6-digitadata_nc_subset.uns['Niches_colors'] =np.array(
[c[:-2] forcinadata_nc_subset.uns['Niches_colors']]
)
# Copy over to Spatialdata objectsdata.tables['table'].obs_names=sdata.tables['table'].obs['cell_id']
sdata.tables['table'].obs['Niches'] =adata_nc_subset.obs['Niches']
sdata.tables['table'].obs['cell_type_coarse'] =adata_nc_subset.obs['cell_type_coarse']
sdata.tables['table'].obs['cell_type_granular'] =adata_nc_subset.obs['cell_type_granular']
sdata.tables['table'].uns['Niches_colors'] =adata_nc_subset.uns['Niches_colors']
sdata.tables['table'].uns['cell_type_coarse_colors'] =adata_nc_subset.uns['cell_type_coarse_colors']
sdata.tables['table'].uns['cell_type_granular_colors'] =adata_nc_subset.uns['cell_type_granular_colors']
# Reset index of .obssdata.tables['table'].obs.reset_index(drop=True, inplace=True)
# Reset table annotation to 'cell_boundaries'sdata["table"].obs["region"] ="cell_boundaries"sdata.set_table_annotates_spatialelement("table", region="cell_boundaries")
# Replace NA valuessdata.tables['table'].obs['Niches'] = (
sdata.tables['table'].obs['Niches'].cat.add_categories(['Unknown'])
.fillna('Unknown')
)
# Process colour paletteniches_g=sdata.tables['table'].obs['Niches'].cat.categories.tolist()
niches_p=sdata.tables['table'].uns['Niches_colors'].tolist()
# Add a separate value for cells lacking 'Niche' annotationniches_p.append('#ffffff')INFO reading [/lustre/scratch124/cellgen/bayraktar/kr23/projects/FB_SPI/data/raw/xenium/output-XETG00155__0043039__7dpi-](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/lustre/scratch124/cellgen/bayraktar/kr23/projects/FB_SPI/data/raw/xenium/output-XETG00155__0043039__7dpi-)
C__20240725__115033/cell_feature_matrix.h5 <timed exec>:3: DeprecationWarning: `cell_boundaries` is being deprecated as an argument to `xenium.xenium` in SpatialData version 0.1, switch to `cells_boundaries` instead.
[/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/spatialdata_io/_utils.py:48](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/spatialdata_io/_utils.py:48): UserWarning: The "cell_id" column in the cells metadata table does not match the "cell_id" column in the annotation table. This could be due to trying to read a new version that is not supported yet. Please report this issue.
return f(*args, **kwargs)
[/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/spatialdata_io/_utils.py:48](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/spatialdata_io/_utils.py:48): UserWarning: The cell_id column in the cell_labels_table does not match the cell_id column derived from the cell labels data. This could be due to trying to read a new version that is not supported yet. Please report this issue.
return f(*args, **kwargs)
CPU times: user 23.3 s, sys: 4.31 s, total: 27.6 s
Wall time: 25.1 s
[/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/spatialdata/_core/spatialdata.py:511](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/spatialdata/_core/spatialdata.py:511): UserWarning: Converting `region_key: region` to categorical dtype.
convert_region_column_to_categorical(table)
# Bounding box to region of interestbb_xmin=11500bb_ymin=4000bb_w=4000bb_h=4000bb_xmax=bb_xmin+bb_wbb_ymax=bb_ymin+bb_h# Highlight region of interestf, ax=plt.subplots(figsize=(12,24))
sdata.pl.render_shapes(
'cell_boundaries',
method='matplotlib',
color='Niches',
groups=niches_g,
palette=niches_p,
alpha_fill=1
).pl.show(
ax=ax,
title=f'{slide} (zoom)',
)
rect=patches.Rectangle((bb_xmin, bb_ymin), bb_w, bb_h, linewidth=1, edgecolor="red", facecolor="none")
ax.add_patch(rect)
# Query the bounding boxsdata_xenium_subset=sdata.query.bounding_box(
axes=["x", "y"],
min_coordinate=[bb_xmin, bb_ymin],
max_coordinate=[bb_xmax, bb_ymax],
target_coordinate_system="global",
)
sdata_xenium_subset.pl.render_shapes(
'cell_boundaries',
method='matplotlib',
color='Niches',
groups=niches_g,
palette=niches_p,
fill_alpha=0.8
).pl.show(
title=f'{slide} (zoom) (niches)',
figsize= (12,12)
)The full tissue slide:

And the queried bounding box:

Now I am aware of this issue: #370,
but don't even seem to get a similar result:
sdata_xenium_subset.pl.render_images(
"morphology_focus",
palette= ["#0F73E6", "#F300A5", "#A4A400", "#008A00"],
channel= ['DAPI', 'ATP1A1/CD45/E-Cadherin', '18S', 'AlphaSMA/Vimentin']
).pl.show(
title="Morphology image", coordinate_systems="global",
colorbar=False,
figsize= (6,6)
)
[/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/tifffile/tifffile.py:8797](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/software/conda/users/kr23/spatialdata/lib/python3.10/site-packages/tifffile/tifffile.py:8797): UserWarning: <tifffile.TiffPage0 @16>readingarrayfromclosedfilewarnings.warn(
INFOYourimagehas4channels. Samplingcategoricalcolorsandusingmultichannelstrategy'stack'torender.

Individual channels look fine:
sdata_xenium_subset.pl.render_images(
'morphology_focus',
palette= ['#0f73e6'],
channel= ['DAPI'],
alpha=1# norm = matplotlib.colors.Normalize(0, 5000, clip=True)
).pl.show(
title=f'{slide} (zoom) (DAPI)',
colorbar=False,
figsize= (6,6)
)
sdata_xenium_subset.pl.render_images(
'morphology_focus',
palette= ['#a4a400'],
channel= ['18S'],
# norm = matplotlib.colors.Normalize(0, 5000, clip=True)
).pl.show(
title=f'{slide} (zoom) (18S)',
colorbar=False,
figsize= (6,6)
)
sdata_xenium_subset.pl.render_images(
'morphology_focus',
palette= ['#f300a5'],
channel= ['ATP1A1/CD45/E-Cadherin'],
# norm = matplotlib.colors.Normalize(0, 8000, clip=True)
).pl.show(
title=f'{slide} (zoom) (ATP1A1/CD45/E-Cadherin)',
colorbar=False,
figsize= (6,6)
)
However none of the options to do normalisation clipping seem to affect any of the combined plots, neither when I do this for instance:
###sdata_xenium_subset.pl.render_images(
'morphology_focus',
palette= [
'#0f73e6',
'#a4a400',
'#f300a5'
],
channel= [
'DAPI',
'18S',
'ATP1A1/CD45/E-Cadherin'
],
# norm = matplotlib.colors.Normalize(0, 8000, clip=True)
).pl.show(
title=f'{slide} (zoom) (DAPI - 18S - E-Cadherin)',
colorbar=False,
figsize= (6,6),
)
Is exactly the same look regardless of setting e.g. norm = matplotlib.colors.Normalize(0, 10000, clip=True), norm = matplotlib.colors.Normalize(0, 1.5, clip=True), or norm = matplotlib.colors.Normalize(0, 2000, clip=True).
This is what is found in the queried object:
sdata_xenium_subsetSpatialDataobject
├── Images
│ └── 'morphology_focus': DataTree[cyx] (4, 4000, 4000), (4, 2000, 2000), (4, 1000, 1000), (4, 500, 500), (4, 250, 250)
├── Labels
│ ├── 'cell_labels': DataTree[yx] (4000, 4000), (2000, 2000), (1000, 1000), (500, 500), (250, 250)
│ └── 'nucleus_labels': DataTree[yx] (4000, 4000), (2000, 2000), (1000, 1000), (500, 500), (250, 250)
├── Points
│ └── 'transcripts': DataFramewithshape: (<Delayed>, 13) (3Dpoints)
├── Shapes
│ └── 'cell_boundaries': GeoDataFrameshape: (4500, 1) (2Dshapes)
└── Tables
└── 'table': AnnData (4500, 474)
withcoordinatesystems:
▸ 'global', withelements:
morphology_focus (Images), cell_labels (Labels), nucleus_labels (Labels), transcripts (Points), cell_boundaries (Shapes)
and images:
sdata_xenium_subset.images
{'morphology_focus': <xarray.DataTree>Group: [/](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/)
├── Group: [/scale0](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/scale0)
│ Dimensions: (c: 4, y: 4000, x: 4000)
│ Coordinates:
│ *c (c) <U22352B'DAPI' ... 'AlphaSMA/Vimentin'
│ *y (y) float6432kB0.51.52.53.5 ... 3.998e+033.998e+034e+03
│ *x (x) float6432kB0.51.52.53.5 ... 3.998e+033.998e+034e+03
│ Datavariables:
│ image (c, y, x) uint16128MBdask.array<chunksize=(2, 4000, 4000), meta=np.ndarray>
├── Group: [/scale1](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/scale1)
│ Dimensions: (c: 4, y: 2000, x: 2000)
│ Coordinates:
│ *c (c) <U22352B'DAPI' ... 'AlphaSMA/Vimentin'
│ *y (y) float6416kB1.03.05.07.0 ... 3.995e+033.997e+033.999e+03
│ *x (x) float6416kB1.03.05.07.0 ... 3.995e+033.997e+033.999e+03
│ Datavariables:
│ image (c, y, x) uint1632MBdask.array<chunksize=(2, 2000, 2000), meta=np.ndarray>
├── Group: [/scale2](https://vscode-remote+ssh-002dremote-002bfarm22.vscode-resource.vscode-cdn.net/scale2)
│ Dimensions: (c: 4, y: 1000, x: 1000)
│ Coordinates:
│ *c (c) <U22352B'DAPI' ... 'AlphaSMA/Vimentin'
│ *y (y) float648kB2.06.010.014.0 ... 3.99e+033.994e+033.998e+03
│ *x (x) float648kB2.06.010.014.0 ... 3.99e+033.994e+033.998e+03
│ Datavariables:
...
*y (y) float642kB8.024.040.056.0 ... 3.96e+033.976e+033.992e+03*x (x) float642kB8.024.040.056.0 ... 3.96e+033.976e+033.992e+03Datavariables:
image (c, y, x) uint16500kBdask.array<chunksize=(4, 250, 250), meta=np.ndarray>}
Outputistruncated. Viewasa [scrollableelement](command:cellOutput.enableScrolling?a43a3130-bed1-4d79-94bd-0ac7729b722a) oropenina [texteditor](command:workbench.action.openLargeOutput?a43a3130-bed1-4d79-94bd-0ac7729b722a). Adjustcelloutput [settings](command:workbench.action.openSettings?%5B%22%40tag%3AnotebookOutputLayout%22%5D)...Are you familiar with any ways to improve this plotting? I would love to have the custom control that Spatialdata offers to generate high-quality figures for publications, but so far the different scales of stains doesn't seem to work well.
Finally, I have also tried this issue: #460, but got exactly the same issue in the end as the author mentioned in their last comment.
All my code was run with:
print(sd.__version__)
print(spatialdata_io.__version__)
print(spatialdata_plot.__version__)
0.5.00.3.00.2.12
I hope you can help me out!
Best,
Koen
Hi, I am attempting to use Spatiadata's

pl.render_imagesto recreate a Xenium Explorer-style plot for Xenium with the multi-stain segmentation panel. See the example here:I've processed the data so far as:
The full tissue slide:
And the queried bounding box:
Now I am aware of this issue: #370,
but don't even seem to get a similar result:
Individual channels look fine:
However none of the options to do normalisation clipping seem to affect any of the combined plots, neither when I do this for instance:
Is exactly the same look regardless of setting e.g.
norm = matplotlib.colors.Normalize(0, 10000, clip=True),norm = matplotlib.colors.Normalize(0, 1.5, clip=True), ornorm = matplotlib.colors.Normalize(0, 2000, clip=True).This is what is found in the queried object:
and
images:Are you familiar with any ways to improve this plotting? I would love to have the custom control that Spatialdata offers to generate high-quality figures for publications, but so far the different scales of stains doesn't seem to work well.
Finally, I have also tried this issue: #460, but got exactly the same issue in the end as the author mentioned in their last comment.
All my code was run with:
I hope you can help me out!
Best,
Koen