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.
Files changed (95) hide show
  1. {sampledisco-0.2.0/src/sampledisco.egg-info → sampledisco-0.4.0}/PKG-INFO +49 -43
  2. {sampledisco-0.2.0 → sampledisco-0.4.0}/README.md +47 -41
  3. {sampledisco-0.2.0 → sampledisco-0.4.0}/pyproject.toml +1 -1
  4. {sampledisco-0.2.0 → sampledisco-0.4.0}/requirements.txt +3 -3
  5. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/cli.py +14 -1
  6. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/config/config_demo.yaml +12 -9
  7. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/parameter_selection/autotune.py +130 -60
  8. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/ATAC_cell_type.py +6 -3
  9. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/ATAC_cell_type_gpu.py +7 -4
  10. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/atac_preprocess_cpu.py +10 -7
  11. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/atac_preprocess_gpu.py +10 -7
  12. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/cell_type_cpu.py +12 -10
  13. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/cell_type_gpu.py +12 -10
  14. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_batch_correction.py +19 -12
  15. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_cell_type_cpu.py +7 -6
  16. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_cell_type_gpu.py +6 -4
  17. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_glue.py +25 -14
  18. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/multi_omics_merge.py +5 -4
  19. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/rna_preprocess_cpu.py +10 -7
  20. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/rna_preprocess_gpu.py +10 -7
  21. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_association/association.py +2 -2
  22. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/sample_distance.py +18 -18
  23. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_embedding/__init__.py +8 -2
  24. sampledisco-0.4.0/src/sampledisco/sample_embedding/blocks.py +913 -0
  25. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_embedding/sample_embedding.py +88 -73
  26. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_embedding/sample_embedding_gpu.py +94 -78
  27. sampledisco-0.4.0/src/sampledisco/utils/embedding_keys.py +189 -0
  28. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/multi_omics_visualization.py +2 -2
  29. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/visualization_other.py +4 -4
  30. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/atac_wrapper.py +11 -7
  31. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/multiomics_wrapper.py +53 -63
  32. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/rna_wrapper.py +11 -7
  33. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/wrapper.py +44 -22
  34. {sampledisco-0.2.0 → sampledisco-0.4.0/src/sampledisco.egg-info}/PKG-INFO +49 -43
  35. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/SOURCES.txt +5 -1
  36. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/requires.txt +1 -1
  37. sampledisco-0.4.0/tests/test_config_validation.py +54 -0
  38. sampledisco-0.4.0/tests/test_inplace_uns_and_equal_weight.py +186 -0
  39. sampledisco-0.4.0/tests/test_sample_embedding_equivalence.py +148 -0
  40. sampledisco-0.2.0/src/sampledisco/sample_embedding/blocks.py +0 -541
  41. {sampledisco-0.2.0 → sampledisco-0.4.0}/LICENSE +0 -0
  42. {sampledisco-0.2.0 → sampledisco-0.4.0}/setup.cfg +0 -0
  43. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/__init__.py +0 -0
  44. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_ArchR.py +0 -0
  45. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_RNA_harmony.py +0 -0
  46. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_gene_activity.py +0 -0
  47. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/ATAC_peak_annotation.py +0 -0
  48. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/RNA_name_convertor.py +0 -0
  49. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/__init__.py +0 -0
  50. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/pseudo_correlation.py +0 -0
  51. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/test_pseudo_correlation.py +0 -0
  52. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/gene_activity/validation.py +0 -0
  53. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/parameter_selection/__init__.py +0 -0
  54. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/preparation/__init__.py +0 -0
  55. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_association/__init__.py +0 -0
  56. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/RAISIN.py +0 -0
  57. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/RAISIN_TEST.py +0 -0
  58. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/__init__.py +0 -0
  59. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/cluster.py +0 -0
  60. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/cluster_severity_reconcile.py +0 -0
  61. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_clustering/proportion_test.py +0 -0
  62. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/ChiSquare.py +0 -0
  63. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/__init__.py +0 -0
  64. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/distance_test.py +0 -0
  65. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_distance/jensenshannon.py +0 -0
  66. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/CCA.py +0 -0
  67. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/CCA_test.py +0 -0
  68. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/TSCAN.py +0 -0
  69. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/__init__.py +0 -0
  70. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/trajectory_DGE_visualization.py +0 -0
  71. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/sample_trajectory/trajectory_diff_gene.py +0 -0
  72. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/Grouping.py +0 -0
  73. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/__init__.py +0 -0
  74. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/batch_regress.py +0 -0
  75. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/harmony_compat.py +0 -0
  76. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/imbalance_cell_type_handler.py +0 -0
  77. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/inspector.py +0 -0
  78. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/limma.py +0 -0
  79. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/merge_sample_meta.py +0 -0
  80. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/random_seed.py +0 -0
  81. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/safe_save.py +0 -0
  82. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/slim_adata.py +0 -0
  83. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/subsample.py +0 -0
  84. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/subsample_generator.py +0 -0
  85. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/tf_idf.py +0 -0
  86. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/utils/unify_optimal.py +0 -0
  87. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/ATAC_visualization.py +0 -0
  88. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/DEG_visualization.py +0 -0
  89. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/__init__.py +0 -0
  90. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/visualization_embedding.py +0 -0
  91. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/visualization/visualization_helper.py +0 -0
  92. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco/wrapper/__init__.py +0 -0
  93. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/dependency_links.txt +0 -0
  94. {sampledisco-0.2.0 → sampledisco-0.4.0}/src/sampledisco.egg-info/entry_points.txt +0 -0
  95. {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.2.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<0.0.10,>=0.0.9
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
- Paper draft: [`/users/hjiang/GenoDistance/SampleDisco_Draft-11.pdf`](../SampleDisco_Draft-11.pdf)
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
- | **`Z_clust`** | sample-removed embedding — used for clustering and composition blocks | Harmony (single-omics) / Harmony post-pass on scGLUE (multi-omics) |
65
- | **`Z_cmd`** | sample-preserved embedding — used for the counterfactual displacement (CMD) block | second Harmony pass (single-omics) / scGLUE primary output (multi-omics) |
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. **CMD** — leave-one-out cell-type-resolved displacement on `Z_cmd`
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
- ├── SampleDisc.py # CLI entry point (simple or complex mode)
83
- ├── config/ # 9 YAML configs covering covid / blood / eye / heart / ENCODE / tabula / long_covid / unpaired / default
84
- ├── wrapper/ # Orchestration
85
- │ ├── wrapper.py # Master wrapper; gates RNA + ATAC + multiomics + shared downstream
86
- │ ├── rna_wrapper.py
87
- │ ├── atac_wrapper.py
88
- │ └── multiomics_wrapper.py
89
- ├── preparation/ # Preprocessing
90
- │ ├── rna_preprocess_{cpu,gpu}.py # QC → HVG → PCA → dual Harmony → Z_clust + Z_cmd
91
- │ ├── atac_preprocess_{cpu,gpu}.py # QC → TF-IDF → HVF → LSI → dual Harmony → Z_clust + Z_cmd
92
- │ ├── cell_type_{cpu,gpu}.py # Leiden clustering on Z_clust (RNA or ATAC)
93
- │ ├── ATAC_cell_type{,_gpu}.py # ATAC-specific cell typing variants
94
- │ ├── multi_omics_glue.py # scGLUE integration (cross-modality VAE + guidance graph)
95
- │ ├── multi_omics_batch_correction.py # Harmony post-pass on X_glue → Z_clust
96
- │ ├── multi_omics_merge.py # post-GLUE merge + per-modality preprocess/slimming
97
- │ └── multi_omics_cell_type_{cpu,gpu}.py # RNA-Leiden + k-NN label transfer to ATAC
98
- ├── sample_embedding/ # Core method
99
- │ ├── blocks.py # composition, CMD, weighting, Frobenius stack, final PCA + Harmony
100
- │ ├── sample_embedding.py # CPU pipeline
101
- │ └── sample_embedding_gpu.py # GPU pipeline (cuML + cupy)
102
- ├── parameter_selection/
103
- │ └── autotune.py # Bayesian GP sweep over CMD α; adaptive proxy ensemble
104
- ├── sample_distance/ # Pairwise sample distances (DR / EMD / chi-square / JS)
105
- ├── sample_clustering/ # Hierarchical (HRA / HRC / NN / UPGMA / consensus), K-means, proportion test, RAISIN
106
- ├── sample_trajectory/ # CCA (supervised) and TSCAN (unsupervised) + GAM-based trajectory DGE
107
- ├── sample_association/ # Per-PC variance explained vs sample-level covariates (permutation FDR)
108
- ├── visualization/ # Embedding plots, dendrograms, DGE volcanos, modality-aware multi-omics scatters
109
- ├── utils/ # Shared helpers: seed, safe h5ad I/O, limma, TF-IDF, batch regress, Grouping
110
- ├── gene_activity/ # ATAC peak → gene activity inference + RNA-ATAC validation
111
- └── claude/ # Active one-off run scripts (rerun launchers, monitored SE, parameter sweeps)
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
- ### Complex mode (recommended) — YAML-driven
122
+ ### Run — YAML-driven
119
123
 
120
124
  ```bash
121
- python SampleDisc.py -m complex --config config/config.yaml
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 9 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.
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
- ### Simple mode — one positional file, defaults everywhere
137
+ ### Starter config
134
138
 
135
139
  ```bash
136
- python SampleDisc.py -m simple -c <count_data.h5ad> -o <output_dir>
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 Z_clust + Z_cmd
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 # once published — or `pip install -e .` from a clone
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
- Paper draft: [`/users/hjiang/GenoDistance/SampleDisco_Draft-11.pdf`](../SampleDisco_Draft-11.pdf)
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
- | **`Z_clust`** | sample-removed embedding — used for clustering and composition blocks | Harmony (single-omics) / Harmony post-pass on scGLUE (multi-omics) |
18
- | **`Z_cmd`** | sample-preserved embedding — used for the counterfactual displacement (CMD) block | second Harmony pass (single-omics) / scGLUE primary output (multi-omics) |
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. **CMD** — leave-one-out cell-type-resolved displacement on `Z_cmd`
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
- ├── SampleDisc.py # CLI entry point (simple or complex mode)
36
- ├── config/ # 9 YAML configs covering covid / blood / eye / heart / ENCODE / tabula / long_covid / unpaired / default
37
- ├── wrapper/ # Orchestration
38
- │ ├── wrapper.py # Master wrapper; gates RNA + ATAC + multiomics + shared downstream
39
- │ ├── rna_wrapper.py
40
- │ ├── atac_wrapper.py
41
- │ └── multiomics_wrapper.py
42
- ├── preparation/ # Preprocessing
43
- │ ├── rna_preprocess_{cpu,gpu}.py # QC → HVG → PCA → dual Harmony → Z_clust + Z_cmd
44
- │ ├── atac_preprocess_{cpu,gpu}.py # QC → TF-IDF → HVF → LSI → dual Harmony → Z_clust + Z_cmd
45
- │ ├── cell_type_{cpu,gpu}.py # Leiden clustering on Z_clust (RNA or ATAC)
46
- │ ├── ATAC_cell_type{,_gpu}.py # ATAC-specific cell typing variants
47
- │ ├── multi_omics_glue.py # scGLUE integration (cross-modality VAE + guidance graph)
48
- │ ├── multi_omics_batch_correction.py # Harmony post-pass on X_glue → Z_clust
49
- │ ├── multi_omics_merge.py # post-GLUE merge + per-modality preprocess/slimming
50
- │ └── multi_omics_cell_type_{cpu,gpu}.py # RNA-Leiden + k-NN label transfer to ATAC
51
- ├── sample_embedding/ # Core method
52
- │ ├── blocks.py # composition, CMD, weighting, Frobenius stack, final PCA + Harmony
53
- │ ├── sample_embedding.py # CPU pipeline
54
- │ └── sample_embedding_gpu.py # GPU pipeline (cuML + cupy)
55
- ├── parameter_selection/
56
- │ └── autotune.py # Bayesian GP sweep over CMD α; adaptive proxy ensemble
57
- ├── sample_distance/ # Pairwise sample distances (DR / EMD / chi-square / JS)
58
- ├── sample_clustering/ # Hierarchical (HRA / HRC / NN / UPGMA / consensus), K-means, proportion test, RAISIN
59
- ├── sample_trajectory/ # CCA (supervised) and TSCAN (unsupervised) + GAM-based trajectory DGE
60
- ├── sample_association/ # Per-PC variance explained vs sample-level covariates (permutation FDR)
61
- ├── visualization/ # Embedding plots, dendrograms, DGE volcanos, modality-aware multi-omics scatters
62
- ├── utils/ # Shared helpers: seed, safe h5ad I/O, limma, TF-IDF, batch regress, Grouping
63
- ├── gene_activity/ # ATAC peak → gene activity inference + RNA-ATAC validation
64
- └── claude/ # Active one-off run scripts (rerun launchers, monitored SE, parameter sweeps)
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
- ### Complex mode (recommended) — YAML-driven
75
+ ### Run — YAML-driven
72
76
 
73
77
  ```bash
74
- python SampleDisc.py -m complex --config config/config.yaml
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 9 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.
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
- ### Simple mode — one positional file, defaults everywhere
90
+ ### Starter config
87
91
 
88
92
  ```bash
89
- python SampleDisc.py -m simple -c <count_data.h5ad> -o <output_dir>
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 Z_clust + Z_cmd
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 # once published — or `pip install -e .` from a clone
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.2.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 — no PyTorch.
2
- # The deep-learning stack (torch, scglue, harmony-pytorch) and RAPIDS GPU
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>=0.0.9,<0.0.10 # pin to the pure-NumPy release; harmonypy 0.0.10+ imports torch
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, 10.0]
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, 10.0]
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 X_glue_harmony (used by cell typing + A1/A2/A3). Alternative:
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 X_glue_harmony and the Harmony pass auto-skips.
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 X_glue_harmony (sample-removed) if present, else X_glue
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, 10.0]
390
+ multiomics_autotune_alpha_bounds: [0.1, 100.0]
388
391
  multiomics_autotune_grouping_col:
389
392
 
390
393
  # --- Trajectory Analysis Parameters ---