clonetrast 0.1.0__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 (57) hide show
  1. clonetrast-0.1.0/.github/workflows/ci.yml +102 -0
  2. clonetrast-0.1.0/.github/workflows/publish.yml +57 -0
  3. clonetrast-0.1.0/.gitignore +48 -0
  4. clonetrast-0.1.0/.readthedocs.yaml +17 -0
  5. clonetrast-0.1.0/CHANGELOG.md +14 -0
  6. clonetrast-0.1.0/CODE_OF_CONDUCT.md +7 -0
  7. clonetrast-0.1.0/LICENSE +21 -0
  8. clonetrast-0.1.0/PKG-INFO +223 -0
  9. clonetrast-0.1.0/README.md +139 -0
  10. clonetrast-0.1.0/docs/_static/custom.css +1 -0
  11. clonetrast-0.1.0/docs/_static/images/CloneTrast_logo_for_git.png +0 -0
  12. clonetrast-0.1.0/docs/_static/images/figure_1_git.jpg +0 -0
  13. clonetrast-0.1.0/docs/_static/images/figure_2_git.jpg +0 -0
  14. clonetrast-0.1.0/docs/api/index.rst +8 -0
  15. clonetrast-0.1.0/docs/api/pp.rst +7 -0
  16. clonetrast-0.1.0/docs/api/tl.rst +7 -0
  17. clonetrast-0.1.0/docs/cli_reference.rst +51 -0
  18. clonetrast-0.1.0/docs/conf.py +168 -0
  19. clonetrast-0.1.0/docs/contrastive_loss.rst +84 -0
  20. clonetrast-0.1.0/docs/contributing.rst +47 -0
  21. clonetrast-0.1.0/docs/data_format.rst +69 -0
  22. clonetrast-0.1.0/docs/evaluation_metrics.rst +56 -0
  23. clonetrast-0.1.0/docs/index.rst +108 -0
  24. clonetrast-0.1.0/docs/installation.rst +222 -0
  25. clonetrast-0.1.0/docs/notebooks/applying_clonetrast_tutorial.ipynb +1093 -0
  26. clonetrast-0.1.0/docs/notebooks/data_preparation_tutorial.ipynb +2286 -0
  27. clonetrast-0.1.0/docs/output_format.rst +44 -0
  28. clonetrast-0.1.0/docs/requirements-docs.txt +10 -0
  29. clonetrast-0.1.0/docs/tutorials.rst +33 -0
  30. clonetrast-0.1.0/docs/user_guide.rst +14 -0
  31. clonetrast-0.1.0/docs/workflow_inference.rst +104 -0
  32. clonetrast-0.1.0/docs/workflow_train_embed.rst +72 -0
  33. clonetrast-0.1.0/pyproject.toml +145 -0
  34. clonetrast-0.1.0/src/clonetrast/__init__.py +9 -0
  35. clonetrast-0.1.0/src/clonetrast/cli.py +154 -0
  36. clonetrast-0.1.0/src/clonetrast/model/__init__.py +19 -0
  37. clonetrast-0.1.0/src/clonetrast/model/dataset.py +76 -0
  38. clonetrast-0.1.0/src/clonetrast/model/encoder.py +232 -0
  39. clonetrast-0.1.0/src/clonetrast/pp/__init__.py +15 -0
  40. clonetrast-0.1.0/src/clonetrast/pp/normalize.py +274 -0
  41. clonetrast-0.1.0/src/clonetrast/tl/__init__.py +27 -0
  42. clonetrast-0.1.0/src/clonetrast/tl/embedding.py +301 -0
  43. clonetrast-0.1.0/src/clonetrast/tl/metrics.py +261 -0
  44. clonetrast-0.1.0/src/clonetrast/tl/pretrained.py +150 -0
  45. clonetrast-0.1.0/src/clonetrast/tl/train.py +1860 -0
  46. clonetrast-0.1.0/tests/__init__.py +1 -0
  47. clonetrast-0.1.0/tests/conftest.py +63 -0
  48. clonetrast-0.1.0/tests/test_cli.py +238 -0
  49. clonetrast-0.1.0/tests/test_dataset.py +37 -0
  50. clonetrast-0.1.0/tests/test_embedding.py +161 -0
  51. clonetrast-0.1.0/tests/test_metrics.py +79 -0
  52. clonetrast-0.1.0/tests/test_model.py +176 -0
  53. clonetrast-0.1.0/tests/test_normalize_extra.py +40 -0
  54. clonetrast-0.1.0/tests/test_pp.py +66 -0
  55. clonetrast-0.1.0/tests/test_pretrained.py +285 -0
  56. clonetrast-0.1.0/tests/test_train_smoke.py +824 -0
  57. clonetrast-0.1.0/uv.lock +4965 -0
@@ -0,0 +1,102 @@
1
+ # Runs only on GitHub-hosted runners. Nothing here uses or writes the
2
+ # developer's local .venv (CUDA PyTorch included).
3
+ name: CI
4
+
5
+ on:
6
+ push:
7
+ branches: [main]
8
+ pull_request:
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ env:
19
+ UV_PROJECT_ENVIRONMENT: .venv-ci
20
+
21
+ jobs:
22
+ lint:
23
+ name: lint (${{ matrix.os }})
24
+ runs-on: ${{ matrix.os }}
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ os: [ubuntu-latest, windows-latest, macos-latest]
29
+ steps:
30
+ - uses: actions/checkout@v5
31
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
32
+ with:
33
+ python-version: "3.12"
34
+ enable-cache: true
35
+ # Ruff only — do not install torch / project deps.
36
+ - name: Install ruff from the lockfile
37
+ run: uv sync --frozen --only-group dev --no-install-project
38
+ - name: Ruff check
39
+ run: uv run --frozen --no-sync ruff check src tests
40
+
41
+ tests:
42
+ name: tests (${{ matrix.os }}, Python ${{ matrix.python-version }})
43
+ runs-on: ${{ matrix.os }}
44
+ timeout-minutes: 60
45
+ strategy:
46
+ fail-fast: false
47
+ matrix:
48
+ os: [ubuntu-latest, windows-latest, macos-latest]
49
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
50
+ steps:
51
+ - uses: actions/checkout@v5
52
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
53
+ with:
54
+ python-version: ${{ matrix.python-version }}
55
+ enable-cache: true
56
+ - name: Install package and test extras
57
+ run: uv sync --frozen --no-dev --group test
58
+ - name: Run pytest
59
+ run: uv run --frozen --no-sync pytest --cov=clonetrast --cov-report=term-missing --cov-report=xml --color=yes
60
+ - name: Upload coverage to Codecov
61
+ uses: codecov/codecov-action@v5
62
+ with:
63
+ files: coverage.xml
64
+ fail_ci_if_error: false
65
+
66
+ docs:
67
+ name: docs (${{ matrix.os }})
68
+ runs-on: ${{ matrix.os }}
69
+ timeout-minutes: 30
70
+ strategy:
71
+ fail-fast: false
72
+ matrix:
73
+ os: [ubuntu-latest, windows-latest, macos-latest]
74
+ steps:
75
+ - uses: actions/checkout@v5
76
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
77
+ with:
78
+ python-version: "3.12"
79
+ enable-cache: true
80
+ - name: Install package and docs extras
81
+ run: uv sync --frozen --no-dev --extra docs
82
+ - name: Build Sphinx HTML
83
+ run: uv run --frozen --no-sync sphinx-build -b html -T docs docs/_build/html
84
+
85
+ build:
86
+ name: build (${{ matrix.os }})
87
+ runs-on: ${{ matrix.os }}
88
+ strategy:
89
+ fail-fast: false
90
+ matrix:
91
+ os: [ubuntu-latest, windows-latest, macos-latest]
92
+ steps:
93
+ - uses: actions/checkout@v5
94
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
95
+ with:
96
+ python-version: "3.12"
97
+ enable-cache: true
98
+ - name: Build sdist and wheel
99
+ run: uv build
100
+ - name: Check metadata
101
+ shell: bash
102
+ run: uvx twine check dist/*
@@ -0,0 +1,57 @@
1
+ # Publishes to PyPI via Trusted Publishing (OIDC); no API tokens are stored.
2
+ name: Publish
3
+
4
+ on:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ build:
17
+ name: build distributions
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
22
+ with:
23
+ python-version: "3.12"
24
+ enable-cache: true
25
+ - name: Check release tag matches project version
26
+ if: github.event_name == 'release'
27
+ shell: bash
28
+ run: |
29
+ version=$(uv version --short)
30
+ tag="${GITHUB_REF_NAME#v}"
31
+ if [ "$version" != "$tag" ]; then
32
+ echo "::error::Release tag '$GITHUB_REF_NAME' does not match pyproject version '$version'"
33
+ exit 1
34
+ fi
35
+ - name: Build sdist and wheel
36
+ run: uv build
37
+ - name: Check metadata
38
+ run: uvx twine check --strict dist/*
39
+ - uses: actions/upload-artifact@v4
40
+ with:
41
+ name: dist
42
+ path: dist/
43
+ if-no-files-found: error
44
+
45
+ publish-pypi:
46
+ name: publish to PyPI
47
+ if: github.event_name == 'release'
48
+ needs: build
49
+ runs-on: ubuntu-latest
50
+ permissions:
51
+ id-token: write
52
+ steps:
53
+ - uses: actions/download-artifact@v5
54
+ with:
55
+ name: dist
56
+ path: dist/
57
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,48 @@
1
+ # Temp files
2
+ .DS_Store
3
+ *~
4
+ buck-out/
5
+
6
+ # Virtual env
7
+ .venv/
8
+ .venv-ci/
9
+ venv/
10
+ env/
11
+
12
+ # Compiled
13
+ __pycache__/
14
+ .*cache/
15
+ *.py[cod]
16
+ *.so
17
+
18
+ # Distribution / packaging
19
+ /dist/
20
+ /build/
21
+ *.egg-info/
22
+ *.egg
23
+
24
+ # Tests and coverage
25
+ /data/
26
+ /node_modules/
27
+ .coverage*
28
+ coverage.xml
29
+ htmlcov/
30
+ .pytest_cache/
31
+
32
+ # docs
33
+ docs/generated/
34
+ docs/_build/
35
+
36
+ # IDE
37
+ .idea/
38
+ .vscode/
39
+ *.swp
40
+ *.swo
41
+
42
+ # Outputs
43
+ clonetrast_out/
44
+ *.h5ad
45
+ !tests/fixtures/*.h5ad
46
+
47
+ # Notebooks
48
+ /notebooks/
@@ -0,0 +1,17 @@
1
+ # Read the Docs configuration (v2).
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html
3
+
4
+ version: 2
5
+
6
+ build:
7
+ os: ubuntu-24.04
8
+ tools:
9
+ python: "3.12"
10
+ jobs:
11
+ create_environment:
12
+ - pip install --upgrade pip
13
+ - pip install uv
14
+ - uv pip install --system -e ".[docs]"
15
+ build:
16
+ html:
17
+ - python -m sphinx -b html docs "${READTHEDOCS_OUTPUT}/html"
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0]
11
+
12
+ ### Added
13
+
14
+ - Initial public version of CloneTrast.
@@ -0,0 +1,7 @@
1
+ # Code of Conduct
2
+
3
+ CloneTrast is part of the single-cell analysis community and follows the
4
+ [scverse Code of Conduct](https://scverse.org/about/code_of_conduct/).
5
+
6
+ If you experience or witness unacceptable behavior, please report it using the
7
+ contact information on the scverse Code of Conduct page.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026, Ofir Shorer, Asaf Pinhasi, Ron Amit & Keren Yizhak.
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.
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.5
2
+ Name: clonetrast
3
+ Version: 0.1.0
4
+ Summary: Revealing pan-cancer clonal niches of T cells from single-cell RNA sequencing using contrastive learning.
5
+ Project-URL: Documentation, https://clonetrast.readthedocs.io/en/latest/
6
+ Project-URL: Homepage, https://github.com/yizhak-lab-ccg/CloneTrast
7
+ Project-URL: Repository, https://github.com/yizhak-lab-ccg/CloneTrast
8
+ Project-URL: Issues, https://github.com/yizhak-lab-ccg/CloneTrast/issues
9
+ Author-email: Ofir Shorer <ofirshorer@campus.technion.ac.il>
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026, Ofir Shorer, Asaf Pinhasi, Ron Amit & Keren Yizhak.
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Classifier: Intended Audience :: Science/Research
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3 :: Only
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
40
+ Requires-Python: <3.14,>=3.10
41
+ Requires-Dist: adjusttext
42
+ Requires-Dist: airr
43
+ Requires-Dist: anndata>=0.10
44
+ Requires-Dist: captum
45
+ Requires-Dist: colorcet
46
+ Requires-Dist: harmonypy<1,>=0.2
47
+ Requires-Dist: ipykernel
48
+ Requires-Dist: joblib
49
+ Requires-Dist: leidenalg
50
+ Requires-Dist: magic-impute
51
+ Requires-Dist: matplotlib
52
+ Requires-Dist: mudata
53
+ Requires-Dist: muon
54
+ Requires-Dist: nbformat>=5.10.4
55
+ Requires-Dist: numba>=0.61
56
+ Requires-Dist: numpy
57
+ Requires-Dist: optuna
58
+ Requires-Dist: pandas
59
+ Requires-Dist: plotly
60
+ Requires-Dist: pooch
61
+ Requires-Dist: requests
62
+ Requires-Dist: scanpy>=1.9
63
+ Requires-Dist: scikit-learn
64
+ Requires-Dist: scipy
65
+ Requires-Dist: scirpy
66
+ Requires-Dist: scrublet
67
+ Requires-Dist: seaborn
68
+ Requires-Dist: session-info2
69
+ Requires-Dist: squarify
70
+ Requires-Dist: statsmodels
71
+ Requires-Dist: torch>=2.0
72
+ Requires-Dist: tqdm
73
+ Requires-Dist: umap-learn
74
+ Provides-Extra: docs
75
+ Requires-Dist: ipython>=8.0; extra == 'docs'
76
+ Requires-Dist: myst-nb>=1.1; extra == 'docs'
77
+ Requires-Dist: myst-parser>=3.0; extra == 'docs'
78
+ Requires-Dist: sphinx-autodoc-typehints>=2.0; extra == 'docs'
79
+ Requires-Dist: sphinx-book-theme>=1.1; extra == 'docs'
80
+ Requires-Dist: sphinx-copybutton>=0.5; extra == 'docs'
81
+ Requires-Dist: sphinx<9,>=7.4; extra == 'docs'
82
+ Requires-Dist: sphinxext-opengraph>=0.9; extra == 'docs'
83
+ Description-Content-Type: text/markdown
84
+
85
+ <p align="center">
86
+ <a href="https://github.com/yizhak-lab-ccg/CloneTrast/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/yizhak-lab-ccg/CloneTrast/actions/workflows/ci.yml/badge.svg?branch=main"></a>
87
+ <a href="https://codecov.io/gh/yizhak-lab-ccg/CloneTrast"><img alt="codecov" src="https://img.shields.io/codecov/c/github/yizhak-lab-ccg/CloneTrast?logo=codecov&logoColor=white"></a>
88
+ <a href="https://clonetrast.readthedocs.io/en/latest/"><img alt="Docs" src="https://img.shields.io/readthedocs/clonetrast/latest.svg?logo=readthedocs&logoColor=white"></a>
89
+ <img alt="Python 3.10-3.13" src="https://img.shields.io/badge/Python-3.10--3.13-blue.svg?logo=python&logoColor=white">
90
+ <a href="LICENSE"><img alt="License: MIT" src="https://custom-icon-badges.demolab.com/badge/License-MIT-blue.svg?logo=law-24&logoColor=white"></a>
91
+ </p>
92
+
93
+ <p align="center">
94
+ <img src="docs/_static/images/CloneTrast_logo_for_git.png" alt="CloneTrast" width="400">
95
+ </p>
96
+
97
+ <h1 align="center">
98
+ Revealing pan-cancer clonal niches of T cells from single-cell RNA sequencing using contrastive learning
99
+ </h1>
100
+
101
+ CloneTrast maps **gene expression alone** to a latent space where cells from the same T-cell clone cluster together.
102
+ At inference you only need scRNA-seq UMI counts, without paired scTCR-seq. Public **pre-trained model** (hosted on [Figshare](https://doi.org/10.6084/m9.figshare.32228991)) is downloaded automatically on first use, with an additional complementary model used to predict clone size from gene expression alone. Following, you can visualize your data and further explore the clonal functional structure for downstream analysis.
103
+
104
+ ## Graphical description
105
+
106
+ <p align="center">
107
+ <img src="docs/_static/images/figure_1_git.jpg" alt="CloneTrast figure 1 overview" width="800">
108
+ </p>
109
+
110
+ ## Clone labels vs. TCR sequences
111
+
112
+ CloneTrast separates **how models are trained** from **how they are applied**. This distinction is central to what the embedding represents.
113
+
114
+ ### During training: categorical clone labels - not TCR sequence identity
115
+
116
+ Training requires a per-cell **`clone_id`** column: a **categorical label** that groups cells from the same T-cell clone. Those labels are **inferred from scTCR-seq** (please refer to our manuscript for more details). **Importantly**, CloneTrast is **not** trained on TCR sequences. Supervision comes only from the **clone_id category**.
117
+
118
+ ### At inference: scRNA-seq only - no scTCR-seq
119
+
120
+ When you embed new cells (with the public pre-trained model), CloneTrast reads **gene expression only**. You do **not** need scTCR-seq, CDR3 sequences, or `clone_id` labels. The model maps each cell’s transcriptome to a fixed-dimensional embedding (`X_clonetrast`).
121
+
122
+ ### What this means for the embedding space
123
+
124
+ During training, every cell with the same `clone_id` is a positive pair: the contrastive loss rewards them for being located next to each other. At inference, the encoder applies that learned mapping - **cells from the same clone are expected to cluster** in `X_clonetrast` when their expression reflects shared clonal identity.
125
+
126
+ This specific modeling approach results in a distinct embedding space capturing multiple components of clonal organization:
127
+
128
+ **(1) Different clones, similar functional states:** Two clones defined by different TCR sequences can be positioned near one another if they share similar functional status.
129
+
130
+ **(2) Same clone, divergent states:** T cells belonging to the same clone are pulled toward one another despite having diverse differentiation states due to intra-clonal transcriptional heterogeneity.
131
+
132
+ **(3) Same TCR sequence, different functional states:** Two clones with identical TCR sequences but distinct clonal identities, because they originate from different patients, can be positioned far apart if they exhibit different functional states.
133
+
134
+ ## Training and inference description
135
+
136
+ <p align="center">
137
+ <img src="docs/_static/images/figure_2_git.jpg" alt="CloneTrast figure 2 overview" width="800">
138
+ </p>
139
+
140
+ ## Installation
141
+
142
+ For complete installation instructions including prerequisites, package installation, and development setup, please see the [Installation Guide](https://clonetrast.readthedocs.io/en/latest/installation.html).
143
+
144
+ ## Quick start - inference with pre-trained models
145
+
146
+ You only need **gene expression (scRNA-seq)**. CloneTrast does **not** use scTCR-seq or TCR sequences at inference - see [Clone labels vs. TCR sequences](#clone-labels-vs-tcr-sequences---what-clonetrast-actually-uses) above. Optional `clone_id` labels are for coloring plots or computing metrics only.
147
+
148
+ ### Pre-trained models
149
+
150
+ The pre-trained models expect **Ensembl gene IDs** in `adata.var_names` (e.g. `ENSG00000156234`). Input genes are automatically aligned to the training gene list (11,950 genes): missing genes are set to zero (thus mimicking sequencing drop-outs), extra genes are dropped.
151
+
152
+ ### Data format (inference)
153
+
154
+ - AnnData with gene expression (cells × genes), e.g. raw UMI counts in `adata.X`. Raw counts require subsequent row-normalization and log-transformation, as described below.
155
+ - `adata.var_names`: **Ensembl IDs** for compatibility with the public checkpoints.
156
+ - **Optional:** `adata.obs['clone_id']` for visualization or evaluation (not required to run the model).
157
+ - **Importantly:** the model was trained using T cells alone. It is therefore required to ensure your data includes only T cells as input.
158
+
159
+ ### Python API
160
+
161
+ ```python
162
+ import scanpy as sc
163
+ import clonetrast as ct
164
+
165
+ # These are raw UMI counts
166
+ adata = sc.read_h5ad("your_data.h5ad")
167
+
168
+ # Raw counts should be subsequently normalized
169
+ sc.pp.normalize_total(adata, target_sum = 1e4)
170
+ sc.pp.log1p(adata)
171
+
172
+ # Applying the contrastive model and creating a two-dimensional representation with UMAP
173
+ ct.tl.embed(
174
+ adata,
175
+ use_pretrained=True, # default; downloads contrastive model on first run
176
+ device="cuda", # or "cpu"
177
+ )
178
+ ct.tl.compute_umap(adata, obsm_key="X_clonetrast", umap_key="X_umap_clonetrast")
179
+
180
+ # Optional complementary model to predict log clone size per cell
181
+ ct.tl.predict_clone_size(adata, use_pretrained=True, device="cuda")
182
+
183
+ # Visualize
184
+ sc.pl.embedding(adata, basis="umap_clonetrast", color=["predicted_clone_size"])
185
+ ```
186
+
187
+ Embeddings are stored in `adata.obsm['X_clonetrast']`; UMAP coordinates in `adata.obsm['X_umap_clonetrast']`.
188
+
189
+ ## Tutorial notebooks
190
+
191
+ Two step-by-step tutorials:
192
+
193
+ 1. **[Data preparation](https://clonetrast.readthedocs.io/en/latest/notebooks/data_preparation_tutorial.html)** - prepare paired scRNA/TCR-seq data for training (QC, T-cell subtyping, clone labeling, export)
194
+ 2. **[Applying CloneTrast](https://clonetrast.readthedocs.io/en/latest/notebooks/applying_clonetrast_tutorial.html)** - apply CloneTrast to gene expression alone (embed, predict clone size, visualize and compare to a standard UMAP)
195
+
196
+ ## Documentation
197
+
198
+ [Full documentation](https://clonetrast.readthedocs.io/en/latest/) (includes the [contrastive loss reference](https://clonetrast.readthedocs.io/en/latest/contrastive_loss.html) and [tutorials](https://clonetrast.readthedocs.io/en/latest/tutorials.html)).
199
+
200
+ ## License
201
+
202
+ This project is licensed under the MIT License - see the LICENSE file for more details.
203
+
204
+ ## Citation
205
+
206
+ Reference will be added here when available.
207
+
208
+ ## Acknowledgements
209
+
210
+ CloneTrast's logo, the project's graphical description, and the graphical description of the training and inference, were created with [BioRender.com](https://www.biorender.com/) using a paid license.
211
+
212
+ </details>
213
+
214
+ ---
215
+
216
+ <div align="center">
217
+ <p><em>This project was created in favor of the scientific community worldwide, with a special dedication to the cancer research community.</em></p>
218
+ <p><em>We hope you'll find this repository helpful, and we warmly welcome any requests or suggestions - please don't hesitate to reach out!</em></p>
219
+
220
+ <a href="https://mapmyvisitors.com/web/1c8l2">
221
+ <img src="https://mapmyvisitors.com/map.png?d=dwfyT67_zJfn-BQ-6x-NAaKvey45Vl66GhWHhFcDZHw&cl=ffffff" alt="Visitor Map">
222
+ </a>
223
+ </div>
@@ -0,0 +1,139 @@
1
+ <p align="center">
2
+ <a href="https://github.com/yizhak-lab-ccg/CloneTrast/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/yizhak-lab-ccg/CloneTrast/actions/workflows/ci.yml/badge.svg?branch=main"></a>
3
+ <a href="https://codecov.io/gh/yizhak-lab-ccg/CloneTrast"><img alt="codecov" src="https://img.shields.io/codecov/c/github/yizhak-lab-ccg/CloneTrast?logo=codecov&logoColor=white"></a>
4
+ <a href="https://clonetrast.readthedocs.io/en/latest/"><img alt="Docs" src="https://img.shields.io/readthedocs/clonetrast/latest.svg?logo=readthedocs&logoColor=white"></a>
5
+ <img alt="Python 3.10-3.13" src="https://img.shields.io/badge/Python-3.10--3.13-blue.svg?logo=python&logoColor=white">
6
+ <a href="LICENSE"><img alt="License: MIT" src="https://custom-icon-badges.demolab.com/badge/License-MIT-blue.svg?logo=law-24&logoColor=white"></a>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <img src="docs/_static/images/CloneTrast_logo_for_git.png" alt="CloneTrast" width="400">
11
+ </p>
12
+
13
+ <h1 align="center">
14
+ Revealing pan-cancer clonal niches of T cells from single-cell RNA sequencing using contrastive learning
15
+ </h1>
16
+
17
+ CloneTrast maps **gene expression alone** to a latent space where cells from the same T-cell clone cluster together.
18
+ At inference you only need scRNA-seq UMI counts, without paired scTCR-seq. Public **pre-trained model** (hosted on [Figshare](https://doi.org/10.6084/m9.figshare.32228991)) is downloaded automatically on first use, with an additional complementary model used to predict clone size from gene expression alone. Following, you can visualize your data and further explore the clonal functional structure for downstream analysis.
19
+
20
+ ## Graphical description
21
+
22
+ <p align="center">
23
+ <img src="docs/_static/images/figure_1_git.jpg" alt="CloneTrast figure 1 overview" width="800">
24
+ </p>
25
+
26
+ ## Clone labels vs. TCR sequences
27
+
28
+ CloneTrast separates **how models are trained** from **how they are applied**. This distinction is central to what the embedding represents.
29
+
30
+ ### During training: categorical clone labels - not TCR sequence identity
31
+
32
+ Training requires a per-cell **`clone_id`** column: a **categorical label** that groups cells from the same T-cell clone. Those labels are **inferred from scTCR-seq** (please refer to our manuscript for more details). **Importantly**, CloneTrast is **not** trained on TCR sequences. Supervision comes only from the **clone_id category**.
33
+
34
+ ### At inference: scRNA-seq only - no scTCR-seq
35
+
36
+ When you embed new cells (with the public pre-trained model), CloneTrast reads **gene expression only**. You do **not** need scTCR-seq, CDR3 sequences, or `clone_id` labels. The model maps each cell’s transcriptome to a fixed-dimensional embedding (`X_clonetrast`).
37
+
38
+ ### What this means for the embedding space
39
+
40
+ During training, every cell with the same `clone_id` is a positive pair: the contrastive loss rewards them for being located next to each other. At inference, the encoder applies that learned mapping - **cells from the same clone are expected to cluster** in `X_clonetrast` when their expression reflects shared clonal identity.
41
+
42
+ This specific modeling approach results in a distinct embedding space capturing multiple components of clonal organization:
43
+
44
+ **(1) Different clones, similar functional states:** Two clones defined by different TCR sequences can be positioned near one another if they share similar functional status.
45
+
46
+ **(2) Same clone, divergent states:** T cells belonging to the same clone are pulled toward one another despite having diverse differentiation states due to intra-clonal transcriptional heterogeneity.
47
+
48
+ **(3) Same TCR sequence, different functional states:** Two clones with identical TCR sequences but distinct clonal identities, because they originate from different patients, can be positioned far apart if they exhibit different functional states.
49
+
50
+ ## Training and inference description
51
+
52
+ <p align="center">
53
+ <img src="docs/_static/images/figure_2_git.jpg" alt="CloneTrast figure 2 overview" width="800">
54
+ </p>
55
+
56
+ ## Installation
57
+
58
+ For complete installation instructions including prerequisites, package installation, and development setup, please see the [Installation Guide](https://clonetrast.readthedocs.io/en/latest/installation.html).
59
+
60
+ ## Quick start - inference with pre-trained models
61
+
62
+ You only need **gene expression (scRNA-seq)**. CloneTrast does **not** use scTCR-seq or TCR sequences at inference - see [Clone labels vs. TCR sequences](#clone-labels-vs-tcr-sequences---what-clonetrast-actually-uses) above. Optional `clone_id` labels are for coloring plots or computing metrics only.
63
+
64
+ ### Pre-trained models
65
+
66
+ The pre-trained models expect **Ensembl gene IDs** in `adata.var_names` (e.g. `ENSG00000156234`). Input genes are automatically aligned to the training gene list (11,950 genes): missing genes are set to zero (thus mimicking sequencing drop-outs), extra genes are dropped.
67
+
68
+ ### Data format (inference)
69
+
70
+ - AnnData with gene expression (cells × genes), e.g. raw UMI counts in `adata.X`. Raw counts require subsequent row-normalization and log-transformation, as described below.
71
+ - `adata.var_names`: **Ensembl IDs** for compatibility with the public checkpoints.
72
+ - **Optional:** `adata.obs['clone_id']` for visualization or evaluation (not required to run the model).
73
+ - **Importantly:** the model was trained using T cells alone. It is therefore required to ensure your data includes only T cells as input.
74
+
75
+ ### Python API
76
+
77
+ ```python
78
+ import scanpy as sc
79
+ import clonetrast as ct
80
+
81
+ # These are raw UMI counts
82
+ adata = sc.read_h5ad("your_data.h5ad")
83
+
84
+ # Raw counts should be subsequently normalized
85
+ sc.pp.normalize_total(adata, target_sum = 1e4)
86
+ sc.pp.log1p(adata)
87
+
88
+ # Applying the contrastive model and creating a two-dimensional representation with UMAP
89
+ ct.tl.embed(
90
+ adata,
91
+ use_pretrained=True, # default; downloads contrastive model on first run
92
+ device="cuda", # or "cpu"
93
+ )
94
+ ct.tl.compute_umap(adata, obsm_key="X_clonetrast", umap_key="X_umap_clonetrast")
95
+
96
+ # Optional complementary model to predict log clone size per cell
97
+ ct.tl.predict_clone_size(adata, use_pretrained=True, device="cuda")
98
+
99
+ # Visualize
100
+ sc.pl.embedding(adata, basis="umap_clonetrast", color=["predicted_clone_size"])
101
+ ```
102
+
103
+ Embeddings are stored in `adata.obsm['X_clonetrast']`; UMAP coordinates in `adata.obsm['X_umap_clonetrast']`.
104
+
105
+ ## Tutorial notebooks
106
+
107
+ Two step-by-step tutorials:
108
+
109
+ 1. **[Data preparation](https://clonetrast.readthedocs.io/en/latest/notebooks/data_preparation_tutorial.html)** - prepare paired scRNA/TCR-seq data for training (QC, T-cell subtyping, clone labeling, export)
110
+ 2. **[Applying CloneTrast](https://clonetrast.readthedocs.io/en/latest/notebooks/applying_clonetrast_tutorial.html)** - apply CloneTrast to gene expression alone (embed, predict clone size, visualize and compare to a standard UMAP)
111
+
112
+ ## Documentation
113
+
114
+ [Full documentation](https://clonetrast.readthedocs.io/en/latest/) (includes the [contrastive loss reference](https://clonetrast.readthedocs.io/en/latest/contrastive_loss.html) and [tutorials](https://clonetrast.readthedocs.io/en/latest/tutorials.html)).
115
+
116
+ ## License
117
+
118
+ This project is licensed under the MIT License - see the LICENSE file for more details.
119
+
120
+ ## Citation
121
+
122
+ Reference will be added here when available.
123
+
124
+ ## Acknowledgements
125
+
126
+ CloneTrast's logo, the project's graphical description, and the graphical description of the training and inference, were created with [BioRender.com](https://www.biorender.com/) using a paid license.
127
+
128
+ </details>
129
+
130
+ ---
131
+
132
+ <div align="center">
133
+ <p><em>This project was created in favor of the scientific community worldwide, with a special dedication to the cancer research community.</em></p>
134
+ <p><em>We hope you'll find this repository helpful, and we warmly welcome any requests or suggestions - please don't hesitate to reach out!</em></p>
135
+
136
+ <a href="https://mapmyvisitors.com/web/1c8l2">
137
+ <img src="https://mapmyvisitors.com/map.png?d=dwfyT67_zJfn-BQ-6x-NAaKvey45Vl66GhWHhFcDZHw&cl=ffffff" alt="Visitor Map">
138
+ </a>
139
+ </div>
@@ -0,0 +1 @@
1
+ /* Optional theme tweaks for CloneTrast docs. */
@@ -0,0 +1,8 @@
1
+ API reference
2
+ =============
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+
7
+ pp
8
+ tl
@@ -0,0 +1,7 @@
1
+ ``clonetrast.pp``
2
+ =================
3
+
4
+ .. automodule:: clonetrast.pp
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ ``clonetrast.tl``
2
+ =================
3
+
4
+ .. automodule:: clonetrast.tl
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance: