Per-point size array is cumulatively reordered across multi-color subplots
Bug description
When calling sc.pl.embedding (or sc.pl.umap, etc.) with multiple color keys and a per-point size array, the marker sizes are incorrect in all subplots after the first.
The root cause is in scatterplots.py (line 299): the size variable is reordered in-place within the per-color loop, but the reordered result carries over to the next iteration:
for count, (value_to_plot, dims) in enumerate(zip(color, dimensions, strict=True)):
...
order = ... # computed from this color's values
if isinstance(size, np.ndarray):
size = np.array(size)[order] # mutates the loop variable!
Each subplot computes its own order for z-ordering, but applies it to the already-reordered size from the previous iteration. This means:
- Subplot 1: correct sizes
- Subplot 2: sizes scrambled by
order_1 ∘ order_2
- Subplot 3: sizes scrambled by
order_1 ∘ order_2 ∘ order_3
- etc.
Note that color_source_vector, color_vector, and coords don't have this problem because they are freshly computed from adata / basis_values each iteration.
Reproduction
import scanpy as sc
import numpy as np
adata = sc.datasets.pbmc3k_processed()
sizes = np.random.default_rng(0).uniform(10, 200, size=adata.n_obs)
sc.pl.umap(adata, color=["louvain", "n_genes", "n_counts"], size=sizes)
# Dot sizes visibly differ across the three panels despite being the same array
Expected behavior
The same per-point size array should be applied consistently to all subplots: the i-th point should always get size[i], regardless of what z-ordering is applied.
Suggested fix
Use a loop-local variable (e.g., _size) so each iteration reorders from the original array. See PR #4023.
Versions
Confirmed on main as of commit 1fbe008d.
Per-point
sizearray is cumulatively reordered across multi-color subplotsBug description
When calling
sc.pl.embedding(orsc.pl.umap, etc.) with multiplecolorkeys and a per-pointsizearray, the marker sizes are incorrect in all subplots after the first.The root cause is in
scatterplots.py(line 299): thesizevariable is reordered in-place within the per-color loop, but the reordered result carries over to the next iteration:Each subplot computes its own
orderfor z-ordering, but applies it to the already-reorderedsizefrom the previous iteration. This means:order_1 ∘ order_2order_1 ∘ order_2 ∘ order_3Note that
color_source_vector,color_vector, andcoordsdon't have this problem because they are freshly computed fromadata/basis_valueseach iteration.Reproduction
Expected behavior
The same per-point
sizearray should be applied consistently to all subplots: the i-th point should always getsize[i], regardless of what z-ordering is applied.Suggested fix
Use a loop-local variable (e.g.,
_size) so each iteration reorders from the original array. See PR #4023.Versions
Confirmed on
mainas of commit1fbe008d.