Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged

Mypy #235

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
72eef3d
allow feature branches tests
melonora Feb 19, 2024
dcb6fbe
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 12, 2024
9e0861e
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 22, 2024
15ab484
Merge branch 'main' of https://github.com/melonora/spatialdata-plot
melonora Mar 23, 2024
a69b0dc
set outline_alpha 0
melonora Mar 24, 2024
0b24af7
remove comment
melonora Mar 24, 2024
91dddad
remove comment
melonora Mar 24, 2024
0704b44
Merge branch 'scverse:main' into main
melonora Mar 29, 2024
688d1b3
ignore prettier cache
melonora Mar 29, 2024
e93c8a2
mypy fixes
melonora Mar 29, 2024
7466881
add type annotations
melonora Mar 29, 2024
989c13e
add type annotations
melonora Mar 29, 2024
2f8b0e1
some more mypy
melonora Mar 29, 2024
a430ed3
more proper fix
melonora Mar 29, 2024
d518104
just some more
melonora Mar 30, 2024
427c73c
more mypy
melonora Mar 30, 2024
d6b1412
down to 68
melonora Mar 30, 2024
5c6e2ce
back to 53
melonora Mar 30, 2024
3b9ce2f
35 remaining
melonora Mar 30, 2024
37999a9
26 remaining
melonora Mar 31, 2024
01c3ec4
23 remaining
melonora Mar 31, 2024
420adbe
16 remaining
melonora Mar 31, 2024
3a8bb55
12 remaining
melonora Mar 31, 2024
b171d59
11 remaining
melonora Mar 31, 2024
9e9d310
11 remaining
melonora Mar 31, 2024
1b4ede5
10 remaining
melonora Mar 31, 2024
6a13c3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 31, 2024
88cefd3
its the final countdown todododo
melonora Mar 31, 2024
b89778e
and that is 6
melonora Mar 31, 2024
9c88e91
down to 4
melonora Mar 31, 2024
8dd7d86
down to 2
melonora Mar 31, 2024
f29f4ca
and that fixed mypy mess
melonora Mar 31, 2024
302bf8e
fix tests
melonora Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ buck-out/
__pycache__/
.mypy_cache/
.ruff_cache/
/node_modules

# Distribution / packaging
/build/
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/basic.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,7 +272,7 @@ def render_shapes(
def render_points(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
alpha: float | int = 1.0,
groups: list[list[str | None]] | list[str] | str | None = None,
palette: list[list[str | None]] | list[str] | str | None = None,
Expand DownExpand Up@@ -475,7 +475,7 @@ def render_images(
def render_labels(
self,
elements: list[str] | str | None = None,
color: list[str] | str | None = None,
color: list[str | None] | str | None = None,
groups: list[list[str | None]] | list[str] | str | None = None,
contour_px: int = 3,
outline: bool = False,
Expand DownExpand Up@@ -562,6 +562,7 @@ def render_labels(
na_color=na_color, # type: ignore[arg-type]
**kwargs,
)

sdata.plotting_tree[f"{n_steps+1}_render_labels"] = LabelsRenderParams(
elements=params_dict["elements"],
color=params_dict["color"],
Expand Down
96 changes: 51 additions & 45 deletions src/spatialdata_plot/pl/render.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,8 @@
_multiscale_to_spatial_image,
_normalize,
_rasterize_if_necessary,
_return_list_list_str_none,
_return_list_str_none,
_set_color_source_vec,
to_hex,
)
Expand All@@ -62,7 +64,12 @@ def _render_shapes(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)

assert isinstance(element_table_mapping, dict)
sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
filter_tables=any(value is not None for value in element_table_mapping.values()),
Expand All@@ -72,7 +79,7 @@ def _render_shapes(
elements = list(sdata_filt.shapes.keys())

for index, e in enumerate(elements):
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
shapes = sdata.shapes[e]

table_name = element_table_mapping.get(e)
Expand DownExpand Up@@ -104,13 +111,13 @@ def _render_shapes(
element_index=index,
element_name=e,
value_to_plot=col_for_color,
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
groups=groups[index] if groups[index][0] is not None else None,
palette=(
render_params.palette[index] if render_params.palette is not None else None
palettes[index] if palettes is not None else None
), # and render_params.palette[index][0] is not None
na_color=render_params.color[index] or render_params.cmap_params.na_color,
na_color=colors[index] or render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=table_name,
table_name=cast(str, table_name),
)

values_are_categorical = color_source_vector is not None
Expand All@@ -126,12 +133,8 @@ def _render_shapes(

# filter by `groups`

if (
isinstance(render_params.groups, list)
and render_params.groups[index][0] is not None
and color_source_vector is not None
):
mask = color_source_vector.isin(render_params.groups[index])
if isinstance(groups, list) and groups[index][0] is not None and color_source_vector is not None:
mask = color_source_vector.isin(groups[index])
shapes = shapes[mask]
shapes = shapes.reset_index()
color_source_vector = color_source_vector[mask]
Expand DownExpand Up@@ -177,11 +180,11 @@ def _render_shapes(
len(set(color_vector)) == 1 and list(set(color_vector))[0] == to_hex(render_params.cmap_params.na_color)
):
# necessary in case different shapes elements are annotated with one table
if color_source_vector is not None and render_params.col_for_color[index] is not None:
if color_source_vector is not None and col_for_color is not None:
color_source_vector = color_source_vector.remove_unused_categories()

# False if user specified color-like with 'color' parameter
colorbar = False if render_params.col_for_color[index] is None else legend_params.colorbar
colorbar = False if cols_for_color[index] is None else legend_params.colorbar

_ = _decorate_axs(
ax=ax,
Expand DownExpand Up@@ -215,6 +218,12 @@ def _render_points(
) -> None:
elements = render_params.elements
element_table_mapping = render_params.element_table_mapping
cols_for_color = _return_list_str_none(render_params.col_for_color)
groups = _return_list_list_str_none(render_params.groups)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
# Purely for mypy
assert isinstance(element_table_mapping, dict)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand All@@ -226,11 +235,11 @@ def _render_points(

for index, e in enumerate(elements):
points = sdata.points[e]
col_for_color = render_params.col_for_color[index]
col_for_color = cols_for_color[index]
table_name = element_table_mapping.get(e)

coords = ["x", "y"]
# if col_for_color is not None:

if (
col_for_color is not None
and col_for_color not in points.columns
Expand All@@ -257,8 +266,8 @@ def _render_points(
coords += [col_for_color]
points = points[coords].compute()

if render_params.groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(render_params.groups[index])]
if groups[index][0] is not None and col_for_color is not None:
points = points[points[col_for_color].isin(groups[index])]

# we construct an anndata to hack the plotting functions
if table_name is None:
Expand All@@ -285,24 +294,22 @@ def _render_points(
source=adata,
target=adata,
key=col_for_color,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
)

# when user specified a single color, we overwrite na with it
default_color = (
render_params.color[index]
if col_for_color is None and render_params.color[index] is not None
else render_params.cmap_params.na_color
colors[index] if col_for_color is None and colors[index] is not None else render_params.cmap_params.na_color
)

color_source_vector, color_vector, _ = _set_color_source_vec(
sdata=sdata_filt,
element=points,
element_index=index,
element_name=e,
value_to_plot=render_params.col_for_color[index],
groups=render_params.groups[index] if render_params.groups[index][0] is not None else None,
palette=render_params.palette[index] if render_params.palette[index][0] is not None else None,
value_to_plot=col_for_color,
groups=groups[index] if groups[index][0] is not None else None,
palette=palettes[index] if palettes[index][0] is not None else None,
na_color=default_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand All@@ -327,7 +334,6 @@ def _render_points(
norm=norm,
alpha=render_params.alpha,
transform=trans,
# **kwargs,
)
cax = ax.add_collection(_cax)

Expand All@@ -342,7 +348,7 @@ def _render_points(
cax=cax,
fig_params=fig_params,
adata=adata,
value_to_plot=render_params.col_for_color,
value_to_plot=col_for_color,
color_source_vector=color_source_vector,
palette=palette,
alpha=render_params.alpha,
Expand All@@ -369,6 +375,7 @@ def _render_images(
rasterize: bool,
) -> None:
elements = render_params.elements
palettes = _return_list_list_str_none(render_params.palette)

sdata_filt = sdata.filter_by_coordinate_system(
coordinate_system=coordinate_system,
Expand DownExpand Up@@ -445,11 +452,11 @@ def _render_images(
if render_params.cmap_params.norm is not None: # type: ignore[attr-defined]
layer = render_params.cmap_params.norm(layer) # type: ignore[attr-defined]

if isinstance(render_params.palette, list):
if render_params.palette[i][0] is None:
if isinstance(palettes, list):
if palettes[i][0] is None:
cmap = render_params.cmap_params.cmap # type: ignore[attr-defined]
else:
cmap = _get_linear_colormap(render_params.palette[i], "k")[0] # type: ignore[arg-type]
cmap = _get_linear_colormap(palettes[i], "k")[0] # type: ignore[arg-type]

# Overwrite alpha in cmap: https://stackoverflow.com/a/10127675
cmap._init()
Expand DownExpand Up@@ -483,12 +490,8 @@ def _render_images(
layers[c] = render_params.cmap_params[ch_index].norm(layers[c])

# 2A) Image has 3 channels, no palette info, and no/only one cmap was given
if isinstance(render_params.palette, list):
if (
n_channels == 3
and render_params.palette[i][0] is None
and not isinstance(render_params.cmap_params, list)
):
if isinstance(palettes, list):
if n_channels == 3 and palettes[i][0] is None and not isinstance(render_params.cmap_params, list):
if render_params.cmap_params.is_default: # -> use RGB
stacked = np.stack([layers[c] for c in channels], axis=-1)
else: # -> use given cmap for each channel
Expand DownExpand Up@@ -516,7 +519,7 @@ def _render_images(
im.set_transform(trans_data)

# 2B) Image has n channels, no palette/cmap info -> sample n categorical colors
elif render_params.palette[i][0] is None and not got_multiple_cmaps:
elif palettes[i][0] is None and not got_multiple_cmaps:
# overwrite if n_channels == 2 for intuitive result
if n_channels == 2:
seed_colors = ["#ff0000ff", "#00ff00ff"]
Expand All@@ -538,11 +541,11 @@ def _render_images(
im.set_transform(trans_data)

# 2C) Image has n channels and palette info
elif render_params.palette[i][0] is not None and not got_multiple_cmaps:
if len(render_params.palette[i]) != n_channels:
elif palettes[i][0] is not None and not got_multiple_cmaps:
if len(palettes[i]) != n_channels:
raise ValueError("If 'palette' is provided, its length must match the number of channels.")

channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in render_params.palette[i]]
channel_cmaps = [_get_linear_colormap([c], "k")[0] for c in palettes[i] if isinstance(c, str)]

# Apply cmaps to each channel and add up
colored = np.stack([channel_cmaps[i](layers[c]) for i, c in enumerate(channels)], 0).sum(0)
Expand All@@ -556,7 +559,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is None and got_multiple_cmaps:
elif palettes[i][0] is None and got_multiple_cmaps:
channel_cmaps = [cp.cmap for cp in render_params.cmap_params] # type: ignore[union-attr]

# Apply cmaps to each channel, add up and normalize to [0, 1]
Expand All@@ -574,7 +577,7 @@ def _render_images(
)
im.set_transform(trans_data)

elif render_params.palette[i][0] is not None and got_multiple_cmaps:
elif palettes[i][0] is not None and got_multiple_cmaps:
raise ValueError("If 'palette' is provided, 'cmap' must be None.")


Expand All@@ -590,6 +593,9 @@ def _render_labels(
) -> None:
elements = render_params.elements
element_table_mapping = cast(dict[str, str], render_params.element_table_mapping)
palettes = _return_list_list_str_none(render_params.palette)
colors = _return_list_str_none(render_params.color)
groups = _return_list_list_str_none(render_params.groups)

if render_params.outline is False:
render_params.outline_alpha = 0
Expand All@@ -606,7 +612,7 @@ def _render_labels(
label = sdata_filt.labels[e]
extent = get_extent(label, coordinate_system=coordinate_system)
scale = render_params.scale[i] if isinstance(render_params.scale, list) else render_params.scale
color = render_params.color[i]
color = colors[i]

# get best scale out of multiscale label
if isinstance(label, MultiscaleSpatialImage):
Expand DownExpand Up@@ -651,8 +657,8 @@ def _render_labels(
element_index=i,
element_name=e,
value_to_plot=color,
groups=render_params.groups[i],
palette=render_params.palette[i],
groups=groups[i], # if isinstance(groups, list) else None,
palette=palettes[i],
na_color=render_params.cmap_params.na_color,
cmap_params=render_params.cmap_params,
table_name=cast(str, table_name),
Expand DownExpand Up@@ -733,7 +739,7 @@ def _render_labels(
adata=table,
value_to_plot=color,
color_source_vector=color_source_vector,
palette=render_params.palette[i],
palette=palettes[i],
alpha=render_params.fill_alpha,
na_color=render_params.cmap_params.na_color,
legend_fontsize=legend_params.legend_fontsize,
Expand Down
28 changes: 14 additions & 14 deletions src/spatialdata_plot/pl/render_params.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,32 +71,32 @@ class ShapesRenderParams:
cmap_params: CmapParams
outline_params: OutlineParams
elements: str | Sequence[str] | None = None
color: str | None = None
color: list[str | None] | str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.3
scale: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
class PointsRenderParams:
"""Points render parameters.."""

cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: str | None = None
col_for_color: str | None = None
groups: str | Sequence[str] | None = None
palette: ListedColormap | str | None = None
elements: str | list[str] | None = None
color: list[str | None] | str | None = None
col_for_color: list[str | None] | str | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
alpha: float = 1.0
size: float = 1.0
transfunc: Callable[[float], float] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None


@dataclass
Expand All@@ -106,7 +106,7 @@ class ImageRenderParams:
cmap_params: list[CmapParams] | CmapParams
elements: str | Sequence[str] | None = None
channel: list[str] | list[int] | int | str | None = None
palette: ListedColormap | str | None = None
palette: ListedColormap | list[str | None] | None = None
alpha: float = 1.0
quantiles_for_norm: tuple[float | None, float | None] = (None, None)
scale: str | list[str] | None = None
Expand All@@ -119,12 +119,12 @@ class LabelsRenderParams:
cmap_params: CmapParams
elements: str | Sequence[str] | None = None
color: list[str | None] | str | None = None
groups: str | Sequence[str] | None = None
groups: str | list[list[str | None]] | list[str | None] | None = None
contour_px: int | None = None
outline: bool = False
palette: ListedColormap | str | None = None
palette: ListedColormap | list[list[str | None]] | list[str | None] | None = None
outline_alpha: float = 1.0
fill_alpha: float = 0.4
transfunc: Callable[[float], float] | None = None
scale: str | list[str] | None = None
element_table_mapping: dict[str, set[str] | str] | str | list[str] | None = None
element_table_mapping: dict[str, set[str | None] | str | None] | str | list[str] | None = None
Loading