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

render_shapes() fails to accept custom color palette but not when cropped to a certain size

Open HansLambda opened this issue 8 months ago • 1 comments

import os as os
import glob
import numpy as np
import pandas as pd
import scanpy as sc
import anndata as ad
import matplotlib.pyplot as plt
import seaborn as sns
import spatialdata as sd
import spatialdata_plot as sd_plot
import zarr
from spatialdata import SpatialData, read_zarr
from spatialdata.transformations import Identity
import squidpy as sq
from spatialdata.models import Image2DModel, PointsModel, ShapesModel, TableModel
import dask.array as da
import dask.dataframe as dd
import tifffile
import geopandas as gpd
from shapely.geometry import Polygon
from spatialdata import bounding_box_query
def crop0(x):
    return bounding_box_query(
        x,
        min_coordinate=[8000, 3000],
        max_coordinate=[12000, 7000],
        axes=("x", "y"),
        target_coordinate_system="global",
    )
crop0(sdata).pl.render_shapes(color="detailed_celltype_annotation", 
                              groups=cells_detailed, 
                              palette=colors_detailed).pl.show(
    figsize=(12, 9),
    legend_fontsize=14)

Where cells_detailed is a list of strings that match the categories in "detailed_celltype_annotation" and colors_detailed is a list of hexcode strings that match cells_detailed This returns the desired output

Image

However

sdata.pl.render_shapes(color="detailed_celltype_annotation", 
                              groups=cells_detailed, 
                              palette=colors_detailed).pl.show(
    figsize=(12, 9),
    legend_fontsize=14)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[86], line 1
----> 1 sdata.pl.render_shapes(color="detailed_celltype_annotation", 
      2                               groups=cells_detailed, 
      3                               palette=colors_detailed).pl.show(
      4     figsize=(12, 9),
      5     legend_fontsize=14)

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/spatialdata_plot/pl/basic.py:937, in PlotAccessor.show(self, coordinate_systems, legend_fontsize, legend_fontweight, legend_loc, legend_fontoutline, na_in_legend, colorbar, wspace, hspace, ncols, frameon, figsize, dpi, fig, title, share_extent, pad_extent, ax, return_ax, save)
    932     wanted_elements, wanted_shapes_on_this_cs, wants_shapes = _get_wanted_render_elements(
    933         sdata, wanted_elements, params_copy, cs, "shapes"
    934     )
    936     if wanted_shapes_on_this_cs:
--> 937         _render_shapes(
    938             sdata=sdata,
    939             render_params=params_copy,
    940             coordinate_system=cs,
    941             ax=ax,
    942             fig_params=fig_params,
    943             scalebar_params=scalebar_params,
    944             legend_params=legend_params,
    945         )
    947 elif cmd == "render_points" and has_points:
    948     wanted_elements, wanted_points_on_this_cs, wants_points = _get_wanted_render_elements(
    949         sdata, wanted_elements, params_copy, cs, "points"
    950     )

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/spatialdata_plot/pl/render.py:259, in _render_shapes(sdata, render_params, coordinate_system, ax, fig_params, scalebar_params, legend_params)
    256         if isinstance(ds_cmap, str) and ds_cmap[0] == "#":
    257             ds_cmap = ds_cmap[:-2]
--> 259     ds_result = ds.tf.shade(
    260         agg,
    261         cmap=ds_cmap,
    262         color_key=color_key,
    263         min_alpha=np.min([254, render_params.fill_alpha * 255]),
    264         how="linear",
    265     )
    266 elif aggregate_with_reduction is not None:  # to shut up mypy
    267     ds_cmap = render_params.cmap_params.cmap

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/datashader/transfer_functions/__init__.py:725, in shade(agg, cmap, color_key, how, alpha, min_alpha, span, name, color_baseline, rescale_discrete_levels)
    722         return _interpolate(agg, cmap, how, alpha, span, min_alpha, name,
    723                             rescale_discrete_levels)
    724 elif agg.ndim == 3:
--> 725     return _colorize(agg, color_key, how, alpha, span, min_alpha, name, color_baseline,
    726                      rescale_discrete_levels)
    727 else:
    728     raise ValueError("agg must use 2D or 3D coordinates")

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/datashader/transfer_functions/__init__.py:383, in _colorize(agg, color_key, how, alpha, span, min_alpha, name, color_baseline, rescale_discrete_levels)
    379 if len(color_key) < len(cats):
    380     raise ValueError(f"Insufficient colors provided ({len(color_key)}) for the categorical "
    381                      f"fields available ({len(cats)})")
--> 383 colors = [rgb(color_key[c]) for c in cats]
    384 rs, gs, bs = map(array, zip(*colors))
    386 # Reorient array (transposing the category dimension first)

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/datashader/transfer_functions/__init__.py:383, in <listcomp>(.0)
    379 if len(color_key) < len(cats):
    380     raise ValueError(f"Insufficient colors provided ({len(color_key)}) for the categorical "
    381                      f"fields available ({len(cats)})")
--> 383 colors = [rgb(color_key[c]) for c in cats]
    384 rs, gs, bs = map(array, zip(*colors))
    386 # Reorient array (transposing the category dimension first)

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/datashader/colors.py:116, in rgb(x)
    114 if isinstance(x, str):
    115     if x.startswith('#'):
--> 116         return hex_to_rgb(x)
    117     elif x in color_lookup:
    118         return hex_to_rgb(color_lookup[x])

File ~/.conda/envs/pca_env/lib/python3.10/site-packages/datashader/colors.py:91, in hex_to_rgb(x)
     83 """Convert a color hexcode to an rgb tuple.
     84 
     85 Example
   (...)
     88 (255, 255, 255)
     89 """
     90 if not (x.startswith('#') and len(x) == 7):
---> 91     raise ValueError("Invalid hex color")
     92 x = x.strip('#')
     93 try:

ValueError: Invalid hex color

I manually ran this code on my color palette and it returns no error: if not (x.startswith('#') and len(x) == 7) The error occurs in any larger crop area and disappears in smaller crops. My goal here was to transfer my color palette from other plots to ensure a consistent coloring scheme. The only difference I can think of is that the cropped regions don't contain all of the celltypes in this shape and somehow that prevents raising this Error.

HansLambda avatar Apr 01 '25 15:04 HansLambda