multiscoresplot 1.0.3__tar.gz → 1.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. multiscoresplot-1.0.5/.github/workflows/docs.yml +27 -0
  2. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/.pre-commit-config.yaml +1 -0
  3. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/PKG-INFO +9 -7
  4. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/README.md +4 -3
  5. multiscoresplot-1.0.5/docs/api/colorspace.md +25 -0
  6. multiscoresplot-1.0.5/docs/api/index.md +27 -0
  7. multiscoresplot-1.0.5/docs/api/interactive.md +8 -0
  8. multiscoresplot-1.0.5/docs/api/legend.md +5 -0
  9. multiscoresplot-1.0.5/docs/api/plotting.md +5 -0
  10. multiscoresplot-1.0.5/docs/api/scoring.md +5 -0
  11. multiscoresplot-1.0.5/docs/changelog.md +19 -0
  12. multiscoresplot-1.0.5/docs/examples.md +165 -0
  13. multiscoresplot-1.0.5/docs/getting-started.md +64 -0
  14. multiscoresplot-1.0.5/docs/index.md +46 -0
  15. multiscoresplot-1.0.5/docs/pipeline.md +149 -0
  16. multiscoresplot-1.0.5/mkdocs.yml +92 -0
  17. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/pyproject.toml +7 -5
  18. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/__init__.py +1 -1
  19. multiscoresplot-1.0.5/uv.lock +2784 -0
  20. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/.github/workflows/ci.yml +0 -0
  21. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/.github/workflows/publish.yml +0 -0
  22. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/.gitignore +0 -0
  23. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/LICENSE +0 -0
  24. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/_colorspace.py +0 -0
  25. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/_interactive.py +0 -0
  26. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/_legend.py +0 -0
  27. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/_plotting.py +0 -0
  28. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/_scoring.py +0 -0
  29. {multiscoresplot-1.0.3 → multiscoresplot-1.0.5}/src/multiscoresplot/py.typed +0 -0
@@ -0,0 +1,27 @@
1
+ name: Deploy Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: astral-sh/setup-uv@v5
18
+ with:
19
+ python-version: "3.12"
20
+
21
+ - name: Configure git for gh-deploy
22
+ run: |
23
+ git config user.name "github-actions[bot]"
24
+ git config user.email "github-actions[bot]@users.noreply.github.com"
25
+
26
+ - name: Deploy to GitHub Pages
27
+ run: uv run --group docs mkdocs gh-deploy --force
@@ -10,6 +10,7 @@ repos:
10
10
  - id: check-toml
11
11
  - id: check-added-large-files
12
12
  args: ["--maxkb=500"]
13
+ exclude: '^uv\.lock$'
13
14
 
14
15
  - repo: https://github.com/astral-sh/ruff-pre-commit
15
16
  rev: v0.9.9
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multiscoresplot
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Multi-dimensional gene set scoring and visualization for single-cell transcriptomics
5
- Project-URL: Homepage, https://github.com/andrecmacedo/multiscoresplot
6
- Project-URL: Repository, https://github.com/andrecmacedo/multiscoresplot
7
- Project-URL: Issues, https://github.com/andrecmacedo/multiscoresplot/issues
5
+ Project-URL: Homepage, https://github.com/AndreMacedo88/multiscoresplot
6
+ Project-URL: Documentation, https://AndreMacedo88.github.io/multiscoresplot/
7
+ Project-URL: Repository, https://github.com/AndreMacedo88/multiscoresplot
8
+ Project-URL: Issues, https://github.com/AndreMacedo88/multiscoresplot/issues
8
9
  Author: Andre Macedo
9
10
  License-Expression: MIT
10
11
  License-File: LICENSE
@@ -33,9 +34,10 @@ Description-Content-Type: text/markdown
33
34
  # multiscoresplot
34
35
 
35
36
  [![CI](https://github.com/AndreMacedo88/multiscoresplot/actions/workflows/ci.yml/badge.svg)](https://github.com/AndreMacedo88/multiscoresplot/actions/workflows/ci.yml)
36
- [![PyPI](https://img.shields.io/pypi/v/multiscoresplot)](https://pypi.org/project/multiscoresplot/)
37
+ [![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://AndreMacedo88.github.io/multiscoresplot/)
38
+ [![PyPI](https://img.shields.io/pypi/v/multiscoresplot?cacheSeconds=3600)](https://pypi.org/project/multiscoresplot/)
39
+ [![Python](https://img.shields.io/pypi/pyversions/multiscoresplot?cacheSeconds=3600)](https://pypi.org/project/multiscoresplot/)
37
40
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
38
- [![Python](https://img.shields.io/pypi/pyversions/multiscoresplot)](https://pypi.org/project/multiscoresplot/)
39
41
 
40
42
  **Multi-dimensional gene set scoring and visualization for single-cell transcriptomics.**
41
43
 
@@ -230,7 +232,7 @@ rgb = msp.reduce_to_rgb(scores, method="umap")
230
232
  ## Development
231
233
 
232
234
  ```bash
233
- git clone https://github.com/andrecmacedo/multiscoresplot.git
235
+ git clone https://github.com/AndreMacedo88/multiscoresplot.git
234
236
  cd multiscoresplot
235
237
 
236
238
  # Install in editable mode with dev dependencies
@@ -1,9 +1,10 @@
1
1
  # multiscoresplot
2
2
 
3
3
  [![CI](https://github.com/AndreMacedo88/multiscoresplot/actions/workflows/ci.yml/badge.svg)](https://github.com/AndreMacedo88/multiscoresplot/actions/workflows/ci.yml)
4
- [![PyPI](https://img.shields.io/pypi/v/multiscoresplot)](https://pypi.org/project/multiscoresplot/)
4
+ [![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://AndreMacedo88.github.io/multiscoresplot/)
5
+ [![PyPI](https://img.shields.io/pypi/v/multiscoresplot?cacheSeconds=3600)](https://pypi.org/project/multiscoresplot/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/multiscoresplot?cacheSeconds=3600)](https://pypi.org/project/multiscoresplot/)
5
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
- [![Python](https://img.shields.io/pypi/pyversions/multiscoresplot)](https://pypi.org/project/multiscoresplot/)
7
8
 
8
9
  **Multi-dimensional gene set scoring and visualization for single-cell transcriptomics.**
9
10
 
@@ -198,7 +199,7 @@ rgb = msp.reduce_to_rgb(scores, method="umap")
198
199
  ## Development
199
200
 
200
201
  ```bash
201
- git clone https://github.com/andrecmacedo/multiscoresplot.git
202
+ git clone https://github.com/AndreMacedo88/multiscoresplot.git
202
203
  cd multiscoresplot
203
204
 
204
205
  # Install in editable mode with dev dependencies
@@ -0,0 +1,25 @@
1
+ # Color Space
2
+
3
+ Color mapping from gene set scores to RGB (pipeline steps 2–3).
4
+
5
+ ## Blending (2–3 gene sets)
6
+
7
+ ::: multiscoresplot.blend_to_rgb
8
+
9
+ ---
10
+
11
+ ## Dimensionality Reduction (2+ gene sets)
12
+
13
+ ::: multiscoresplot.reduce_to_rgb
14
+
15
+ ---
16
+
17
+ ## Custom Reducers
18
+
19
+ ::: multiscoresplot.register_reducer
20
+
21
+ ---
22
+
23
+ ## Utility
24
+
25
+ ::: multiscoresplot.get_component_labels
@@ -0,0 +1,27 @@
1
+ # API Reference
2
+
3
+ ## Overview
4
+
5
+ | Function | Description | Pipeline Step |
6
+ |----------|-------------|---------------|
7
+ | [`score_gene_sets`](scoring.md) | Score gene sets per cell via pyUCell | Step 1 |
8
+ | [`blend_to_rgb`](colorspace.md#multiscoresplot.blend_to_rgb) | Multiplicative blend to RGB (2–3 sets) | Step 2 |
9
+ | [`reduce_to_rgb`](colorspace.md#multiscoresplot.reduce_to_rgb) | Dimensionality reduction to RGB (2+ sets) | Step 3 |
10
+ | [`plot_embedding`](plotting.md) | Static matplotlib scatter plot | Step 4 |
11
+ | [`plot_embedding_interactive`](interactive.md) | Interactive Plotly scatter plot | Step 4b |
12
+ | [`render_legend`](legend.md) | Draw color-space legend on axes | Step 5 |
13
+ | [`register_reducer`](colorspace.md#multiscoresplot.register_reducer) | Register a custom reduction method | Extensibility |
14
+ | [`get_component_labels`](colorspace.md#multiscoresplot.get_component_labels) | Get axis labels for a reduction method | Utility |
15
+
16
+ ## Module Layout
17
+
18
+ All public functions are available directly from the top-level `multiscoresplot` namespace:
19
+
20
+ ```python
21
+ import multiscoresplot as msp
22
+
23
+ msp.score_gene_sets(...)
24
+ msp.blend_to_rgb(...)
25
+ msp.reduce_to_rgb(...)
26
+ msp.plot_embedding(...)
27
+ ```
@@ -0,0 +1,8 @@
1
+ # Interactive Plotting
2
+
3
+ WebGL-accelerated Plotly scatter plot with hover metadata (pipeline step 4b).
4
+
5
+ !!! note
6
+ Requires the `plotly` extra: `pip install 'multiscoresplot[interactive]'`
7
+
8
+ ::: multiscoresplot.plot_embedding_interactive
@@ -0,0 +1,5 @@
1
+ # Legend
2
+
3
+ Color-space legend rendering for matplotlib axes (pipeline step 5).
4
+
5
+ ::: multiscoresplot.render_legend
@@ -0,0 +1,5 @@
1
+ # Plotting
2
+
3
+ Static matplotlib scatter plot of embeddings colored by RGB values (pipeline step 4).
4
+
5
+ ::: multiscoresplot.plot_embedding
@@ -0,0 +1,5 @@
1
+ # Scoring
2
+
3
+ Gene set scoring via pyUCell (pipeline step 1).
4
+
5
+ ::: multiscoresplot.score_gene_sets
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ ## 1.0.3
4
+
5
+ - Fix badge display in README
6
+
7
+ ## 1.0.2
8
+
9
+ - Fix legend not being plotted in interactive "direct" methods
10
+ - Fix CI badge path in README
11
+
12
+ ## 1.0.1
13
+
14
+ - Initial stable release
15
+ - 5-step pipeline: score, blend, reduce, plot, legend
16
+ - Built-in reducers: PCA, NMF, ICA
17
+ - Pluggable reducer registry
18
+ - Static matplotlib and interactive Plotly plotting
19
+ - Color-space legends for direct and reduction modes
@@ -0,0 +1,165 @@
1
+ # Examples
2
+
3
+ ## Custom Reducer — UMAP
4
+
5
+ Register your own dimensionality reduction method and use it like any built-in:
6
+
7
+ ```python
8
+ import multiscoresplot as msp
9
+
10
+
11
+ def umap_reducer(X, n_components, **kwargs):
12
+ """Reduce score matrix to RGB via UMAP.
13
+
14
+ Parameters
15
+ ----------
16
+ X : ndarray of shape (n_cells, n_gene_sets)
17
+ Score matrix.
18
+ n_components : int
19
+ Number of output components (always 3 for RGB).
20
+
21
+ Returns
22
+ -------
23
+ ndarray of shape (n_cells, 3)
24
+ Embedding with values in [0, 1].
25
+ """
26
+ import umap
27
+
28
+ embedding = umap.UMAP(n_components=n_components, **kwargs).fit_transform(X)
29
+ # min-max normalize each column to [0, 1]
30
+ for j in range(embedding.shape[1]):
31
+ col = embedding[:, j]
32
+ lo, hi = col.min(), col.max()
33
+ if hi > lo:
34
+ embedding[:, j] = (col - lo) / (hi - lo)
35
+ return embedding
36
+
37
+
38
+ # Register it
39
+ msp.register_reducer("umap", umap_reducer, component_prefix="UMAP")
40
+
41
+ # Use it
42
+ rgb = msp.reduce_to_rgb(scores, method="umap")
43
+ msp.plot_embedding(adata, rgb, basis="umap", method="umap",
44
+ gene_set_names=list(gene_sets.keys()))
45
+ ```
46
+
47
+ ## Different Embeddings
48
+
49
+ Plot the same RGB coloring on different embeddings to compare:
50
+
51
+ ```python
52
+ import matplotlib.pyplot as plt
53
+
54
+ scores = msp.score_gene_sets(adata, gene_sets, inplace=True)
55
+ rgb = msp.reduce_to_rgb(scores, method="pca")
56
+
57
+ fig, axes = plt.subplots(1, 3, figsize=(18, 5))
58
+
59
+ for ax, basis in zip(axes, ["umap", "pca", "X_scanorama"]):
60
+ msp.plot_embedding(
61
+ adata, rgb,
62
+ basis=basis,
63
+ method="pca",
64
+ gene_set_names=list(gene_sets.keys()),
65
+ ax=ax,
66
+ title=basis.upper(),
67
+ show=False,
68
+ )
69
+
70
+ plt.tight_layout()
71
+ plt.show()
72
+ ```
73
+
74
+ ## Comparing Reduction Methods
75
+
76
+ Visualize how PCA, NMF, and ICA produce different colorings:
77
+
78
+ ```python
79
+ import matplotlib.pyplot as plt
80
+
81
+ scores = msp.score_gene_sets(adata, gene_sets, inplace=True)
82
+
83
+ fig, axes = plt.subplots(1, 3, figsize=(18, 5))
84
+
85
+ for ax, method in zip(axes, ["pca", "nmf", "ica"]):
86
+ rgb = msp.reduce_to_rgb(scores, method=method)
87
+ msp.plot_embedding(
88
+ adata, rgb,
89
+ basis="umap",
90
+ method=method,
91
+ gene_set_names=list(gene_sets.keys()),
92
+ ax=ax,
93
+ title=method.upper(),
94
+ show=False,
95
+ )
96
+
97
+ plt.tight_layout()
98
+ plt.show()
99
+ ```
100
+
101
+ ## Interactive Plot with Hover Metadata
102
+
103
+ Explore individual cells with hover tooltips:
104
+
105
+ ```python
106
+ scores = msp.score_gene_sets(adata, gene_sets, inplace=True)
107
+ rgb = msp.reduce_to_rgb(scores, method="nmf")
108
+
109
+ msp.plot_embedding_interactive(
110
+ adata, rgb,
111
+ basis="umap",
112
+ scores=scores,
113
+ method="nmf",
114
+ gene_set_names=list(gene_sets.keys()),
115
+ hover_columns=["n_counts", "cell_type"], # any adata.obs columns
116
+ point_size=2,
117
+ width=800,
118
+ height=600,
119
+ )
120
+ ```
121
+
122
+ ## Customizing Plot Appearance
123
+
124
+ ```python
125
+ ax = msp.plot_embedding(
126
+ adata, rgb,
127
+ basis="umap",
128
+ method="pca",
129
+ gene_set_names=list(gene_sets.keys()),
130
+ point_size=5,
131
+ alpha=0.6,
132
+ figsize=(8, 8),
133
+ title="SVZ Neural Lineage",
134
+ legend=True,
135
+ legend_style="side", # legend in a separate panel
136
+ legend_loc="upper right",
137
+ show=False,
138
+ )
139
+
140
+ # Further customize the returned axes
141
+ ax.set_xlabel("UMAP 1", fontsize=14)
142
+ ax.set_ylabel("UMAP 2", fontsize=14)
143
+ ```
144
+
145
+ ## Direct Blend for 2–3 Gene Sets
146
+
147
+ When you have exactly 2 or 3 gene sets, direct blending gives the most intuitive
148
+ color mapping:
149
+
150
+ ```python
151
+ two_sets = {
152
+ "Stem": ["Sox2", "Pax6", "Nes"],
153
+ "Neuronal": ["Dcx", "Tubb3", "Neurod1"],
154
+ }
155
+
156
+ scores = msp.score_gene_sets(adata, two_sets, inplace=True)
157
+ rgb = msp.blend_to_rgb(scores) # blue/red by default
158
+
159
+ msp.plot_embedding(
160
+ adata, rgb,
161
+ basis="umap",
162
+ method="direct",
163
+ gene_set_names=list(two_sets.keys()),
164
+ )
165
+ ```
@@ -0,0 +1,64 @@
1
+ # Getting Started
2
+
3
+ ## Installation
4
+
5
+ Install from PyPI:
6
+
7
+ ```bash
8
+ pip install multiscoresplot
9
+ ```
10
+
11
+ For interactive Plotly plots:
12
+
13
+ ```bash
14
+ pip install 'multiscoresplot[interactive]'
15
+ ```
16
+
17
+ ## Prerequisites
18
+
19
+ multiscoresplot expects an [AnnData](https://anndata.readthedocs.io/) object with:
20
+
21
+ - A precomputed dimensionality reduction embedding (e.g., UMAP, PCA, or Scanorama) stored in `adata.obsm`
22
+ - Gene expression data (raw or normalized) accessible for scoring
23
+
24
+ ## Minimal Working Example
25
+
26
+ ```python
27
+ import multiscoresplot as msp
28
+
29
+ # 1. Define your gene sets
30
+ gene_sets = {
31
+ "Stem": ["Sox2", "Pax6", "Nes"],
32
+ "Neuronal": ["Dcx", "Tubb3", "Neurod1"],
33
+ "Astrocytic": ["Gfap", "Aqp4", "Aldh1l1"],
34
+ }
35
+
36
+ # 2. Score gene sets per cell (stores in adata.obs as score-<name>)
37
+ scores = msp.score_gene_sets(adata, gene_sets, inplace=True)
38
+
39
+ # 3. Map scores to RGB — choose one:
40
+ # Direct blend (2–3 gene sets only)
41
+ rgb = msp.blend_to_rgb(scores)
42
+ # Or dimensionality reduction (any number of gene sets)
43
+ rgb = msp.reduce_to_rgb(scores, method="pca")
44
+
45
+ # 4. Plot on a UMAP embedding
46
+ msp.plot_embedding(
47
+ adata, rgb,
48
+ basis="umap",
49
+ method="pca",
50
+ gene_set_names=list(gene_sets.keys()),
51
+ )
52
+ ```
53
+
54
+ !!! tip "Which color mapping to use?"
55
+ - **`blend_to_rgb`** — Best for 2–3 gene sets. Uses intuitive multiplicative blending from white, where each gene set darkens toward its assigned color.
56
+ - **`reduce_to_rgb`** — Works for any number of gene sets (2+). Uses PCA, NMF, or ICA to project scores into a 3D RGB space.
57
+
58
+ See the [Pipeline Guide](pipeline.md) for a detailed comparison.
59
+
60
+ ## Next Steps
61
+
62
+ - [Pipeline Guide](pipeline.md) — Understand each step and when to use each method
63
+ - [API Reference](api/index.md) — Full function signatures and parameters
64
+ - [Examples](examples.md) — Custom reducers, plot customization, and more
@@ -0,0 +1,46 @@
1
+ # multiscoresplot
2
+
3
+ **Multi-dimensional gene set scoring and visualization for single-cell transcriptomics.**
4
+
5
+ Color dimensionality reduction plots (UMAP, PCA, etc.) using a multi-dimensional
6
+ color space derived from gene set scores — visualize the activity of multiple gene
7
+ programs simultaneously in a single plot.
8
+
9
+ ## Key Features
10
+
11
+ - **Score** gene sets per cell using [UCell](https://github.com/Cem-Gulec/pyUCell)
12
+ - **Blend** 2–3 gene sets to RGB via multiplicative blending
13
+ - **Reduce** any number of gene sets to RGB via PCA / NMF / ICA
14
+ - **Plot** static matplotlib or interactive Plotly scatter plots
15
+ - **Extend** with custom dimensionality reduction methods
16
+
17
+ ## Quick Example
18
+
19
+ ```python
20
+ import multiscoresplot as msp
21
+
22
+ # Define gene sets of interest
23
+ gene_sets = {
24
+ "qNSCs": ["Id3", "Aldoc", "Slc1a3"],
25
+ "aNSCs": ["Egfr", "Ascl1", "Mki67"],
26
+ "TAP": ["Dll1", "Dcx", "Neurod1"],
27
+ "NB": ["Dcx", "Sox11", "Tubb3"],
28
+ }
29
+
30
+ # 1. Score gene sets per cell
31
+ scores = msp.score_gene_sets(adata, gene_sets, inplace=True)
32
+
33
+ # 2. Map scores to RGB colors
34
+ rgb = msp.reduce_to_rgb(scores, method="pca")
35
+
36
+ # 3. Plot
37
+ msp.plot_embedding(
38
+ adata, rgb,
39
+ basis="umap",
40
+ method="pca",
41
+ gene_set_names=list(gene_sets.keys()),
42
+ )
43
+ ```
44
+
45
+ [Get Started](getting-started.md){ .md-button .md-button--primary }
46
+ [API Reference](api/index.md){ .md-button }
@@ -0,0 +1,149 @@
1
+ # Pipeline Guide
2
+
3
+ multiscoresplot follows a 5-step pipeline to go from gene sets to a colored embedding plot.
4
+
5
+ ## Step 1 — Score Gene Sets
6
+
7
+ Calculate per-cell gene set scores using [pyUCell](https://github.com/Cem-Gulec/pyUCell).
8
+ Scores are stored in `adata.obs` as `score-<name>` columns with values in [0, 1].
9
+
10
+ ```python
11
+ scores = msp.score_gene_sets(adata, gene_sets, inplace=True)
12
+
13
+ # With tuning parameters
14
+ scores = msp.score_gene_sets(
15
+ adata, gene_sets,
16
+ max_rank=1500, # rank cap (tune to median genes per cell)
17
+ chunk_size=1000, # cells per batch
18
+ n_jobs=-1, # parallelism (-1 = all cores)
19
+ inplace=False, # don't store in adata.obs
20
+ )
21
+ ```
22
+
23
+ !!! note
24
+ `score_gene_sets` wraps pyUCell's ranking-based scoring. The `max_rank` parameter
25
+ controls how many top-ranked genes per cell are considered — set it close to the
26
+ median number of detected genes per cell for best results.
27
+
28
+ ## Step 2 — Blend to RGB (2–3 Gene Sets)
29
+
30
+ For **2–3 gene sets**, multiplicative blending maps scores directly to colors. Starting from
31
+ white, each gene set darkens the color toward its base hue proportionally to the score.
32
+
33
+ ```python
34
+ # Default colors (2 sets: blue/red, 3 sets: R/G/B)
35
+ rgb = msp.blend_to_rgb(scores)
36
+
37
+ # Custom colors
38
+ rgb = msp.blend_to_rgb(scores, colors=[(1, 0, 0), (0, 0.5, 1)])
39
+ ```
40
+
41
+ **How it works:** Each cell starts as white `(1, 1, 1)`. For each gene set, the cell's
42
+ color is multiplied element-wise by a blend between white and the gene set's base color,
43
+ weighted by the score. High scores pull the color toward the base hue; low scores leave
44
+ it near white. Cells with multiple high scores produce mixed colors.
45
+
46
+ ## Step 3 — Reduce to RGB (2+ Gene Sets)
47
+
48
+ For **any number of gene sets**, dimensionality reduction projects the score matrix into
49
+ 3 components that become RGB channels.
50
+
51
+ ```python
52
+ rgb = msp.reduce_to_rgb(scores, method="pca") # default
53
+ rgb = msp.reduce_to_rgb(scores, method="nmf")
54
+ rgb = msp.reduce_to_rgb(scores, method="ica")
55
+ ```
56
+
57
+ ### Choosing a Reduction Method
58
+
59
+ | Method | Best for | Properties |
60
+ |--------|----------|------------|
61
+ | **PCA** | General use | Linear, orthogonal components, preserves maximum variance. Components can mix positive and negative loadings. |
62
+ | **NMF** | Interpretability | Non-negative components — each RGB channel corresponds to a non-negative combination of gene sets. Often more biologically intuitive. |
63
+ | **ICA** | Independent signals | Maximizes statistical independence between components. Useful when gene programs are expected to be independent. |
64
+
65
+ !!! tip
66
+ Start with **PCA** for exploration. Switch to **NMF** if you want components that are
67
+ easier to interpret biologically (since NMF coefficients are always non-negative).
68
+ Use **ICA** when you suspect the gene programs represent statistically independent signals.
69
+
70
+ ## Step 4 — Plot Embedding
71
+
72
+ Scatter plot of embedding coordinates (UMAP, PCA, etc.) colored by the RGB values,
73
+ with an integrated color-space legend.
74
+
75
+ ```python
76
+ # Basic usage
77
+ msp.plot_embedding(
78
+ adata, rgb,
79
+ basis="umap",
80
+ method="pca",
81
+ gene_set_names=["qNSCs", "aNSCs", "TAP", "NB"],
82
+ )
83
+
84
+ # With customization
85
+ ax = msp.plot_embedding(
86
+ adata, rgb,
87
+ basis="umap",
88
+ method="pca",
89
+ gene_set_names=["qNSCs", "aNSCs", "TAP", "NB"],
90
+ legend=True, # show color legend (default)
91
+ legend_style="inset", # "inset" or "side"
92
+ legend_loc="lower right", # legend position
93
+ point_size=3,
94
+ alpha=0.8,
95
+ figsize=(6, 6),
96
+ title="SVZ lineage",
97
+ show=False, # return axes instead of displaying
98
+ )
99
+ ```
100
+
101
+ ### Step 4b — Interactive Plot (requires Plotly)
102
+
103
+ WebGL-accelerated scatter plot with hover info showing gene set scores, RGB channel
104
+ values, and custom metadata.
105
+
106
+ ```python
107
+ msp.plot_embedding_interactive(
108
+ adata, rgb,
109
+ basis="umap",
110
+ scores=scores,
111
+ method="nmf",
112
+ gene_set_names=["qNSCs", "aNSCs", "TAP", "NB"],
113
+ hover_columns=["n_counts", "cell_type"],
114
+ legend=True,
115
+ legend_loc="lower right",
116
+ point_size=2,
117
+ width=600,
118
+ height=500,
119
+ )
120
+ ```
121
+
122
+ !!! note
123
+ Interactive plots require the `plotly` extra: `pip install 'multiscoresplot[interactive]'`
124
+
125
+ ## Step 5 — Standalone Legend
126
+
127
+ Render the color-space legend independently on any matplotlib axes.
128
+
129
+ ```python
130
+ import matplotlib.pyplot as plt
131
+
132
+ fig, ax = plt.subplots()
133
+
134
+ # Direct mode (2-set square or 3-set triangle)
135
+ msp.render_legend(ax, "direct", gene_set_names=["A", "B", "C"])
136
+
137
+ # Reduction mode (RGB triangle with component labels)
138
+ msp.render_legend(ax, "pca")
139
+ msp.render_legend(ax, "nmf", component_labels=["NMF1", "NMF2", "NMF3"])
140
+ ```
141
+
142
+ ## Blend vs. Reduce — When to Use Which
143
+
144
+ | | `blend_to_rgb` | `reduce_to_rgb` |
145
+ |---|---|---|
146
+ | **Gene sets** | 2–3 only | 2 or more |
147
+ | **Color mapping** | Direct: each gene set has its own color | Learned: RGB channels are linear combinations of scores |
148
+ | **Interpretability** | Immediate — colors correspond directly to gene sets | Requires the legend to interpret RGB channels |
149
+ | **Best for** | Focused comparisons of 2–3 programs | Exploratory analysis of many programs simultaneously |