Skip to content

Commit 3e5d3ee

Browse files
committed
perf(shapes): drop the per-render table join when coloring by a table column
_render_shapes joined the element to its annotating table via _join_table_for_element, whose table[indices, :].copy() does an out-of-order sparse CSR row-gather copy of the whole AnnData (~150 ms on Visium-width tables, more on Xenium/Visium-HD). After #709 color is resolved per shape by _extract_color_column (region-masks + reindexes the table itself) and after #711 the join is a left join, so the joined element/table are no longer needed: use the original element + table. An audit confirms no downstream consumer needs the joined table - the matplotlib/datashader draws never touch it, _decorate_axs's adata is a dead parameter, and .uns custom colors are read from sdata[table_name] inside _set_color_source_vec. Output is pixel-identical to the join path (verified on partial-annotation/na_color, fully-annotated, real datashader (curio 69k) and real Visium), so the visual baselines are unchanged. Measured: visium_hne render_shapes(color=gene) 451 ms -> 297 ms (1.52x). The outline path keeps its own (rarer) join; converting it is a separate follow-up.
1 parent 2066b57 commit 3e5d3ee

1 file changed

Lines changed: 5 additions & 6 deletions

File tree

src/spatialdata_plot/pl/render.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -600,8 +600,8 @@ def _render_shapes(
600600

601601
_check_obs_var_shadow(sdata, element, col_for_color, render_params.table_name)
602602

603-
# filter_tables=False: join_spatialelement_table below overwrites the table,
604-
# so the cs-level sparse copy is wasted work.
603+
# filter_tables=False: the annotating table is read directly below (color is resolved per shape
604+
# from it, region-masked and reindexed), so the cs-level sparse table copy would be wasted work.
605605
sdata_filt = sdata.filter_by_coordinate_system(
606606
coordinate_system=coordinate_system,
607607
filter_tables=False,
@@ -610,12 +610,11 @@ def _render_shapes(
610610
table_name = render_params.table_name
611611
if table_name is None:
612612
table = None
613-
shapes = sdata_filt[element]
614613
else:
614+
# No join/copy: _set_color_source_vec resolves each shape's color from the table (region-masked
615+
# and reindexed to the element), so unannotated shapes keep their place and render with na_color.
615616
_check_instance_ids_overlap(sdata_filt, table_name, element, sdata_filt[element].index)
616-
joined_element, joined_table = _join_table_for_element(sdata, element, table_name)
617-
sdata_filt[element] = shapes = joined_element
618-
sdata_filt[table_name] = table = joined_table
617+
table = sdata_filt[table_name]
619618

620619
shapes = sdata_filt[element]
621620

0 commit comments

Comments
 (0)