gset 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.
gset-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,255 @@
1
+ Metadata-Version: 2.4
2
+ Name: gset
3
+ Version: 0.1.0
4
+ Summary: GSET: Gene Signals from Embedding Trajectories select compact contexts for mechanistic GRN inference
5
+ Author: Zeev Weizmann, Elias Ventre
6
+ Project-URL: Repository, https://github.com/ZeevWeizmann/gset
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: numpy
10
+ Requires-Dist: scipy
11
+ Requires-Dist: pandas
12
+ Requires-Dist: scikit-learn
13
+ Requires-Dist: torch
14
+ Requires-Dist: torch_geometric
15
+ Requires-Dist: pot
16
+
17
+ # GSET: Gene Signals from Embedding Trajectories select compact contexts for mechanistic GRN inference
18
+
19
+ Zeev Weizmann and Elias Ventre
20
+
21
+ Code for the paper *GSET: Gene Signals from Embedding Trajectories select compact contexts for mechanistic GRN inference*. It contains the method (also an installable Python package, see "Use on your own data"),
22
+ the simulated data and the code that makes the figures and tables of the paper (see the list of what is
23
+ not included below).
24
+
25
+ ## What is in the folders
26
+
27
+ ```
28
+ gset/ the method (the installable package)
29
+ data.py reads the simulations
30
+ graph.py co-expression graph of the genes
31
+ embeddings.py GCN (co-expression) and DeepSets (expression) encoders of the simulations
32
+ signals.py KL signal and OT residual
33
+ lags.py lagged similarity matrices and the scores of the genes
34
+ programs.py finds the programs, their order and their core genes
35
+ selection.py builds the gene set (bridges + cores) and the baselines HVG, TF list, random
36
+ metrics.py coverage of relay edges and other scores
37
+ clustering.py scores for the recovery of programs
38
+ cardamom_eval.py scores a network inferred by CardamomOT
39
+ ot_similarity.py gene-gene OT distance (Huizing et al.)
40
+ pipeline.py trains the encoders and gives the vectors of all transitions
41
+ reproducible.py makes the neural networks give the same numbers in every run
42
+ rmsexplorer/ the co-expression encoder of the Gene Program Explorer, shared by the RMS and reprogramming experiments
43
+ baselines/ wrappers of methods from other authors (OTVelo, DELVE, lagged OT similarity)
44
+ data/simulations/ the 41 simulated networks (HARISSA) used in the paper
45
+ data/rms/ the rhabdomyosarcoma counts with the six pseudotime bins and the UMAP coordinates
46
+ data/schiebinger_days0-3.h5ad the prepared reprogramming data (days 0-3), unpacked by experiments/schiebinger/unpack_data.py
47
+ simulation_code/ the code that made the simulated networks (as it was used, see its README)
48
+ experiments/<block>/ computes the numbers of one block of the paper, saves them in results/<block>/
49
+ results/<block>/ saved numbers
50
+ figures/<block>/ make_figures.py and the pictures in output/
51
+ tables/<block>/ make_tables.py, prints the LaTeX of the tables
52
+ run_pipeline.py runs the blocks
53
+ ```
54
+
55
+ ## Where is what in the paper
56
+
57
+ Sections, appendices, tables and figures are numbered as in the submitted PDF of the paper
58
+ (`run_pipeline.py --list` prints the same references). `--all` runs the blocks in this order.
59
+
60
+ | Block (`run_pipeline.py --block ...`) | Paper |
61
+ |---|---|
62
+ | `nb_signals` | Appendix B: negative binomial benchmark (Figs. 4 and 5) |
63
+ | `endpoint_signals` | Appendix C: endpoint maps (Figs. 6 and 7), Table 1, dropout figure (Fig. 8) |
64
+ | `program_recovery` | Section 3.3 and Appendix C: Table 3 (program recovery for all representations) |
65
+ | `lagged_association` | Section 3.4 and Appendix D: discrimination, direction, sampling resolution (Tables 4 to 6), lag figure (Fig. 9) |
66
+ | `rms` | Section 3.5 and Appendix L: query genes on the rhabdomyosarcoma data (Figs. 11 to 15, Tables 20 and 21) |
67
+ | `schiebinger` | Section 3.5 and Appendix K, the reprogramming time course (Schiebinger et al., days 0-3): Fig. 2, Table 19, the bridge genes between the programs of Lox and Birc5 (the query genes with `query_genes.py`; `bridges.py`, with the overlap of the bridges between training seeds against chance and the lagged-correlation baseline; the terms in which the bridges are enriched, which are not significant after correction, with `bridges_terms.py`; OTVelo as a baseline with `otvelo_baseline.py`) (needs the data, see below) |
68
+ | `retrieval_curves` | Section 3.6 and Appendix G: recall curves (Figs. 3 and 10) |
69
+ | `retrieval_selections` | Appendix F: ablation of the retrieval channels (Tables 9 and 10); the gene sets used by CardamomOT |
70
+ | `experiments/raw_embeddings/run.py` | Appendix F: Tables 11 and 12, GSET without the learned encoders (a script of its own, not a block of `run_pipeline.py`; the table is printed by `tables/raw_embeddings/make_tables.py`) |
71
+ | `experiments/spike_in/run.py`, `run_raw.py` | Appendix H: Table 15, 1000 real genes added to the 150-gene cascades, with and without the learned encoders (scripts of their own, results in `results/spike_in` and `results/spike_in_raw`; need `data/schiebinger`) |
72
+ | `baseline_selections` | Appendix E: the gene sets of DELVE, OTVelo and OT similarity (needs `DELVE_REPO` and `OTVELO_REPO`) |
73
+ | `extra_baselines` | Appendix E: Table 8 (temporal DE, GRNBoost2, GENIE3, WGCNA hubs, Hotspot; needs arboreto and hotspotsc, see `requirements.txt`) |
74
+ | `cardamom` | Section 3.6, Appendices E and G: CardamomOT on the retrieved contexts (Tables 2, 7, 13 and 14) (needs `CARDAMOM_REPO` to infer the networks again) |
75
+ | `scalability` | Appendix J: run times and memory (Tables 16 to 18) |
76
+
77
+ ## What is not in the repository
78
+
79
+ * The whole reprogramming time course (165,892 cells, Schiebinger et al.; GEO: GSE122662) and the raw single-cell
80
+ RNA-seq counts of the rhabdomyosarcoma samples (GEO: GSE248183). Instead, the repository has the prepared days 0-3
81
+ of the reprogramming data (`data/schiebinger_days0-3.h5ad`) and the rhabdomyosarcoma counts with the pseudotime bins
82
+ (`data/rms/rms_counts.h5ad`). The code that makes these files from the full data is included:
83
+ `experiments/schiebinger/prepare_data.py` and `experiments/rms/make_pseudotime.py`.
84
+ * **Code that made the simulations** is in `simulation_code/` as it was used and was not run again for
85
+ this repository. The simulated networks themselves are in `data/simulations/`.
86
+ * **Baselines of other authors.** DELVE and OTVelo are not included (see Notes); the pipeline runs them
87
+ through the wrappers in `baselines/` when `DELVE_REPO` and `OTVELO_REPO` are set, and otherwise uses
88
+ the gene sets saved in `results/retrieval_selections/`. The networks inferred by CardamomOT are saved
89
+ in `results/cardamom_networks/`, and the tables are made from them.
90
+ * The overview figure of the paper is a drawing and is not made by code.
91
+
92
+ ## Installation
93
+
94
+ Tested with Python 3.13.
95
+
96
+ ```bash
97
+ pip install -r requirements.txt
98
+ ```
99
+
100
+ This is enough to rebuild every figure and table from the saved results
101
+ (`python run_pipeline.py --all --from-results`) and to run GSET itself.
102
+
103
+ To use the method in your own code, install the package `gset` too:
104
+
105
+ ```bash
106
+ pip install -e .
107
+ ```
108
+
109
+ ### Methods of other authors (only to run them again)
110
+
111
+ The results of these methods are saved in `results/`. To compute them again, install the method
112
+ and set the variable; without the variable, `run_pipeline.py` skips the step and uses the saved
113
+ results. The versions below are the ones checked to give the results of the paper.
114
+
115
+ **CardamomOT** (block `cardamom`):
116
+
117
+ ```bash
118
+ git clone https://github.com/eliasventre/CardamomOT
119
+ cd CardamomOT && git checkout 36c5ca2
120
+ pip install -e . && cd ..
121
+ export CARDAMOM_REPO=$PWD/CardamomOT
122
+ ```
123
+
124
+ Only on macOS with Apple silicon: if the process aborts when torch is loaded, apply
125
+ `experiments/cardamom/cardamomot_serial_numba.patch` before `pip install -e .` (`git apply /path/to/this/repository/experiments/cardamom/cardamomot_serial_numba.patch`).
126
+ It makes two numba loops serial instead of parallel. The networks of the paper were inferred with it.
127
+
128
+ **OTVelo** (block `baseline_selections`; GPL-3.0, so it is not copied here):
129
+
130
+ ```bash
131
+ git clone https://github.com/Sandstede-Lab/OT-Velocity
132
+ cd OT-Velocity && git checkout 8b8df25 && cd ..
133
+ export OTVELO_REPO=$PWD/OT-Velocity/Utils
134
+ ```
135
+
136
+ **DELVE** (block `baseline_selections`). DELVE is used from its folder and not installed with pip,
137
+ because its package asks for numpy < 2:
138
+
139
+ ```bash
140
+ git clone https://github.com/jranek/delve
141
+ cd delve && git checkout ff08435 && cd ..
142
+ export DELVE_REPO=$PWD/delve
143
+ pip install --no-deps sketchKH==0.1.4 tqdm_joblib==0.0.5
144
+ ```
145
+
146
+ **GRNBoost2, GENIE3 and Hotspot** (block `extra_baselines`):
147
+
148
+ ```bash
149
+ pip install --no-deps arboreto==0.1.6 hotspotsc==1.1.3
150
+ ```
151
+
152
+ ## Run
153
+
154
+ A quick check that everything works (about ten seconds): it makes Table 1 and Figs. 6 to 8 from the saved results.
155
+
156
+ ```bash
157
+ python run_pipeline.py --block endpoint_signals --from-results
158
+ ```
159
+
160
+ The other blocks:
161
+
162
+ ```bash
163
+ python run_pipeline.py --list # the blocks
164
+ python run_pipeline.py --block endpoint_signals # one block: experiment, figures, tables
165
+ python run_pipeline.py --all --from-results # only the figures and tables, from the saved results
166
+ python run_pipeline.py --all # everything again (many hours)
167
+ ```
168
+
169
+ Every experiment can also be run alone, for example
170
+ `python experiments/program_recovery/run.py twophase60_s1 1`.
171
+
172
+ The pseudotime bins of the rhabdomyosarcoma data can be made again from the raw single-cell RNA-seq counts
173
+ (10x Genomics format). Set the folders of the two samples in `experiments/rms/make_pseudotime.py` and run
174
+ (about five minutes):
175
+
176
+ ```bash
177
+ pip install palantir leidenalg igraph
178
+ python experiments/rms/make_pseudotime.py
179
+ ```
180
+
181
+ ## Use on your own data
182
+
183
+ Install the package from the folder of this repository:
184
+
185
+ ```bash
186
+ pip install -e .
187
+ ```
188
+
189
+ Then:
190
+
191
+ ```python
192
+ import anndata as ad
193
+ from gset import select_genes
194
+
195
+ adata = ad.read_h5ad("my_data.h5ad") # raw counts in X, the time of every cell in adata.obs["time"]
196
+ genes = adata.var_names[select_genes(adata, budget=30, n_programs=3)]
197
+ ```
198
+
199
+ `select_genes` trains the encoders on your data (see Notes for the two co-expression encoders) and returns the
200
+ indices of the selected genes: bridges between consecutive gene programs and the core
201
+ genes of the programs. By default a third of the budget goes to the cores and two thirds to the bridges, and the
202
+ programs are found by clustering, with their number given. Other settings:
203
+
204
+ ```python
205
+ # the numbers of cores and bridges (the budget is their sum), and of the two channels of the bridges
206
+ genes = select_genes(adata, n_cores=10, n_bridges=20, n_kl=14, n_ot=6, n_programs=3)
207
+
208
+ # programs built around one query gene each, in the order in which the programs become active.
209
+ # The program of a query gene is the gene and its program_size - 1 nearest genes, here 10 genes in all.
210
+ queries = [adata.var_names.get_loc("Lox"), adata.var_names.get_loc("Birc5")]
211
+ genes = select_genes(adata, budget=30, query_genes=queries, program_size=10)
212
+
213
+ # programs of your own: the program of every gene (0, 1, 2, ...) and the order of the programs
214
+ genes = select_genes(adata, budget=30, labels=labels, order=[0, 1, 2])
215
+
216
+ # the co-expression encoder of the experiments on the real data, for thousands of genes
217
+ genes = select_genes(adata, budget=30, n_programs=3, coexpr_encoder="real_data")
218
+
219
+ # the data as a list of count matrices (cells x genes), one per timepoint, instead of an AnnData object
220
+ genes = select_genes([X_t0, X_t1, X_t2], budget=30, n_programs=3)
221
+ ```
222
+
223
+ With several replicates, pass a list of such lists. The genes can then be given to CardamomOT or another network
224
+ inference method. The genes related to a query gene can also be explored interactively in the Gene Program Explorer
225
+ (https://rmsexplorer.org).
226
+
227
+ ## Notes
228
+
229
+ * **Same numbers on every run.** Every experiment calls `make_reproducible()`: torch uses one
230
+ thread and deterministic algorithms. Without it, the sums of torch change in the last digits
231
+ when it uses several threads, and this can change which genes are ranked first.
232
+ * **Encoders.** The co-expression embedding, which gives the KL signal, has two encoders. The one in
233
+ `gset/embeddings.py` is used on the simulations, which have tens to a few hundred genes, and is the default of
234
+ `select_genes` (`coexpr_encoder="simulation"`). The one in `rmsexplorer/encoder.py` is used on the real data
235
+ (rhabdomyosarcoma, reprogramming), with thousands of genes (`coexpr_encoder="real_data"`), see `experiments/rms` and
236
+ `experiments/schiebinger`.
237
+ * **Methods of other authors** (CardamomOT, OTVelo, DELVE, arboreto, Hotspot) are not part of this
238
+ repository; see Installation.
239
+ * **Data.** The four data sets of the paper:
240
+ * *Negative binomial mixtures.* They are not stored: `experiments/nb_signals/nb_data.py` simulates them (40 genes,
241
+ 5,000 cells per timepoint, two scenarios, rewiring and positional deviation, at several dropout rates). The scores are
242
+ in `results/nb_signals/`.
243
+ * *HARISSA simulations* (https://github.com/ulysseherbach/harissa). Cascades, switches and the families with
244
+ TF-to-TF relays, 41 networks in `data/simulations/`, made by `simulation_code/`.
245
+ * *Reprogramming time course* of Schiebinger et al. (Cell, 2019; GEO: GSE122662, serum condition), days 0-3,
246
+ 34,101 cells and 4,007 genes, in `data/schiebinger_days0-3.h5ad`. Run
247
+ `python experiments/schiebinger/unpack_data.py` once to unpack it into `data/schiebinger/`, which the block
248
+ `schiebinger` and `experiments/spike_in/` use. The same files can be made from the original serum data, saved as
249
+ `data/schiebinger_raw/reprogramming_schiebinger_only_serum.h5ad`, with `experiments/schiebinger/prepare_data.py`.
250
+ `query_genes.py` also needs Table S2 of the paper (`mmc2.xlsx`), saved as
251
+ `data/schiebinger_raw/schiebinger2019_mmc2.xlsx`.
252
+ * *Rhabdomyosarcoma (RMS)* of Savary et al. (Cell Reports Medicine, 2023; GEO: GSE248183), 13,968 cells and 8,442
253
+ genes, with the six pseudotime bins (the column `time`), the cell types (`cell_type`) and the UMAP coordinates, in
254
+ `data/rms/`. All the analyses use this file. `experiments/rms/make_pseudotime.py` makes a similar file from the raw
255
+ single-cell RNA-seq counts (see Run). It needs `palantir`, `leidenalg` and `igraph`.
gset-0.1.0/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # GSET: Gene Signals from Embedding Trajectories select compact contexts for mechanistic GRN inference
2
+
3
+ Zeev Weizmann and Elias Ventre
4
+
5
+ Code for the paper *GSET: Gene Signals from Embedding Trajectories select compact contexts for mechanistic GRN inference*. It contains the method (also an installable Python package, see "Use on your own data"),
6
+ the simulated data and the code that makes the figures and tables of the paper (see the list of what is
7
+ not included below).
8
+
9
+ ## What is in the folders
10
+
11
+ ```
12
+ gset/ the method (the installable package)
13
+ data.py reads the simulations
14
+ graph.py co-expression graph of the genes
15
+ embeddings.py GCN (co-expression) and DeepSets (expression) encoders of the simulations
16
+ signals.py KL signal and OT residual
17
+ lags.py lagged similarity matrices and the scores of the genes
18
+ programs.py finds the programs, their order and their core genes
19
+ selection.py builds the gene set (bridges + cores) and the baselines HVG, TF list, random
20
+ metrics.py coverage of relay edges and other scores
21
+ clustering.py scores for the recovery of programs
22
+ cardamom_eval.py scores a network inferred by CardamomOT
23
+ ot_similarity.py gene-gene OT distance (Huizing et al.)
24
+ pipeline.py trains the encoders and gives the vectors of all transitions
25
+ reproducible.py makes the neural networks give the same numbers in every run
26
+ rmsexplorer/ the co-expression encoder of the Gene Program Explorer, shared by the RMS and reprogramming experiments
27
+ baselines/ wrappers of methods from other authors (OTVelo, DELVE, lagged OT similarity)
28
+ data/simulations/ the 41 simulated networks (HARISSA) used in the paper
29
+ data/rms/ the rhabdomyosarcoma counts with the six pseudotime bins and the UMAP coordinates
30
+ data/schiebinger_days0-3.h5ad the prepared reprogramming data (days 0-3), unpacked by experiments/schiebinger/unpack_data.py
31
+ simulation_code/ the code that made the simulated networks (as it was used, see its README)
32
+ experiments/<block>/ computes the numbers of one block of the paper, saves them in results/<block>/
33
+ results/<block>/ saved numbers
34
+ figures/<block>/ make_figures.py and the pictures in output/
35
+ tables/<block>/ make_tables.py, prints the LaTeX of the tables
36
+ run_pipeline.py runs the blocks
37
+ ```
38
+
39
+ ## Where is what in the paper
40
+
41
+ Sections, appendices, tables and figures are numbered as in the submitted PDF of the paper
42
+ (`run_pipeline.py --list` prints the same references). `--all` runs the blocks in this order.
43
+
44
+ | Block (`run_pipeline.py --block ...`) | Paper |
45
+ |---|---|
46
+ | `nb_signals` | Appendix B: negative binomial benchmark (Figs. 4 and 5) |
47
+ | `endpoint_signals` | Appendix C: endpoint maps (Figs. 6 and 7), Table 1, dropout figure (Fig. 8) |
48
+ | `program_recovery` | Section 3.3 and Appendix C: Table 3 (program recovery for all representations) |
49
+ | `lagged_association` | Section 3.4 and Appendix D: discrimination, direction, sampling resolution (Tables 4 to 6), lag figure (Fig. 9) |
50
+ | `rms` | Section 3.5 and Appendix L: query genes on the rhabdomyosarcoma data (Figs. 11 to 15, Tables 20 and 21) |
51
+ | `schiebinger` | Section 3.5 and Appendix K, the reprogramming time course (Schiebinger et al., days 0-3): Fig. 2, Table 19, the bridge genes between the programs of Lox and Birc5 (the query genes with `query_genes.py`; `bridges.py`, with the overlap of the bridges between training seeds against chance and the lagged-correlation baseline; the terms in which the bridges are enriched, which are not significant after correction, with `bridges_terms.py`; OTVelo as a baseline with `otvelo_baseline.py`) (needs the data, see below) |
52
+ | `retrieval_curves` | Section 3.6 and Appendix G: recall curves (Figs. 3 and 10) |
53
+ | `retrieval_selections` | Appendix F: ablation of the retrieval channels (Tables 9 and 10); the gene sets used by CardamomOT |
54
+ | `experiments/raw_embeddings/run.py` | Appendix F: Tables 11 and 12, GSET without the learned encoders (a script of its own, not a block of `run_pipeline.py`; the table is printed by `tables/raw_embeddings/make_tables.py`) |
55
+ | `experiments/spike_in/run.py`, `run_raw.py` | Appendix H: Table 15, 1000 real genes added to the 150-gene cascades, with and without the learned encoders (scripts of their own, results in `results/spike_in` and `results/spike_in_raw`; need `data/schiebinger`) |
56
+ | `baseline_selections` | Appendix E: the gene sets of DELVE, OTVelo and OT similarity (needs `DELVE_REPO` and `OTVELO_REPO`) |
57
+ | `extra_baselines` | Appendix E: Table 8 (temporal DE, GRNBoost2, GENIE3, WGCNA hubs, Hotspot; needs arboreto and hotspotsc, see `requirements.txt`) |
58
+ | `cardamom` | Section 3.6, Appendices E and G: CardamomOT on the retrieved contexts (Tables 2, 7, 13 and 14) (needs `CARDAMOM_REPO` to infer the networks again) |
59
+ | `scalability` | Appendix J: run times and memory (Tables 16 to 18) |
60
+
61
+ ## What is not in the repository
62
+
63
+ * The whole reprogramming time course (165,892 cells, Schiebinger et al.; GEO: GSE122662) and the raw single-cell
64
+ RNA-seq counts of the rhabdomyosarcoma samples (GEO: GSE248183). Instead, the repository has the prepared days 0-3
65
+ of the reprogramming data (`data/schiebinger_days0-3.h5ad`) and the rhabdomyosarcoma counts with the pseudotime bins
66
+ (`data/rms/rms_counts.h5ad`). The code that makes these files from the full data is included:
67
+ `experiments/schiebinger/prepare_data.py` and `experiments/rms/make_pseudotime.py`.
68
+ * **Code that made the simulations** is in `simulation_code/` as it was used and was not run again for
69
+ this repository. The simulated networks themselves are in `data/simulations/`.
70
+ * **Baselines of other authors.** DELVE and OTVelo are not included (see Notes); the pipeline runs them
71
+ through the wrappers in `baselines/` when `DELVE_REPO` and `OTVELO_REPO` are set, and otherwise uses
72
+ the gene sets saved in `results/retrieval_selections/`. The networks inferred by CardamomOT are saved
73
+ in `results/cardamom_networks/`, and the tables are made from them.
74
+ * The overview figure of the paper is a drawing and is not made by code.
75
+
76
+ ## Installation
77
+
78
+ Tested with Python 3.13.
79
+
80
+ ```bash
81
+ pip install -r requirements.txt
82
+ ```
83
+
84
+ This is enough to rebuild every figure and table from the saved results
85
+ (`python run_pipeline.py --all --from-results`) and to run GSET itself.
86
+
87
+ To use the method in your own code, install the package `gset` too:
88
+
89
+ ```bash
90
+ pip install -e .
91
+ ```
92
+
93
+ ### Methods of other authors (only to run them again)
94
+
95
+ The results of these methods are saved in `results/`. To compute them again, install the method
96
+ and set the variable; without the variable, `run_pipeline.py` skips the step and uses the saved
97
+ results. The versions below are the ones checked to give the results of the paper.
98
+
99
+ **CardamomOT** (block `cardamom`):
100
+
101
+ ```bash
102
+ git clone https://github.com/eliasventre/CardamomOT
103
+ cd CardamomOT && git checkout 36c5ca2
104
+ pip install -e . && cd ..
105
+ export CARDAMOM_REPO=$PWD/CardamomOT
106
+ ```
107
+
108
+ Only on macOS with Apple silicon: if the process aborts when torch is loaded, apply
109
+ `experiments/cardamom/cardamomot_serial_numba.patch` before `pip install -e .` (`git apply /path/to/this/repository/experiments/cardamom/cardamomot_serial_numba.patch`).
110
+ It makes two numba loops serial instead of parallel. The networks of the paper were inferred with it.
111
+
112
+ **OTVelo** (block `baseline_selections`; GPL-3.0, so it is not copied here):
113
+
114
+ ```bash
115
+ git clone https://github.com/Sandstede-Lab/OT-Velocity
116
+ cd OT-Velocity && git checkout 8b8df25 && cd ..
117
+ export OTVELO_REPO=$PWD/OT-Velocity/Utils
118
+ ```
119
+
120
+ **DELVE** (block `baseline_selections`). DELVE is used from its folder and not installed with pip,
121
+ because its package asks for numpy < 2:
122
+
123
+ ```bash
124
+ git clone https://github.com/jranek/delve
125
+ cd delve && git checkout ff08435 && cd ..
126
+ export DELVE_REPO=$PWD/delve
127
+ pip install --no-deps sketchKH==0.1.4 tqdm_joblib==0.0.5
128
+ ```
129
+
130
+ **GRNBoost2, GENIE3 and Hotspot** (block `extra_baselines`):
131
+
132
+ ```bash
133
+ pip install --no-deps arboreto==0.1.6 hotspotsc==1.1.3
134
+ ```
135
+
136
+ ## Run
137
+
138
+ A quick check that everything works (about ten seconds): it makes Table 1 and Figs. 6 to 8 from the saved results.
139
+
140
+ ```bash
141
+ python run_pipeline.py --block endpoint_signals --from-results
142
+ ```
143
+
144
+ The other blocks:
145
+
146
+ ```bash
147
+ python run_pipeline.py --list # the blocks
148
+ python run_pipeline.py --block endpoint_signals # one block: experiment, figures, tables
149
+ python run_pipeline.py --all --from-results # only the figures and tables, from the saved results
150
+ python run_pipeline.py --all # everything again (many hours)
151
+ ```
152
+
153
+ Every experiment can also be run alone, for example
154
+ `python experiments/program_recovery/run.py twophase60_s1 1`.
155
+
156
+ The pseudotime bins of the rhabdomyosarcoma data can be made again from the raw single-cell RNA-seq counts
157
+ (10x Genomics format). Set the folders of the two samples in `experiments/rms/make_pseudotime.py` and run
158
+ (about five minutes):
159
+
160
+ ```bash
161
+ pip install palantir leidenalg igraph
162
+ python experiments/rms/make_pseudotime.py
163
+ ```
164
+
165
+ ## Use on your own data
166
+
167
+ Install the package from the folder of this repository:
168
+
169
+ ```bash
170
+ pip install -e .
171
+ ```
172
+
173
+ Then:
174
+
175
+ ```python
176
+ import anndata as ad
177
+ from gset import select_genes
178
+
179
+ adata = ad.read_h5ad("my_data.h5ad") # raw counts in X, the time of every cell in adata.obs["time"]
180
+ genes = adata.var_names[select_genes(adata, budget=30, n_programs=3)]
181
+ ```
182
+
183
+ `select_genes` trains the encoders on your data (see Notes for the two co-expression encoders) and returns the
184
+ indices of the selected genes: bridges between consecutive gene programs and the core
185
+ genes of the programs. By default a third of the budget goes to the cores and two thirds to the bridges, and the
186
+ programs are found by clustering, with their number given. Other settings:
187
+
188
+ ```python
189
+ # the numbers of cores and bridges (the budget is their sum), and of the two channels of the bridges
190
+ genes = select_genes(adata, n_cores=10, n_bridges=20, n_kl=14, n_ot=6, n_programs=3)
191
+
192
+ # programs built around one query gene each, in the order in which the programs become active.
193
+ # The program of a query gene is the gene and its program_size - 1 nearest genes, here 10 genes in all.
194
+ queries = [adata.var_names.get_loc("Lox"), adata.var_names.get_loc("Birc5")]
195
+ genes = select_genes(adata, budget=30, query_genes=queries, program_size=10)
196
+
197
+ # programs of your own: the program of every gene (0, 1, 2, ...) and the order of the programs
198
+ genes = select_genes(adata, budget=30, labels=labels, order=[0, 1, 2])
199
+
200
+ # the co-expression encoder of the experiments on the real data, for thousands of genes
201
+ genes = select_genes(adata, budget=30, n_programs=3, coexpr_encoder="real_data")
202
+
203
+ # the data as a list of count matrices (cells x genes), one per timepoint, instead of an AnnData object
204
+ genes = select_genes([X_t0, X_t1, X_t2], budget=30, n_programs=3)
205
+ ```
206
+
207
+ With several replicates, pass a list of such lists. The genes can then be given to CardamomOT or another network
208
+ inference method. The genes related to a query gene can also be explored interactively in the Gene Program Explorer
209
+ (https://rmsexplorer.org).
210
+
211
+ ## Notes
212
+
213
+ * **Same numbers on every run.** Every experiment calls `make_reproducible()`: torch uses one
214
+ thread and deterministic algorithms. Without it, the sums of torch change in the last digits
215
+ when it uses several threads, and this can change which genes are ranked first.
216
+ * **Encoders.** The co-expression embedding, which gives the KL signal, has two encoders. The one in
217
+ `gset/embeddings.py` is used on the simulations, which have tens to a few hundred genes, and is the default of
218
+ `select_genes` (`coexpr_encoder="simulation"`). The one in `rmsexplorer/encoder.py` is used on the real data
219
+ (rhabdomyosarcoma, reprogramming), with thousands of genes (`coexpr_encoder="real_data"`), see `experiments/rms` and
220
+ `experiments/schiebinger`.
221
+ * **Methods of other authors** (CardamomOT, OTVelo, DELVE, arboreto, Hotspot) are not part of this
222
+ repository; see Installation.
223
+ * **Data.** The four data sets of the paper:
224
+ * *Negative binomial mixtures.* They are not stored: `experiments/nb_signals/nb_data.py` simulates them (40 genes,
225
+ 5,000 cells per timepoint, two scenarios, rewiring and positional deviation, at several dropout rates). The scores are
226
+ in `results/nb_signals/`.
227
+ * *HARISSA simulations* (https://github.com/ulysseherbach/harissa). Cascades, switches and the families with
228
+ TF-to-TF relays, 41 networks in `data/simulations/`, made by `simulation_code/`.
229
+ * *Reprogramming time course* of Schiebinger et al. (Cell, 2019; GEO: GSE122662, serum condition), days 0-3,
230
+ 34,101 cells and 4,007 genes, in `data/schiebinger_days0-3.h5ad`. Run
231
+ `python experiments/schiebinger/unpack_data.py` once to unpack it into `data/schiebinger/`, which the block
232
+ `schiebinger` and `experiments/spike_in/` use. The same files can be made from the original serum data, saved as
233
+ `data/schiebinger_raw/reprogramming_schiebinger_only_serum.h5ad`, with `experiments/schiebinger/prepare_data.py`.
234
+ `query_genes.py` also needs Table S2 of the paper (`mmc2.xlsx`), saved as
235
+ `data/schiebinger_raw/schiebinger2019_mmc2.xlsx`.
236
+ * *Rhabdomyosarcoma (RMS)* of Savary et al. (Cell Reports Medicine, 2023; GEO: GSE248183), 13,968 cells and 8,442
237
+ genes, with the six pseudotime bins (the column `time`), the cell types (`cell_type`) and the UMAP coordinates, in
238
+ `data/rms/`. All the analyses use this file. `experiments/rms/make_pseudotime.py` makes a similar file from the raw
239
+ single-cell RNA-seq counts (see Run). It needs `palantir`, `leidenalg` and `igraph`.
@@ -0,0 +1,11 @@
1
+ from .graph import build_graph
2
+ from .embeddings import (train_gcn, coexpr_embedding,
3
+ train_deepsets, expr_embedding, train_both)
4
+ from .signals import kl_vector, kl_score, ot_residual, ot_score
5
+ from .lags import lag_matrix, symmetric_score
6
+ from .programs import find_programs, program_order, core_genes, programs_from_queries
7
+ from .selection import gset_context, bridge_genes, hvg_ranking, tf_selection, random_selection
8
+ from .metrics import relay_coverage, within_between_gap
9
+ from .pipeline import transition_vectors
10
+ from .reproducible import make_reproducible
11
+ from .api import select_genes, matrices_from_anndata
gset-0.1.0/gset/api.py ADDED
@@ -0,0 +1,109 @@
1
+ """select_genes: GSET in one function.
2
+
3
+ from gset import select_genes
4
+ genes = select_genes(adata, budget=30, n_programs=3)
5
+
6
+ It follows the steps of the paper:
7
+ 1. train the encoders and compute the KL and OT signals of every transition
8
+ 2. find the gene programs, and their order
9
+ 3. choose the bridge genes between consecutive programs and the core genes of the programs
10
+ """
11
+ import numpy as np
12
+
13
+ from .lags import lag_matrix
14
+ from .pipeline import transition_vectors
15
+ from .programs import concat_embedding, find_programs, mean_profiles, program_order, programs_from_queries
16
+ from .selection import gset_context
17
+
18
+
19
+ def matrices_from_anndata(adata, time_key="time"):
20
+ """The count matrices (cells x genes), one per timepoint, in the order of the time.
21
+ The counts are in adata.X and the time of every cell is in adata.obs[time_key]."""
22
+ X = adata.X.toarray() if hasattr(adata.X, "toarray") else np.asarray(adata.X)
23
+ times = np.asarray(adata.obs[time_key])
24
+ return [X[times == t].astype(float) for t in np.unique(times)]
25
+
26
+
27
+ def _runs_from(data, time_key):
28
+ """Every run is a dict {timepoint: matrix}. Here: one run, or one for every replicate."""
29
+ if hasattr(data, "obs"): # an AnnData object
30
+ data = matrices_from_anndata(data, time_key)
31
+ if isinstance(data[0], np.ndarray): # one run: a list of matrices
32
+ data = [data]
33
+ runs = [dict(enumerate(run)) for run in data]
34
+ return runs, list(range(len(runs[0])))
35
+
36
+
37
+ def _split_budget(budget, n_cores, n_bridges, n_kl, n_ot):
38
+ """How many genes are cores, bridges from the KL signal and bridges from the OT signal."""
39
+ if n_cores is None and n_bridges is None:
40
+ n_cores = budget // 3 # a third of the budget for the cores
41
+ n_bridges = budget - n_cores # two thirds for the bridges
42
+ elif n_cores is None:
43
+ n_cores = budget - n_bridges
44
+ elif n_bridges is None:
45
+ n_bridges = budget - n_cores
46
+ if n_kl is None and n_ot is None:
47
+ n_ot = int(round(0.3 * n_bridges)) # 70% of the bridges from KL, 30% from OT
48
+ if n_kl is None:
49
+ n_kl = n_bridges - n_ot
50
+ if n_ot is None:
51
+ n_ot = n_bridges - n_kl
52
+ return n_cores + n_bridges, n_kl, n_ot
53
+
54
+
55
+ def select_genes(data, budget=30, n_programs=3, n_cores=None, n_bridges=None, n_kl=None, n_ot=None,
56
+ query_genes=None, program_size=30, labels=None, order=None,
57
+ coexpr_encoder="simulation", time_key="time", seed=42, n_epochs=None):
58
+ """Select a compact set of genes from time-resolved single-cell data.
59
+
60
+ Returns the sorted list of the indices of the selected genes: the bridge genes between consecutive
61
+ programs and the core genes of the programs.
62
+
63
+ Data
64
+ data an AnnData object (raw counts in X, the time of every cell in obs[time_key]) or a list of
65
+ count matrices (cells x genes), one per timepoint in the order of the time. With several
66
+ replicates, a list of such lists. The cells of different timepoints do not have to be matched.
67
+ time_key the column of obs with the time of the cells ("time")
68
+
69
+ Number of genes
70
+ budget how many genes to select (30)
71
+ n_cores how many of them are core genes (default: a third of the budget)
72
+ n_bridges how many are bridges (default: the rest). If you give both n_cores and n_bridges, the budget
73
+ is their sum.
74
+ n_kl, n_ot how many of the bridges come from the KL signal without lag and from the OT signal with lag 1
75
+ (default: 70% and 30%)
76
+
77
+ Programs (the groups of genes that work together). Choose one of the three ways:
78
+ n_programs the number of programs, found by clustering the genes (3)
79
+ query_genes the indices of one gene for every program, in the order in which the programs become active.
80
+ The program of a query gene is the gene and its program_size - 1 nearest genes (program_size
81
+ is 30), and the other genes go to the program with the nearest centroid.
82
+ labels, order the program of every gene (0, 1, 2, ...) and the order of the programs (by default 0, 1, 2, ...)
83
+
84
+ Encoders
85
+ coexpr_encoder the encoder of the co-expression embedding (the KL signal). "simulation" (default): the
86
+ encoder of the simulations, for panels of tens to a few hundred genes. "real_data": the encoder
87
+ of the experiments on the real data, for thousands of genes (rmsexplorer/encoder.py).
88
+ seed, n_epochs the training. n_epochs: 300 for "simulation", 200 and 150 for "real_data" (default).
89
+ """
90
+ runs, times = _runs_from(data, time_key)
91
+
92
+ # 1. the signals of every transition
93
+ vectors = transition_vectors(runs, times, seed=seed, n_epochs=n_epochs, coexpr_encoder=coexpr_encoder)
94
+ kl_lag0 = lag_matrix(vectors["kl"], 0)
95
+ ot_lag1 = lag_matrix(vectors["ot"], 1)
96
+ z_concat = concat_embedding(vectors["gcn"], runs, vectors["active"], embed=vectors["embed"])
97
+
98
+ # 2. the programs and their order
99
+ if query_genes is not None:
100
+ labels, order = programs_from_queries(z_concat, query_genes, program_size)
101
+ elif labels is None:
102
+ labels = find_programs(z_concat, n_programs)
103
+ order, _ = program_order(labels, mean_profiles(runs, vectors["active"]))
104
+ elif order is None:
105
+ order = list(range(int(np.max(labels)) + 1))
106
+
107
+ # 3. the bridges and the cores
108
+ budget, n_kl, n_ot = _split_budget(budget, n_cores, n_bridges, n_kl, n_ot)
109
+ return gset_context(budget, n_kl, n_ot, np.asarray(labels), order, kl_lag0, ot_lag1, z_concat)