Skip to content

Commit 51d652f

Browse files
authored
Merge pull request #1 from CSOgroup/feature/complete-selectsim-py
Add feature-complete Python port of SelectSim (v0.3.0)
2 parents 8892b18 + 6b38fd8 commit 51d652f

60 files changed

Lines changed: 12973 additions & 1256 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
name: Bug report
3+
about: Report a bug or unexpected behaviour in SelectSim
4+
title: "[BUG] "
5+
labels: bug
6+
assignees: ''
7+
---
8+
9+
## Describe the bug
10+
11+
A clear and concise description of what the bug is.
12+
13+
## Minimal reproducible example
14+
15+
```python
16+
import selectsim as ss
17+
# paste the smallest code that reproduces the issue
18+
```
19+
20+
## Expected behaviour
21+
22+
What you expected to happen.
23+
24+
## Actual behaviour
25+
26+
What actually happened. Include the full error message / traceback or
27+
unexpected output.
28+
29+
## Environment
30+
31+
- selectsim version: <!-- python -c "import selectsim; print(selectsim.__version__)" -->
32+
- Python version: <!-- python --version -->
33+
- Installation method: <!-- pip / uv / editable install from source -->
34+
- OS: <!-- e.g. macOS 14.5, Ubuntu 22.04 -->
35+
- Optional extras installed: <!-- e.g. selectsim[fast] (jax), selectsim[storage] (zarr) -->
36+
37+
## Additional context
38+
39+
Any other context that may be relevant (e.g. dataset size, number of cores
40+
used, `n_permut`, `backend`/`store` options passed to `null_model_parallel`).
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
name: Feature request
3+
about: Suggest a new feature or improvement for SelectSim
4+
title: "[FEATURE] "
5+
labels: enhancement
6+
assignees: ''
7+
---
8+
9+
## Is your feature request related to a problem?
10+
11+
A clear and concise description of the problem or limitation you are experiencing.
12+
13+
## Proposed solution
14+
15+
Describe the feature or change you would like to see, including any API
16+
design ideas if relevant (e.g. new function signature, new parameter on
17+
`selectX()`).
18+
19+
## Alternatives considered
20+
21+
Any alternative approaches you have considered, and why you prefer the
22+
proposed solution.
23+
24+
## Additional context
25+
26+
Any other context, references, or examples that support the request.

‎.github/workflows/docs.yml‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: docs
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
11+
concurrency:
12+
group: docs-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
build-and-deploy:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Install uv
23+
uses: astral-sh/setup-uv@v3
24+
with:
25+
python-version: "3.12"
26+
27+
- name: Install dependencies (including docs extra)
28+
run: uv sync --all-extras
29+
30+
- name: Build Sphinx docs
31+
run: uv run sphinx-build -b html docs/source docs/build
32+
33+
- name: Deploy to GitHub Pages
34+
uses: peaceiris/actions-gh-pages@v3
35+
with:
36+
github_token: ${{ secrets.GITHUB_TOKEN }}
37+
publish_dir: docs/build
38+
publish_branch: gh-pages

‎.github/workflows/tests.yml‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: tests
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
workflow_dispatch:
9+
10+
permissions: read-all
11+
12+
jobs:
13+
pytest:
14+
runs-on: ubuntu-latest
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
python-version: ["3.10", "3.11", "3.12"]
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Install uv
24+
uses: astral-sh/setup-uv@v3
25+
with:
26+
python-version: ${{ matrix.python-version }}
27+
28+
- name: Install dependencies
29+
run: uv sync --all-extras
30+
31+
- name: Run tests
32+
run: uv run pytest tests/ -q

‎.gitignore‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
.idea/*
1212
.python-version
1313
.vscode/*
14+
.venv/
1415

1516
# Sphinx documentation
1617
docs/build/
18+
docs/jupyter_execute/
19+
docs/.jupyter_cache/
20+
docs/source/generated/

‎CITATION.cff‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
cff-version: 1.2.0
2+
message: "If you use this software, please cite it using the metadata below, and cite the accompanying article as the primary reference (see 'preferred-citation')."
3+
type: software
4+
title: "SelectSim (Python)"
5+
abstract: >-
6+
A Python implementation of the SelectSim methodology for inferring
7+
evolutionary dependencies -- co-mutations and mutual exclusivities --
8+
between functional alterations across cancer genomes. Estimates expected
9+
co-mutation frequencies from individual gene mutation rates and per-sample
10+
tumor mutation burden (TMB), then evaluates significance against a
11+
permutation-based null model.
12+
version: 0.2.0
13+
date-released: "2026-07-12"
14+
license: MIT
15+
repository-code: "https://github.com/CSOgroup/SelectSim_py"
16+
url: "https://csogroup.github.io/SelectSim/"
17+
authors:
18+
- given-names: Arvind
19+
family-names: Iyer
20+
email: ayalurarvind@gmail.com
21+
orcid: "https://orcid.org/0000-0002-8247-700X"
22+
- given-names: Marco
23+
family-names: Mina
24+
email: marco.mina.85@gmail.com
25+
- given-names: Miljan
26+
family-names: Petrovic
27+
email: miljanpet93@gmail.com
28+
- given-names: Giovanni
29+
family-names: Ciriello
30+
email: giovanni.ciriello@unil.ch
31+
orcid: "https://orcid.org/0000-0003-2021-8683"
32+
preferred-citation:
33+
type: article
34+
title: "Evolving patterns of co-mutations from tumor initiation to metastatic progression"
35+
journal: "Nature Genetics"
36+
year: 2026
37+
doi: "10.1038/s41588-026-02661-4"
38+
url: "https://doi.org/10.1038/s41588-026-02661-4"
39+
authors:
40+
- given-names: Arvind
41+
family-names: Iyer
42+
- given-names: Miljan
43+
family-names: Petrovic
44+
- given-names: Debora
45+
family-names: Sesia
46+
- given-names: Luca
47+
family-names: Nanni
48+
- given-names: Marco
49+
family-names: Mina
50+
- given-names: Giovanni
51+
family-names: Ciriello

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 SelectSim authors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎NEWS.md‎

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# SelectSim (Python) 0.1.0
2+
3+
Initial feature-complete Python port of the [SelectSim R package](https://github.com/CSOgroup/SelectSim).
4+
5+
* Ported the core algorithm: `selectX()` end-to-end pipeline, `AlterationLandscape`,
6+
template-matrix generation (`template.py`), TMB-based weighting (`weights.py`),
7+
the permutation null model (`null_model.py`), and all overlap / effect-size /
8+
FDR statistics (`stats.py`).
9+
* Added an optional accelerated backend for `null_model_parallel`
10+
(`backend="jax"`, via the `selectsim[fast]` extra) alongside the default
11+
NumPy backend, and an optional on-disk Zarr store for large null-model runs
12+
(`store="zarr"`, via the `selectsim[storage]` extra) so simulations no
13+
longer need to be held entirely in memory.
14+
* Added `selectsim.gam`: a full port of `R/gam_utils.r`'s MAF-ingestion
15+
pipeline (`filter_maf_*`, `stat_maf_*`, `maf_to_gam`, `TCGA_maf_schema`,
16+
`GENIE_maf_schema`, `mutation_type`) for building Gene Alteration Matrices
17+
(GAMs) directly from raw MAF files.
18+
* Added `selectsim.plotting`: matplotlib/seaborn ports of the R package's
19+
visualization helpers -- `theme_publication`, `obs_exp_scatter`,
20+
`overlap_pair_extract`, `ridge_plot_ed`, `ridge_plot_ed_compare`.
21+
* Added `selectsim.io`: Parquet read/write helpers and Zarr null-model store
22+
utilities.
23+
* Bundled real TCGA LUAD example data (`tests/data/*.parquet`, exported from
24+
the R package's `luad_run_data`/`luad_result`/`luad_maf` datasets) and
25+
added an R-parity test suite (`TestSelectXWithRData` in
26+
`tests/test_selectsim.py`) validating the Python port's output against a
27+
real `SelectSim::selectX()` R reference run.
28+
* 126 tests passing across algorithm, statistics, GAM ingestion, plotting,
29+
and I/O modules.
30+
* Added Sphinx documentation (`docs/`) with a full API reference, an
31+
"Overview" quick-start, and two tutorial notebooks (`introduction`,
32+
`data_processing`) mirroring the R package's vignettes, plus standard
33+
open-source project scaffolding (`LICENSE`, `CITATION.cff`, CI workflows,
34+
issue templates).
35+
* Supports Python 3.10-3.12 (`requires-python = ">=3.10,<3.13"`). The upper
36+
bound is intentional, not a typo: numpy/scipy/jax/zarr don't all publish
37+
prebuilt wheels for 3.13+ yet, and installing on an unsupported interpreter
38+
can silently trigger a slow (or failing) from-source build of numpy.
39+
3.10/3.11/3.12 were each verified to resolve prebuilt wheels and pass the
40+
full test suite.
41+
42+
# SelectSim (Python) 0.2.0
43+
44+
* Fixed several correctness bugs found in code review: `filter_maf_column`
45+
computed a union instead of an intersection when excluding rows matching
46+
several substring values (`inclusive=False, fixed=False`); `store="zarr"`
47+
fully materialized all permutations in memory before writing them to disk,
48+
defeating its own purpose (now streams in bounded batches, ~5x lower peak
49+
memory); the jax backend recompiled from scratch on every call instead of
50+
reusing JAX's compilation cache; `n_cores` was silently ignored with
51+
`backend="jax"` (now warns); `ridge_plot_ed` crashed on an empty null
52+
model; and `retrieve_outliers`'s `n_sim` parameter was dead code and its
53+
90th-percentile threshold was off-by-one relative to the R original.
54+
* This round of work (the fixes above, plus the earlier module ports,
55+
documentation, and uv migration) was developed with the assistance of
56+
Claude Code (Anthropic), directed and verified by Arvind Iyer throughout;
57+
see `git log` for detailed commit history.
58+
59+
# SelectSim (Python) 0.3.0
60+
61+
* **Performance**: the default numpy null-model backend
62+
(`null_model_parallel`, `store="memory"` or `"zarr"`) no longer loops
63+
over genes in Python to pick each row's top-k residual columns;
64+
it now uses the same vectorized double-argsort rank trick the (now
65+
removed) jax backend used, with no per-gene Python loop. Benchmarked
66+
as bit-identical to the old implementation (full R-parity test suite
67+
still passes) and consistently faster, especially at higher `n_cores`.
68+
* **Performance**: `store="zarr"` null-model runs now chunk the on-disk
69+
Zarr array to match the internal write-batch size instead of
70+
defaulting to one chunk per permutation; writing in batches of 200
71+
(the default) previously forced 200 separate compress/write calls per
72+
batch. Benchmarked at ~2.5x faster zarr writes in isolation.
73+
* **Performance**: `estimate_p_val`'s `gene_names: List[str]` parameter
74+
is now `gene_index: Dict[str, int]` -- callers looking up many pairs
75+
(as `estimate_pairwise_p` does, used when `estimate_pairwise=True`)
76+
now build the name-to-index mapping once instead of doing an O(n_genes)
77+
list scan per gene per pair.
78+
* **Removed**: the jax null-model backend (`backend="jax"` on
79+
`null_model_parallel`, the `selectsim[fast]` extra). Benchmarked
80+
against the numpy backend on real LUAD-sized data on CPU (no GPU):
81+
jax was consistently 5-10x *slower*, dominated by per-call JIT
82+
dispatch overhead that this workload's array sizes never amortize.
83+
If GPU-backed acceleration is needed in the future, it should be
84+
re-evaluated against the current (vectorized) numpy backend on
85+
representative GPU hardware, not reintroduced by default.
86+
* **Fixed**: `significance_heatmap` was implemented and tested but never
87+
exported from the top-level `selectsim` package (only reachable via
88+
`selectsim.plotting.significance_heatmap`); it's now `ss.significance_heatmap`.
89+
* Added `null_model_parallel`/`selectX` `store="auto"`: estimates the
90+
null model's memory footprint from cohort size and `n_permut` and
91+
picks `"memory"` or `"zarr"` automatically against a detected (or
92+
configured, `memory_budget_gb`) RAM budget, so one call scales safely
93+
across machines without the caller needing to know cohort dimensions
94+
up front.
95+
* Added `oncoprint` and `oncoprint_pair`: new (not present in the R
96+
package) multi-gene and two-gene co-mutation visualizations comparing
97+
the observed alteration pattern to a retained null-model simulation,
98+
with a per-sample TMB track.
99+
* Extended the `introduction` tutorial notebook with `significance_heatmap`,
100+
`oncoprint`, `oncoprint_pair`, and `ridge_plot_ed_compare` (previously
101+
only `obs_exp_scatter` and `ridge_plot_ed` were demonstrated).
102+
* This round of work was developed with the assistance of Claude Code
103+
(Anthropic), directed and verified by Arvind Iyer throughout; see
104+
`git log` for detailed commit history.

‎README.md‎

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,60 @@
11
# SelectSim Python
22

3-
The goal of `selectsim` package is to implement the methodology to infer
4-
inter-dependencies between functional alterations in cancer. SelectSim
5-
estimates the expected number of mutations in a given gene and a given
6-
sample from the mutation frequency of the gene, f(g), and the tumor
7-
mutation burden (TMB) of the sample, $\mu$(t). These values can be
8-
estimated within specific mutation and tumor subsets, to account for
9-
heterogeneous tumor types, tissue specificities, and distinct mutational
10-
processes.
3+
SelectSim infers evolutionary dependencies — co-mutations and mutual
4+
exclusivities — between functional alterations across cancer genomes. It
5+
estimates the expected co-mutation frequency for each gene pair from
6+
individual mutation frequencies and per-sample tumor mutation burden (TMB),
7+
then evaluates significance against a simulation-based null model.
8+
9+
![SelectSim Method](docs/source/_static/SelectSim_method.png)
10+
11+
This package accompanies the manuscript:
12+
13+
> Iyer A, Petrovic M, Sesia D, Nanni L, Mina M, Ciriello G (2026). Evolving
14+
> patterns of co-mutations from tumor initiation to metastatic progression.
15+
> *Nature Genetics*. DOI: [10.1038/s41588-026-02661-4](https://doi.org/10.1038/s41588-026-02661-4)
16+
17+
## Installation
18+
19+
```bash
20+
cd SelectSim_py
21+
uv sync # recommended; or: pip install -e .
22+
```
23+
24+
Optional extras: `uv sync --extra storage` (Zarr on-disk storage), `--extra docs` (build docs locally), `--all-extras`. Supports Python 3.10-3.12.
25+
26+
## Quick start
27+
28+
```python
29+
import selectsim as ss
30+
31+
# M, sample_class, alteration_class: see the Introduction tutorial for how
32+
# to build these from a MAF, or load the bundled TCGA LUAD example data.
33+
result = ss.selectX(
34+
M, sample_class, alteration_class,
35+
n_cores=1, min_freq=10, n_permut=1000,
36+
)
37+
38+
# Significant evolutionary dependencies
39+
significant = result['result'][result['result']['FDR']]
40+
```
41+
42+
See the [Introduction tutorial](docs/source/tutorials/introduction.ipynb) for a full walkthrough on real TCGA LUAD data, and [`docs/`](docs/) for the full API reference (`selectsim.gam` for MAF ingestion, `selectsim.plotting` for visualization, `selectsim.io` for Parquet/Zarr storage).
43+
44+
## Citation
45+
46+
If you use SelectSim in your research, please cite:
47+
48+
> Iyer A, Petrovic M, Sesia D, Nanni L, Mina M, Ciriello G (2026). Evolving
49+
> patterns of co-mutations from tumor initiation to metastatic progression.
50+
> *Nature Genetics*. DOI: [10.1038/s41588-026-02661-4](https://doi.org/10.1038/s41588-026-02661-4)
51+
52+
Citation metadata is also available in [`CITATION.cff`](CITATION.cff).
53+
54+
## License
55+
56+
MIT License. See [LICENSE](LICENSE).
57+
58+
## Contact
59+
60+
For bugs or feature requests, use the [issue tracker](https://github.com/CSOgroup/SelectSim_py/issues). This is the Python implementation of the [SelectSim R package](https://github.com/CSOgroup/SelectSim).
286 KB
Loading

0 commit comments

Comments
 (0)