sampledisco 0.2.0__tar.gz → 0.4.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.
- {sampledisco-0.2.0/src/sampledisco.egg-info → sampledisco-0.4.0}/PKG-INFO +49 -43
- {sampledisco-0.2.0 → sampledisco-0.4.0}/README.md +47 -41
- {sampledisco-0.2.0 → sampledisco-0.4.0}/pyproject.toml +1 -1
- {sampledisco-0.2.0 → sampledisco-0.4.0}/requirements.txt +3 -3
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/cli.py +14 -1
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/config/config_demo.yaml +12 -9
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/parameter_selection/autotune.py +130 -60
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/ATAC_cell_type.py +6 -3
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/ATAC_cell_type_gpu.py +7 -4
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/atac_preprocess_cpu.py +10 -7
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/atac_preprocess_gpu.py +10 -7
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/cell_type_cpu.py +12 -10
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/cell_type_gpu.py +12 -10
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_batch_correction.py +19 -12
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_cell_type_cpu.py +7 -6
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_cell_type_gpu.py +6 -4
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_glue.py +25 -14
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_merge.py +5 -4
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/rna_preprocess_cpu.py +10 -7
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/rna_preprocess_gpu.py +10 -7
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_association/association.py +2 -2
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/sample_distance.py +18 -18
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_embedding/__init__.py +8 -2
- sampledisco-0.4.0/src/sampledisco/sample_embedding/blocks.py +913 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_embedding/sample_embedding.py +88 -73
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_embedding/sample_embedding_gpu.py +94 -78
- sampledisco-0.4.0/src/sampledisco/utils/embedding_keys.py +189 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/multi_omics_visualization.py +2 -2
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/visualization_other.py +4 -4
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/atac_wrapper.py +11 -7
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/multiomics_wrapper.py +53 -63
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/rna_wrapper.py +11 -7
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/wrapper.py +44 -22
- {sampledisco-0.2.0 → sampledisco-0.4.0/src/sampledisco.egg-info}/PKG-INFO +49 -43
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/SOURCES.txt +5 -1
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/requires.txt +1 -1
- sampledisco-0.4.0/tests/test_config_validation.py +54 -0
- sampledisco-0.4.0/tests/test_inplace_uns_and_equal_weight.py +186 -0
- sampledisco-0.4.0/tests/test_sample_embedding_equivalence.py +148 -0
- sampledisco-0.2.0/src/sampledisco/sample_embedding/blocks.py +0 -541
- {sampledisco-0.2.0 → sampledisco-0.4.0}/LICENSE +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/setup.cfg +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_ArchR.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_RNA_harmony.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_gene_activity.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_peak_annotation.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/RNA_name_convertor.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/pseudo_correlation.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/test_pseudo_correlation.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/validation.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/parameter_selection/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_association/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/RAISIN.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/RAISIN_TEST.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/cluster.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/cluster_severity_reconcile.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/proportion_test.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/ChiSquare.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/distance_test.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/jensenshannon.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/CCA.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/CCA_test.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/TSCAN.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/trajectory_DGE_visualization.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/trajectory_diff_gene.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/Grouping.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/batch_regress.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/harmony_compat.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/imbalance_cell_type_handler.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/inspector.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/limma.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/merge_sample_meta.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/random_seed.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/safe_save.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/slim_adata.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/subsample.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/subsample_generator.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/tf_idf.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/unify_optimal.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/ATAC_visualization.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/DEG_visualization.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/visualization_embedding.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/visualization_helper.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/__init__.py +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/dependency_links.txt +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/entry_points.txt +0 -0
- {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sampledisco
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Cross-omics, cross-condition sample embedding for single-cell data (RNA + ATAC)
|
|
5
5
|
Author: Hongkai Ji
|
|
6
6
|
Author-email: Harry Jiang <hjiang55@jh.edu>
|
|
@@ -28,7 +28,7 @@ Requires-Dist: patsy>=0.5
|
|
|
28
28
|
Requires-Dist: scanpy>=1.11
|
|
29
29
|
Requires-Dist: anndata>=0.10
|
|
30
30
|
Requires-Dist: muon>=0.1
|
|
31
|
-
Requires-Dist: harmonypy
|
|
31
|
+
Requires-Dist: harmonypy==0.2.0
|
|
32
32
|
Requires-Dist: python-igraph>=0.10
|
|
33
33
|
Requires-Dist: leidenalg>=0.9
|
|
34
34
|
Requires-Dist: networkx>=3.0
|
|
@@ -51,7 +51,7 @@ A cross-omics, cross-condition **sample embedding** tool for single-cell data.
|
|
|
51
51
|
|
|
52
52
|
SampleDisco takes a cell-level embedding (from any standard scRNA / scATAC / multi-omics integration method) and lifts it to a **sample-level embedding** that captures both cell-type composition and the per-cell-type state of each sample. Every downstream analysis — sample-to-sample distance, clustering, trajectory inference, phenotype association — then runs on that single shared sample embedding, regardless of modality.
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
Documentation and tutorial: <https://j041120h.github.io/SampleDisco_tutorial/>
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -61,15 +61,15 @@ For each modality (RNA, ATAC, or integrated multi-omics) the pipeline produces t
|
|
|
61
61
|
|
|
62
62
|
| Key | Role | Source |
|
|
63
63
|
|---|---|---|
|
|
64
|
-
| **`
|
|
65
|
-
| **`
|
|
64
|
+
| **`Z_comp`** | sample-removed embedding — used for cell typing and the composition blocks | Harmony (single-omics) / Harmony post-pass on scGLUE (multi-omics) |
|
|
65
|
+
| **`Z_rmd`** | sample-preserved embedding — used for the reference-relative mean displacement (RMD) block | second Harmony pass (single-omics) / scGLUE primary output (multi-omics) |
|
|
66
66
|
|
|
67
67
|
It then assembles **four blocks** per sample (or per sample × modality for multi-omics):
|
|
68
68
|
|
|
69
69
|
1. **A1** — one-hot cell-type composition
|
|
70
70
|
2. **A2** — soft k-means composition at K_med (≈120)
|
|
71
71
|
3. **A3** — soft k-means composition at K_fine (≈300)
|
|
72
|
-
4. **
|
|
72
|
+
4. **RMD** — leave-one-out cell-type-resolved displacement on `Z_rmd`
|
|
73
73
|
|
|
74
74
|
The four blocks are inverse-variance weighted, Frobenius-stacked, PCA-reduced to 10 dimensions, and Harmony-corrected at sample level. The result is stored as `adata.uns['X_DR_sample']` and feeds every downstream module.
|
|
75
75
|
|
|
@@ -79,46 +79,50 @@ The four blocks are inverse-variance weighted, Frobenius-stacked, PCA-reduced to
|
|
|
79
79
|
|
|
80
80
|
```
|
|
81
81
|
code/
|
|
82
|
-
├──
|
|
83
|
-
├── config/
|
|
84
|
-
├──
|
|
85
|
-
│ ├──
|
|
86
|
-
│ ├──
|
|
87
|
-
│ ├──
|
|
88
|
-
│
|
|
89
|
-
├──
|
|
90
|
-
│ ├──
|
|
91
|
-
│
|
|
92
|
-
│ ├──
|
|
93
|
-
│ ├──
|
|
94
|
-
│ ├──
|
|
95
|
-
│ ├──
|
|
96
|
-
│ ├──
|
|
97
|
-
│
|
|
98
|
-
├──
|
|
99
|
-
│ ├──
|
|
100
|
-
│
|
|
101
|
-
│
|
|
102
|
-
├──
|
|
103
|
-
│
|
|
104
|
-
|
|
105
|
-
├──
|
|
106
|
-
|
|
107
|
-
├──
|
|
108
|
-
├──
|
|
109
|
-
├──
|
|
110
|
-
├──
|
|
111
|
-
|
|
82
|
+
├── pyproject.toml # package metadata; `pip install -e .` installs the `sampledisco` command
|
|
83
|
+
├── config/ # 10 YAML configs for the paper's datasets: covid / blood (1M-scBloodNL) / eye / heart / ENCODE / healthy-aging PBMC / long_covid / unpaired (+ RNA-tuned) / default
|
|
84
|
+
├── src/sampledisco/ # the package
|
|
85
|
+
│ ├── cli.py # `sampledisco` command: `-m complex --config <yaml>`, `--init-config <path>`
|
|
86
|
+
│ ├── config/config_demo.yaml # demo config written by `sampledisco --init-config`
|
|
87
|
+
│ ├── wrapper/ # Orchestration
|
|
88
|
+
│ │ ├── wrapper.py # Master wrapper; gates RNA + ATAC + multiomics + shared downstream
|
|
89
|
+
│ │ ├── rna_wrapper.py
|
|
90
|
+
│ │ ├── atac_wrapper.py
|
|
91
|
+
│ │ └── multiomics_wrapper.py
|
|
92
|
+
│ ├── preparation/ # Preprocessing
|
|
93
|
+
│ │ ├── rna_preprocess_{cpu,gpu}.py # QC → HVG → PCA → dual Harmony → Z_comp + Z_rmd
|
|
94
|
+
│ │ ├── atac_preprocess_{cpu,gpu}.py # QC → TF-IDF → HVF → LSI → dual Harmony → Z_comp + Z_rmd
|
|
95
|
+
│ │ ├── cell_type_{cpu,gpu}.py # Leiden clustering on Z_comp (RNA or ATAC)
|
|
96
|
+
│ │ ├── ATAC_cell_type{,_gpu}.py # ATAC-specific cell typing variants
|
|
97
|
+
│ │ ├── multi_omics_glue.py # scGLUE integration (cross-modality VAE + guidance graph)
|
|
98
|
+
│ │ ├── multi_omics_batch_correction.py # Harmony post-pass on X_glue → Z_comp
|
|
99
|
+
│ │ ├── multi_omics_merge.py # post-GLUE merge + per-modality preprocess/slimming
|
|
100
|
+
│ │ └── multi_omics_cell_type_{cpu,gpu}.py # RNA-Leiden + k-NN label transfer to ATAC
|
|
101
|
+
│ ├── sample_embedding/ # Core method
|
|
102
|
+
│ │ ├── blocks.py # composition, RMD, weighting, Frobenius stack, final PCA + Harmony
|
|
103
|
+
│ │ ├── sample_embedding.py # CPU pipeline
|
|
104
|
+
│ │ └── sample_embedding_gpu.py # GPU pipeline (cuML + cupy)
|
|
105
|
+
│ ├── parameter_selection/
|
|
106
|
+
│ │ └── autotune.py # Bayesian GP sweep over RMD α; adaptive proxy ensemble
|
|
107
|
+
│ ├── sample_distance/ # Pairwise sample distances (DR / EMD / chi-square / JS)
|
|
108
|
+
│ ├── sample_clustering/ # Hierarchical (HRA / HRC / NN / UPGMA / consensus), K-means, proportion test, RAISIN
|
|
109
|
+
│ ├── sample_trajectory/ # CCA (supervised) and TSCAN (unsupervised) + GAM-based trajectory DGE
|
|
110
|
+
│ ├── sample_association/ # Per-PC variance explained vs sample-level covariates (permutation FDR)
|
|
111
|
+
│ ├── visualization/ # Embedding plots, dendrograms, DGE volcanos, modality-aware multi-omics scatters
|
|
112
|
+
│ ├── utils/ # Shared helpers: seed, safe h5ad I/O, limma, TF-IDF, batch regress, Grouping
|
|
113
|
+
│ └── gene_activity/ # ATAC peak → gene activity inference + RNA-ATAC validation
|
|
114
|
+
├── Benchmark_covid/, Benchmark_multiomics/ # benchmark drivers used for the paper
|
|
115
|
+
└── claude/ # one-off run scripts (rerun launchers, monitored runs, parameter sweeps)
|
|
112
116
|
```
|
|
113
117
|
|
|
114
118
|
---
|
|
115
119
|
|
|
116
120
|
## Usage
|
|
117
121
|
|
|
118
|
-
###
|
|
122
|
+
### Run — YAML-driven
|
|
119
123
|
|
|
120
124
|
```bash
|
|
121
|
-
|
|
125
|
+
sampledisco -m complex --config config/config.yaml # same as: python -m sampledisco.cli -m complex --config ...
|
|
122
126
|
```
|
|
123
127
|
|
|
124
128
|
The YAML drives every flag and parameter for all three pipelines:
|
|
@@ -128,14 +132,16 @@ The YAML drives every flag and parameter for all three pipelines:
|
|
|
128
132
|
- **Per-modality downstream gates** (Phase 2): `*_sample_distance_calculation`, `*_trajectory_analysis`, `*_trajectory_dge`, `*_sample_cluster`, `*_proportion_test`, `*_cluster_dge`, `*_visualize_data`, `*_dimension_association_analysis`
|
|
129
133
|
- **Multi-omics-specific**: `multiomics_run_glue_*`, `multiomics_treat_sample_as_batch`, `multiomics_run_glue_twice_for_sample_removal`
|
|
130
134
|
|
|
131
|
-
The
|
|
135
|
+
The 10 ready-to-use configs in `config/` are point-in-time snapshots for the datasets used in the paper; copy one and adjust paths / column names for your own data.
|
|
132
136
|
|
|
133
|
-
###
|
|
137
|
+
### Starter config
|
|
134
138
|
|
|
135
139
|
```bash
|
|
136
|
-
|
|
140
|
+
sampledisco --init-config my_config.yaml
|
|
137
141
|
```
|
|
138
142
|
|
|
143
|
+
writes the demo config (tuned for the Zenodo demo dataset) to `my_config.yaml`. The YAML is validated against every `wrapper()` parameter, so edit values rather than deleting keys.
|
|
144
|
+
|
|
139
145
|
---
|
|
140
146
|
|
|
141
147
|
## Inputs
|
|
@@ -165,7 +171,7 @@ For multi-omics, the pipeline takes two separate h5ads (RNA + ATAC) and integrat
|
|
|
165
171
|
├── atac/ (parallel structure)
|
|
166
172
|
├── multiomics/
|
|
167
173
|
│ ├── integration/glue/{rna-pp,atac-pp,guidance.graphml.gz}
|
|
168
|
-
│ ├── preprocess/adata_sample.h5ad # post-GLUE merged adata with
|
|
174
|
+
│ ├── preprocess/adata_sample.h5ad # post-GLUE merged adata with Z_comp + Z_rmd
|
|
169
175
|
│ ├── sample_embedding/sample_embedding.csv
|
|
170
176
|
│ └── (same downstream subdirs as single-omics)
|
|
171
177
|
└── sys_log/main_process_status.json # which stages completed
|
|
@@ -182,7 +188,7 @@ detects and uses them at runtime. There is no separate "GPU build" of SampleDisc
|
|
|
182
188
|
### 1. Core install (CPU)
|
|
183
189
|
|
|
184
190
|
```bash
|
|
185
|
-
pip install sampledisco #
|
|
191
|
+
pip install sampledisco # or `pip install -e .` from a clone
|
|
186
192
|
```
|
|
187
193
|
|
|
188
194
|
### 2. System prerequisite — bedtools
|
|
@@ -4,7 +4,7 @@ A cross-omics, cross-condition **sample embedding** tool for single-cell data.
|
|
|
4
4
|
|
|
5
5
|
SampleDisco takes a cell-level embedding (from any standard scRNA / scATAC / multi-omics integration method) and lifts it to a **sample-level embedding** that captures both cell-type composition and the per-cell-type state of each sample. Every downstream analysis — sample-to-sample distance, clustering, trajectory inference, phenotype association — then runs on that single shared sample embedding, regardless of modality.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Documentation and tutorial: <https://j041120h.github.io/SampleDisco_tutorial/>
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -14,15 +14,15 @@ For each modality (RNA, ATAC, or integrated multi-omics) the pipeline produces t
|
|
|
14
14
|
|
|
15
15
|
| Key | Role | Source |
|
|
16
16
|
|---|---|---|
|
|
17
|
-
| **`
|
|
18
|
-
| **`
|
|
17
|
+
| **`Z_comp`** | sample-removed embedding — used for cell typing and the composition blocks | Harmony (single-omics) / Harmony post-pass on scGLUE (multi-omics) |
|
|
18
|
+
| **`Z_rmd`** | sample-preserved embedding — used for the reference-relative mean displacement (RMD) block | second Harmony pass (single-omics) / scGLUE primary output (multi-omics) |
|
|
19
19
|
|
|
20
20
|
It then assembles **four blocks** per sample (or per sample × modality for multi-omics):
|
|
21
21
|
|
|
22
22
|
1. **A1** — one-hot cell-type composition
|
|
23
23
|
2. **A2** — soft k-means composition at K_med (≈120)
|
|
24
24
|
3. **A3** — soft k-means composition at K_fine (≈300)
|
|
25
|
-
4. **
|
|
25
|
+
4. **RMD** — leave-one-out cell-type-resolved displacement on `Z_rmd`
|
|
26
26
|
|
|
27
27
|
The four blocks are inverse-variance weighted, Frobenius-stacked, PCA-reduced to 10 dimensions, and Harmony-corrected at sample level. The result is stored as `adata.uns['X_DR_sample']` and feeds every downstream module.
|
|
28
28
|
|
|
@@ -32,46 +32,50 @@ The four blocks are inverse-variance weighted, Frobenius-stacked, PCA-reduced to
|
|
|
32
32
|
|
|
33
33
|
```
|
|
34
34
|
code/
|
|
35
|
-
├──
|
|
36
|
-
├── config/
|
|
37
|
-
├──
|
|
38
|
-
│ ├──
|
|
39
|
-
│ ├──
|
|
40
|
-
│ ├──
|
|
41
|
-
│
|
|
42
|
-
├──
|
|
43
|
-
│ ├──
|
|
44
|
-
│
|
|
45
|
-
│ ├──
|
|
46
|
-
│ ├──
|
|
47
|
-
│ ├──
|
|
48
|
-
│ ├──
|
|
49
|
-
│ ├──
|
|
50
|
-
│
|
|
51
|
-
├──
|
|
52
|
-
│ ├──
|
|
53
|
-
│
|
|
54
|
-
│
|
|
55
|
-
├──
|
|
56
|
-
│
|
|
57
|
-
|
|
58
|
-
├──
|
|
59
|
-
|
|
60
|
-
├──
|
|
61
|
-
├──
|
|
62
|
-
├──
|
|
63
|
-
├──
|
|
64
|
-
|
|
35
|
+
├── pyproject.toml # package metadata; `pip install -e .` installs the `sampledisco` command
|
|
36
|
+
├── config/ # 10 YAML configs for the paper's datasets: covid / blood (1M-scBloodNL) / eye / heart / ENCODE / healthy-aging PBMC / long_covid / unpaired (+ RNA-tuned) / default
|
|
37
|
+
├── src/sampledisco/ # the package
|
|
38
|
+
│ ├── cli.py # `sampledisco` command: `-m complex --config <yaml>`, `--init-config <path>`
|
|
39
|
+
│ ├── config/config_demo.yaml # demo config written by `sampledisco --init-config`
|
|
40
|
+
│ ├── wrapper/ # Orchestration
|
|
41
|
+
│ │ ├── wrapper.py # Master wrapper; gates RNA + ATAC + multiomics + shared downstream
|
|
42
|
+
│ │ ├── rna_wrapper.py
|
|
43
|
+
│ │ ├── atac_wrapper.py
|
|
44
|
+
│ │ └── multiomics_wrapper.py
|
|
45
|
+
│ ├── preparation/ # Preprocessing
|
|
46
|
+
│ │ ├── rna_preprocess_{cpu,gpu}.py # QC → HVG → PCA → dual Harmony → Z_comp + Z_rmd
|
|
47
|
+
│ │ ├── atac_preprocess_{cpu,gpu}.py # QC → TF-IDF → HVF → LSI → dual Harmony → Z_comp + Z_rmd
|
|
48
|
+
│ │ ├── cell_type_{cpu,gpu}.py # Leiden clustering on Z_comp (RNA or ATAC)
|
|
49
|
+
│ │ ├── ATAC_cell_type{,_gpu}.py # ATAC-specific cell typing variants
|
|
50
|
+
│ │ ├── multi_omics_glue.py # scGLUE integration (cross-modality VAE + guidance graph)
|
|
51
|
+
│ │ ├── multi_omics_batch_correction.py # Harmony post-pass on X_glue → Z_comp
|
|
52
|
+
│ │ ├── multi_omics_merge.py # post-GLUE merge + per-modality preprocess/slimming
|
|
53
|
+
│ │ └── multi_omics_cell_type_{cpu,gpu}.py # RNA-Leiden + k-NN label transfer to ATAC
|
|
54
|
+
│ ├── sample_embedding/ # Core method
|
|
55
|
+
│ │ ├── blocks.py # composition, RMD, weighting, Frobenius stack, final PCA + Harmony
|
|
56
|
+
│ │ ├── sample_embedding.py # CPU pipeline
|
|
57
|
+
│ │ └── sample_embedding_gpu.py # GPU pipeline (cuML + cupy)
|
|
58
|
+
│ ├── parameter_selection/
|
|
59
|
+
│ │ └── autotune.py # Bayesian GP sweep over RMD α; adaptive proxy ensemble
|
|
60
|
+
│ ├── sample_distance/ # Pairwise sample distances (DR / EMD / chi-square / JS)
|
|
61
|
+
│ ├── sample_clustering/ # Hierarchical (HRA / HRC / NN / UPGMA / consensus), K-means, proportion test, RAISIN
|
|
62
|
+
│ ├── sample_trajectory/ # CCA (supervised) and TSCAN (unsupervised) + GAM-based trajectory DGE
|
|
63
|
+
│ ├── sample_association/ # Per-PC variance explained vs sample-level covariates (permutation FDR)
|
|
64
|
+
│ ├── visualization/ # Embedding plots, dendrograms, DGE volcanos, modality-aware multi-omics scatters
|
|
65
|
+
│ ├── utils/ # Shared helpers: seed, safe h5ad I/O, limma, TF-IDF, batch regress, Grouping
|
|
66
|
+
│ └── gene_activity/ # ATAC peak → gene activity inference + RNA-ATAC validation
|
|
67
|
+
├── Benchmark_covid/, Benchmark_multiomics/ # benchmark drivers used for the paper
|
|
68
|
+
└── claude/ # one-off run scripts (rerun launchers, monitored runs, parameter sweeps)
|
|
65
69
|
```
|
|
66
70
|
|
|
67
71
|
---
|
|
68
72
|
|
|
69
73
|
## Usage
|
|
70
74
|
|
|
71
|
-
###
|
|
75
|
+
### Run — YAML-driven
|
|
72
76
|
|
|
73
77
|
```bash
|
|
74
|
-
|
|
78
|
+
sampledisco -m complex --config config/config.yaml # same as: python -m sampledisco.cli -m complex --config ...
|
|
75
79
|
```
|
|
76
80
|
|
|
77
81
|
The YAML drives every flag and parameter for all three pipelines:
|
|
@@ -81,14 +85,16 @@ The YAML drives every flag and parameter for all three pipelines:
|
|
|
81
85
|
- **Per-modality downstream gates** (Phase 2): `*_sample_distance_calculation`, `*_trajectory_analysis`, `*_trajectory_dge`, `*_sample_cluster`, `*_proportion_test`, `*_cluster_dge`, `*_visualize_data`, `*_dimension_association_analysis`
|
|
82
86
|
- **Multi-omics-specific**: `multiomics_run_glue_*`, `multiomics_treat_sample_as_batch`, `multiomics_run_glue_twice_for_sample_removal`
|
|
83
87
|
|
|
84
|
-
The
|
|
88
|
+
The 10 ready-to-use configs in `config/` are point-in-time snapshots for the datasets used in the paper; copy one and adjust paths / column names for your own data.
|
|
85
89
|
|
|
86
|
-
###
|
|
90
|
+
### Starter config
|
|
87
91
|
|
|
88
92
|
```bash
|
|
89
|
-
|
|
93
|
+
sampledisco --init-config my_config.yaml
|
|
90
94
|
```
|
|
91
95
|
|
|
96
|
+
writes the demo config (tuned for the Zenodo demo dataset) to `my_config.yaml`. The YAML is validated against every `wrapper()` parameter, so edit values rather than deleting keys.
|
|
97
|
+
|
|
92
98
|
---
|
|
93
99
|
|
|
94
100
|
## Inputs
|
|
@@ -118,7 +124,7 @@ For multi-omics, the pipeline takes two separate h5ads (RNA + ATAC) and integrat
|
|
|
118
124
|
├── atac/ (parallel structure)
|
|
119
125
|
├── multiomics/
|
|
120
126
|
│ ├── integration/glue/{rna-pp,atac-pp,guidance.graphml.gz}
|
|
121
|
-
│ ├── preprocess/adata_sample.h5ad # post-GLUE merged adata with
|
|
127
|
+
│ ├── preprocess/adata_sample.h5ad # post-GLUE merged adata with Z_comp + Z_rmd
|
|
122
128
|
│ ├── sample_embedding/sample_embedding.csv
|
|
123
129
|
│ └── (same downstream subdirs as single-omics)
|
|
124
130
|
└── sys_log/main_process_status.json # which stages completed
|
|
@@ -135,7 +141,7 @@ detects and uses them at runtime. There is no separate "GPU build" of SampleDisc
|
|
|
135
141
|
### 1. Core install (CPU)
|
|
136
142
|
|
|
137
143
|
```bash
|
|
138
|
-
pip install sampledisco #
|
|
144
|
+
pip install sampledisco # or `pip install -e .` from a clone
|
|
139
145
|
```
|
|
140
146
|
|
|
141
147
|
### 2. System prerequisite — bedtools
|
|
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
|
|
10
10
|
[project]
|
|
11
11
|
name = "sampledisco"
|
|
12
|
-
version = "0.
|
|
12
|
+
version = "0.4.0"
|
|
13
13
|
description = "Cross-omics, cross-condition sample embedding for single-cell data (RNA + ATAC)"
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
requires-python = ">=3.10"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# SampleDisco core (CPU) dependencies
|
|
2
|
-
# The deep-learning stack (
|
|
1
|
+
# SampleDisco core (CPU) dependencies. PyTorch is installed as a dependency of harmonypy 0.2.0.
|
|
2
|
+
# The deep-learning stack (scglue, harmony-pytorch, a CUDA build of torch) and RAPIDS GPU
|
|
3
3
|
# acceleration are NOT installed here — they're OS/driver-specific and you
|
|
4
4
|
# install them yourself (see the Installation page). SampleDisco falls back to
|
|
5
5
|
# the CPU path when they are absent.
|
|
@@ -14,7 +14,7 @@ patsy>=0.5
|
|
|
14
14
|
scanpy>=1.11
|
|
15
15
|
anndata>=0.10
|
|
16
16
|
muon>=0.1
|
|
17
|
-
harmonypy
|
|
17
|
+
harmonypy==0.2.0 # the version used for the published results; it requires torch
|
|
18
18
|
python-igraph>=0.10
|
|
19
19
|
leidenalg>=0.9
|
|
20
20
|
networkx>=3.0
|
|
@@ -35,14 +35,27 @@ def load_config(config_path):
|
|
|
35
35
|
return yaml.safe_load(f)
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
# Keys added after 0.2.0. Configs written before them may omit these keys, which
|
|
39
|
+
# then take their wrapper() default; every other key stays required.
|
|
40
|
+
OPTIONAL_KEYS = frozenset(f"{m}_save_cell_adata_after_embedding"
|
|
41
|
+
for m in ("rna", "atac", "multiomics"))
|
|
42
|
+
|
|
43
|
+
|
|
38
44
|
def validate_config(config, func):
|
|
39
45
|
valid_params = inspect.signature(func).parameters
|
|
40
46
|
for key in config:
|
|
41
47
|
if key not in valid_params:
|
|
42
48
|
raise ValueError(f"Unexpected parameter in config: '{key}'")
|
|
43
49
|
for key in valid_params:
|
|
44
|
-
if key not in config:
|
|
50
|
+
if key not in config and key not in OPTIONAL_KEYS:
|
|
45
51
|
raise ValueError(f"Missing required parameter in config: '{key}'")
|
|
52
|
+
from sampledisco.sample_embedding.blocks import check_rmd_weight
|
|
53
|
+
for key in config:
|
|
54
|
+
if key.endswith("_sample_embedding_rmd_weight"):
|
|
55
|
+
try:
|
|
56
|
+
check_rmd_weight(config[key])
|
|
57
|
+
except ValueError as e:
|
|
58
|
+
raise ValueError(f"Invalid value for '{key}': {e}") from None
|
|
46
59
|
|
|
47
60
|
|
|
48
61
|
def write_template(dest):
|
|
@@ -86,16 +86,17 @@ rna_sample_embedding_rmd_dim: 8
|
|
|
86
86
|
rna_sample_embedding_use_clr: false
|
|
87
87
|
rna_sample_embedding_use_rmd: true
|
|
88
88
|
rna_sample_embedding_block_weights:
|
|
89
|
-
rna_sample_embedding_rmd_weight: 0.60
|
|
89
|
+
rna_sample_embedding_rmd_weight: "equal" # RMD block weight α: "equal" = same energy as the three composition blocks together (α² = w_A1² + w_A2² + w_A3²); a number fixes α (0.60 = previous default)
|
|
90
90
|
rna_sample_embedding_pca_components: 10
|
|
91
91
|
rna_sample_embedding_batch_method: "harmony"
|
|
92
|
+
rna_save_cell_adata_after_embedding: true # store .uns['X_DR_sample'] in the cell-level h5ad (updated in place; false = keep only the CSV)
|
|
92
93
|
|
|
93
94
|
# --- Autotune Parameters ---
|
|
94
95
|
rna_autotune_enable: false
|
|
95
96
|
rna_autotune_search: "bayesian"
|
|
96
97
|
rna_autotune_scoring: "auto"
|
|
97
98
|
rna_autotune_scope: "alpha_only"
|
|
98
|
-
rna_autotune_alpha_bounds: [0.1,
|
|
99
|
+
rna_autotune_alpha_bounds: [0.1, 100.0]
|
|
99
100
|
rna_autotune_grouping_col:
|
|
100
101
|
|
|
101
102
|
# --- Trajectory Analysis Parameters ---
|
|
@@ -207,16 +208,17 @@ atac_sample_embedding_rmd_dim: 8
|
|
|
207
208
|
atac_sample_embedding_use_clr: false
|
|
208
209
|
atac_sample_embedding_use_rmd: true
|
|
209
210
|
atac_sample_embedding_block_weights:
|
|
210
|
-
atac_sample_embedding_rmd_weight: 0.60
|
|
211
|
+
atac_sample_embedding_rmd_weight: "equal" # RMD block weight α: "equal" = same energy as the three composition blocks together (α² = w_A1² + w_A2² + w_A3²); a number fixes α (0.60 = previous default)
|
|
211
212
|
atac_sample_embedding_pca_components: 10
|
|
212
213
|
atac_sample_embedding_batch_method: "harmony"
|
|
214
|
+
atac_save_cell_adata_after_embedding: true # store .uns['X_DR_sample'] in the cell-level h5ad (updated in place; false = keep only the CSV)
|
|
213
215
|
|
|
214
216
|
# --- Autotune Parameters ---
|
|
215
217
|
atac_autotune_enable: false
|
|
216
218
|
atac_autotune_search: "bayesian"
|
|
217
219
|
atac_autotune_scoring: "auto"
|
|
218
220
|
atac_autotune_scope: "alpha_only"
|
|
219
|
-
atac_autotune_alpha_bounds: [0.1,
|
|
221
|
+
atac_autotune_alpha_bounds: [0.1, 100.0]
|
|
220
222
|
atac_autotune_grouping_col:
|
|
221
223
|
|
|
222
224
|
# --- Trajectory Analysis Parameters ---
|
|
@@ -332,9 +334,9 @@ multiomics_treat_sample_as_batch: false # GLUE preserves per-sample variance (V
|
|
|
332
334
|
|
|
333
335
|
# --- Sample-removed cluster embedding (X_glue from scGLUE is the RMD/sample-preserved emb) ---
|
|
334
336
|
# By default, one Harmony pass on X_glue removes per-sample variance to
|
|
335
|
-
# produce
|
|
337
|
+
# produce Z_comp (used by cell typing + A1/A2/A3). Alternative:
|
|
336
338
|
# train scGLUE a second time with treat_sample_as_batch=True; that run's
|
|
337
|
-
# embedding is merged in as
|
|
339
|
+
# embedding is merged in as Z_comp and the Harmony pass auto-skips.
|
|
338
340
|
multiomics_harmonize_xglue_max_iter: 30
|
|
339
341
|
multiomics_run_glue_twice_for_sample_removal: false
|
|
340
342
|
multiomics_save_prefix: "glue"
|
|
@@ -355,7 +357,7 @@ multiomics_metric: "cosine"
|
|
|
355
357
|
multiomics_existing_cell_types: false
|
|
356
358
|
multiomics_n_target_clusters: 8
|
|
357
359
|
multiomics_cluster_resolution: 0.8
|
|
358
|
-
# null → auto-resolve to
|
|
360
|
+
# null → auto-resolve to Z_comp (sample-removed); legacy key names accepted
|
|
359
361
|
multiomics_use_rep_celltype:
|
|
360
362
|
multiomics_markers:
|
|
361
363
|
multiomics_generate_umap_celltype: true
|
|
@@ -375,16 +377,17 @@ multiomics_sample_embedding_rmd_dim: 8
|
|
|
375
377
|
multiomics_sample_embedding_use_clr: false
|
|
376
378
|
multiomics_sample_embedding_use_rmd: true
|
|
377
379
|
multiomics_sample_embedding_block_weights:
|
|
378
|
-
multiomics_sample_embedding_rmd_weight: 0.60
|
|
380
|
+
multiomics_sample_embedding_rmd_weight: "equal" # RMD block weight α: "equal" = same energy as the three composition blocks together (α² = w_A1² + w_A2² + w_A3²); a number fixes α (0.60 = previous default)
|
|
379
381
|
multiomics_sample_embedding_pca_components: 10
|
|
380
382
|
multiomics_sample_embedding_batch_method: "harmony"
|
|
383
|
+
multiomics_save_cell_adata_after_embedding: true # store .uns['X_DR_sample'] in the cell-level h5ad (updated in place; false = keep only the CSV)
|
|
381
384
|
|
|
382
385
|
# --- Autotune Parameters ---
|
|
383
386
|
multiomics_autotune_enable: false
|
|
384
387
|
multiomics_autotune_search: "bayesian"
|
|
385
388
|
multiomics_autotune_scoring: "auto"
|
|
386
389
|
multiomics_autotune_scope: "alpha_only"
|
|
387
|
-
multiomics_autotune_alpha_bounds: [0.1,
|
|
390
|
+
multiomics_autotune_alpha_bounds: [0.1, 100.0]
|
|
388
391
|
multiomics_autotune_grouping_col:
|
|
389
392
|
|
|
390
393
|
# --- Trajectory Analysis Parameters ---
|