flowsig 0.3.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 (37) hide show
  1. flowsig-0.3.0/LICENSE.md +21 -0
  2. flowsig-0.3.0/PKG-INFO +374 -0
  3. flowsig-0.3.0/README.md +334 -0
  4. flowsig-0.3.0/pyproject.toml +67 -0
  5. flowsig-0.3.0/src/flowsig/.DS_Store +0 -0
  6. flowsig-0.3.0/src/flowsig/__init__.py +4 -0
  7. flowsig-0.3.0/src/flowsig/data/allTFs_human.txt +1892 -0
  8. flowsig-0.3.0/src/flowsig/data/allTFs_mouse.txt +1860 -0
  9. flowsig-0.3.0/src/flowsig/data/allTFs_zebrafish.txt +2351 -0
  10. flowsig-0.3.0/src/flowsig/data/cellchat_interactions_and_tfs_human.csv.gz +0 -0
  11. flowsig-0.3.0/src/flowsig/data/cellchat_interactions_and_tfs_mouse.csv.gz +0 -0
  12. flowsig-0.3.0/src/flowsig/data/cellchat_interactions_tfs_human.csv.gz +0 -0
  13. flowsig-0.3.0/src/flowsig/data/cellchat_interactions_tfs_mouse.csv.gz +0 -0
  14. flowsig-0.3.0/src/flowsig/plotting/__init__.py +6 -0
  15. flowsig-0.3.0/src/flowsig/plotting/_plotting.py +627 -0
  16. flowsig-0.3.0/src/flowsig/preprocessing/__init__.py +23 -0
  17. flowsig-0.3.0/src/flowsig/preprocessing/_flow_expressions.py +744 -0
  18. flowsig-0.3.0/src/flowsig/preprocessing/_flow_preprocessing.py +243 -0
  19. flowsig-0.3.0/src/flowsig/preprocessing/_gem_construction.py +160 -0
  20. flowsig-0.3.0/src/flowsig/preprocessing/_spatial_blocking.py +26 -0
  21. flowsig-0.3.0/src/flowsig/preprocessing/_townes_nsf_utils.py +169 -0
  22. flowsig-0.3.0/src/flowsig/tools/__init__.py +9 -0
  23. flowsig-0.3.0/src/flowsig/tools/_network.py +387 -0
  24. flowsig-0.3.0/src/flowsig/tools/_spatial.py +5 -0
  25. flowsig-0.3.0/src/flowsig/tools/_validate_network.py +134 -0
  26. flowsig-0.3.0/src/flowsig/tutorials/.ipynb_checkpoints/mouse_embryo_stereoseq_example-checkpoint.ipynb +214 -0
  27. flowsig-0.3.0/src/flowsig/tutorials/.ipynb_checkpoints/mouse_embryo_stereoseq_example_script-checkpoint.py +63 -0
  28. flowsig-0.3.0/src/flowsig/tutorials/.ipynb_checkpoints/pancreatic_islets_example_script-checkpoint.py +65 -0
  29. flowsig-0.3.0/src/flowsig/tutorials/.ipynb_checkpoints/pancreatic_islets_scrnaseq_example-checkpoint.ipynb +216 -0
  30. flowsig-0.3.0/src/flowsig/tutorials/burkhardt21_communications_Ctrl.csv +419 -0
  31. flowsig-0.3.0/src/flowsig/tutorials/burkhardt21_communications_IFNg.csv +332 -0
  32. flowsig-0.3.0/src/flowsig/tutorials/mouse_embryo_stereoseq_example.ipynb +207 -0
  33. flowsig-0.3.0/src/flowsig/tutorials/mouse_embryo_stereoseq_example_script.py +67 -0
  34. flowsig-0.3.0/src/flowsig/tutorials/pancreatic_islets_example_script.py +61 -0
  35. flowsig-0.3.0/src/flowsig/tutorials/pancreatic_islets_scrnaseq_example.ipynb +212 -0
  36. flowsig-0.3.0/src/flowsig/utilities/__init__.py +1 -0
  37. flowsig-0.3.0/src/flowsig/utilities/_utils.py +246 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2024] [Axel Allen Almet]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
flowsig-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,374 @@
1
+ Metadata-Version: 2.3
2
+ Name: flowsig
3
+ Version: 0.3.0
4
+ Summary: Infer dependent intercellular communication from single-cell and spatial transcriptomics data.
5
+ License: MIT
6
+ Keywords: single-cell,spatial,cell-cell-communication,transcriptomics
7
+ Author: Axel A. Almet
8
+ Requires-Python: >=3.10,<3.12
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Requires-Dist: anndata (>=0.11.3,<0.12.0)
16
+ Requires-Dist: causaldag (>=0.1a163,<0.2)
17
+ Requires-Dist: cnmf (>=1.7.0,<2.0.0)
18
+ Requires-Dist: dm-tree (>=0.1.9,<0.2.0)
19
+ Requires-Dist: geopandas (>=1.1.1,<2.0.0)
20
+ Requires-Dist: graphical-models (>=0.1a21,<0.2)
21
+ Requires-Dist: joblib (>=1.4.2,<2.0.0)
22
+ Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
23
+ Requires-Dist: networkx (>=3.4.2,<4.0.0)
24
+ Requires-Dist: numpy (>=1.26.0,<2.2.0)
25
+ Requires-Dist: pandas (>=2.2.3,<3.0.0)
26
+ Requires-Dist: pyliger (>=0.2.4,<0.3.0)
27
+ Requires-Dist: scanpy (>=1.11.0,<2.0.0)
28
+ Requires-Dist: scipy (>=1.10.1,<2.0.0)
29
+ Requires-Dist: seaborn (>=0.13.2,<0.14.0)
30
+ Requires-Dist: squidpy (>=1.6.5,<2.0.0)
31
+ Requires-Dist: tensorflow (>=2.19.0,<3.0.0)
32
+ Requires-Dist: tensorflow-probability (>=0.25.0,<0.26.0)
33
+ Requires-Dist: tf-keras (>=2.19.0,<3.0.0)
34
+ Requires-Dist: tqdm (>=4.67.1,<5.0.0)
35
+ Project-URL: Documentation, https://flowsig.readthedocs.io
36
+ Project-URL: Homepage, https://github.com/axelalmet/flowsig
37
+ Project-URL: Repository, https://github.com/axelalmet/flowsig
38
+ Description-Content-Type: text/markdown
39
+
40
+ # FlowSig
41
+ Python package to infer directed intercellular flows described by ligand-receptor interactions driving tissue-scale gene expression patterning.
42
+
43
+ FlowSig requires:
44
+
45
+ 1. Single-cell RNA-sequencing (scRNA-seq) data with cell state annotations that compare a baseline control to one or more perturbed conditions, e.g. disease severity, OR spatial transcriptomics (ST) data.
46
+ 2. Cell-cell communication (CCC) inferred for each condition of interest. For non-spatial data, we require input from [CellChat](https://github.com/sqjin/CellChat). For ST data, we require input from [COMMOT](https://github.com/zcang/COMMOT).
47
+
48
+ The code used to generate all of the results in Almet et al., "Inferring pattern-driving intercellular flows from single-cell and spatial transcriptomics", can be found in another GitHub repository [here](https://github.com/axelalmet/FlowSigAnalysis_2023).
49
+
50
+ **Update (April 20, 2025): I've done some re-factoring to make FlowSig more efficient in its construction of flow variables and streamlined in its implementation. Some of the function arguments are a little different and I've done my best to update the documentation and tutorials, but please let me know if you run into any issues!**
51
+
52
+ <details>
53
+ <summary>Installation</summary>
54
+
55
+ ## Installation instructions
56
+
57
+ The easiest way to currently install FlowSig is to generate a Python virtual environment and clone the repository, so that you can install all of the relevant dependencies, particularly those needed by [pyliger](https://github.com/welch-lab/pyliger) and [NSF](https://github.com/willtownes/spatial-factorization-py). We are working on making flowsig pip installable ASAP!
58
+
59
+ **To generate a virtual environment, run the command. N.B. make sure you're using Python 3.10!**
60
+
61
+ ```
62
+ # Create the virtual environment
63
+ python3.10 -m venv flowsigenv
64
+
65
+ # Activate the virtual environment
66
+ source flowsigenv/bin/activate
67
+
68
+ # Clone the repository
69
+ git clone https://github.com/axelalmet/flowsig.git
70
+ cd ./flowsig/
71
+
72
+ # Install
73
+ pip3 install .
74
+ ```
75
+ </details>
76
+ <details>
77
+ <summary>Non-spatial scRNA-seq example </summary>
78
+
79
+ ## Application to non-spatial scRNA-seq of stimulated pancreatic islets
80
+
81
+ Here, we show how to apply FlowSig to an scRNA-seq dataset of wildtype
82
+ and stimulated human pancreatic islets, as originally studied in [Burkhardt et al. (2021)](https://www.nature.com/articles/s41587-020-00803-5).
83
+ The processed data and cell-cell communication inference, which was obtained using CellChat,
84
+ can be downloaded from the following Zenodo [repository](https://zenodo.org/doi/10.5281/zenodo.10850397).
85
+
86
+ You can also look at the code in a Jupyter notebook found [here](https://github.com/axelalmet/flowsig/blob/main/flowsig/tutorials/pancreatic_islets_scrnaseq_example.ipynb).
87
+
88
+ ### Import packages
89
+ ```
90
+ import flowsig as fs
91
+ import scanpy as sc
92
+ import pandas as pd
93
+ ```
94
+
95
+ ### Load the data and cell-cell communication inference
96
+
97
+ Data is specified in the form of a [Scanpy](https://scanpy.readthedocs.io/en/stable/) object, which is really just an annotated dataframe, i.e. [AnnData](https://anndata.readthedocs.io/en/latest/) object. All subsequent output generated from FlowSig is stored in the Scanpy object.
98
+
99
+ ```
100
+ data_directory = '../data/'
101
+
102
+ # Load the scanpy object
103
+ adata = sc.read(data_directory + 'burkhardt21_merged.h5ad')
104
+ condition_key = 'Condition'
105
+
106
+ # Load the cell-cell communication inference
107
+ cellchat_Ctrl = pd.read_csv('../communication_inference/output/burkhardt21_leiden_communications_Ctrl.csv')
108
+ cellchat_IFNg = pd.read_csv('../communication_inference/output/burkhardt21_leiden_communications_IFNg.csv')
109
+
110
+ cellchat_output_key = 'cellchat_output'
111
+ # Make sure your keys for the cellchat output dictionary match the relevant condition labels
112
+ adata.uns[cellchat_output_key] = {'Ctrl': cellchat_Ctrl,
113
+ 'IFNg': cellchat_IFNg}
114
+ ```
115
+
116
+ ### Construct GEMs
117
+ We now construct gene expression modules (GEMs) from the unnormalised count data. For non-spatial scRNA-seq where we have multiple conditions, we use the iNMF algorithm by [pyliger](https://github.com/welch-lab/pyliger).
118
+
119
+ ```
120
+ fs.pp.construct_gems_using_pyliger(adata,
121
+ n_gems = 10,
122
+ layer_key = 'counts',
123
+ condition_key = condition_key)
124
+ ```
125
+
126
+ ### Construct the flow expression matrices
127
+ We construct augmented flow expression matrices for each condition that measure three types of variables:
128
+ 1. Intercellular signal inflow, i.e., how much of a signal did a cell _receive_. For non-spatial scRNA-seq, signal inflow is defined as receptor gene expression weighted by the average expression of immediate downstream transcription factors that indicate signal activation.
129
+ 2. GEMs, which encapsulate intracellular information processing. We define these as cellwise membership to the GEM.
130
+ 3. Intercellular signal outflow, i.e., how much of a signal did a cell _send_. These are simply ligand gene expression.
131
+
132
+
133
+ The kay assumption of flowsig is that all intercellular information flows are directed from signal inflows to GEMs, from one GEM to another GEM, and from GEMs to signal outflows.
134
+
135
+ For non-spatial scRNA-seq, we need to specify the model organism so that FlowSig knows which receptor-transcription factor targets list to look at.
136
+ ```
137
+ fs.pp.construct_flow_expressions(adata,
138
+ cellchat_output_key=cellchat_output_key,
139
+ model_organism = 'human',
140
+ spatial = False,
141
+ method = 'cellchat'
142
+ )
143
+ ```
144
+
145
+
146
+ To reduce the number of variables over which we have to infer intercellular flows—and thus computation time—and to prioritise 'informative variables', we only retain inflow and outflow signals that are sufficiently _differentially flowing_ between the control and perturbed conditions. We determine differentially flowing signals using a Wilcoxon rank-sum test and retain variables only if they are below a specified adjusted p-value threshold (q-value) and above a specified log-fold-change threshold.
147
+
148
+ ```
149
+ fs.pp.ddetermine_informative_variables(adata,
150
+ spatial = False,
151
+ condition_key = 'Condition',
152
+ control = 'Ctrl',
153
+ qval_threshold = 0.05,
154
+ logfc_threshold = 0.5)
155
+ ```
156
+
157
+ If you wanted to visualise which variables remained, e.g., which are differentially outflowing, you can run the following code:
158
+ ```
159
+ fig, ax = plt.subplots(figsize=(6, 4))
160
+ fs.pl.plot_differentially_flowing_signals(adata,
161
+ condition_key = 'Condition',
162
+ pert_key = 'IFNg',
163
+ var_type = 'outflow',
164
+ flowsig_expr_key = 'X_flow_orig',
165
+ flowsig_network_key = 'flowsig_network_orig',
166
+ qval_threshold = 0.05,
167
+ logfc_threshold = 0.5,
168
+ label_lowqval = True,
169
+ ax=ax
170
+ )
171
+ plt.show()
172
+ ```
173
+ Setting pert_key='IFNg orients results so that those upregulated in the perturbed condition have positive log fold change. Note also that you also need to set `flowsig_expr_key = 'X_flow_orig'` and `flowsig_network_key = 'flowsig_network_orig'` to visualise both significant and non-significant variables.
174
+ ### Learn intercellular flows
175
+
176
+ We are now in a position to learn the intercellular flows. To increase reliability of objects, we bootstrap aggregate results over a number of realisations. For non-spatial data, we have to specify the condition label and the control condition.
177
+
178
+ This step uses [UT-IGSP](https://uhlerlab.github.io/causaldag/utigsp.html) to learn what is called a completed partially directed acyclic graph (CPDAG), which encodes directed arcs and undirected edges that describe the Markov Equivalence Class of statistical dependence relations that were learned directly from the data using conditional independence testing (how do variables depend on one another) and conditional invariance testing (which variables changed significantly between conditions). For both tests, we use a parametric partial-correlation-based method. The main reason we used these tests were because they take the least time to run compared to nonparametric kernel-based tests. Any test like the Hilbert-Schmidt Independence Criterion takes way too long for even 10-20 variables. The big caveat is that partial correlation assumes the data is described by a linear Gaussian model, which obviously isn't true for scRNA-seq. It's a long-term goal to add different types of nonparametric conditional independence/invariance tests that can be run in a reasonable amount of time.
179
+
180
+ ```
181
+ fs.tl.learn_intercellular_flows(adata,
182
+ condition_key = condition_key,
183
+ control = 'Ctrl',
184
+ use_spatial = False,
185
+ n_jobs = 4,
186
+ n_bootstraps = 500)
187
+ ```
188
+ ### Partially validate intercellular flow network
189
+
190
+ Finally, we will remove any "false positive" edges. Noting that the CPDAG contains directed arcs and undirected arcs we do two things.
191
+
192
+ First, we remove directed arcs that are not oriented from signal inflow to GEM, GEM to GEM, or from GEM to signal outflow and for undirected edges, we reorient them so that they obey the previous directionalities.
193
+
194
+ ```
195
+ fs.tl.apply_biological_flow(adata,
196
+ adjacency_key = 'adjacency',
197
+ validated_key = 'validated')
198
+ ```
199
+
200
+ Second, we will remove directed arcs whose bootstrapped frequencies are below a specified edge threshold as well as undirected edges whose total bootstrapped frequencies are below the same threshold.
201
+
202
+ ```
203
+ edge_threshold = 0.7
204
+ fs.tl.filter_low_confidence_edges(adata,
205
+ edge_threshold = edge_threshold,
206
+ adjacency_key = 'adjacency_validated',
207
+ filtered_key = 'filtered')
208
+ ```
209
+
210
+ Every time we apply these steps, we generate a new adjacency matrix that describes the intercellular flow network edges. The original output from `learn_intercellular_flows` is stored in `adata.uns['flowsig_network]['network']['adjacency']`. After validation using `apply_biological_flow`, we add the `_validated` key to the adjacency key, so that the new adjacency is stored in `adata.uns['flowsig_network]['network']['adjacency_validated']`. After filtering low-confidence edges, the adjacency is stored under `adata.uns['flowsig_network]['network']['adjacency_validated_filtered']`. As a note, you could change the order of these two post-processing steps, which would mean that the final adjacency would be under the key `adjacency_filtered_validated`. The results should be similar but it's worth remembering this.
211
+
212
+ We also note that if you want to explore the network directly, we included a function to generate the directed [NetworkX](https://networkx.org/documentation/stable/index.html) `DiGraph` object. You will need to generate this for any of the plotting functions.
213
+
214
+ ```
215
+ flow_network = fs.tl.construct_intercellular_flow_network(adata,
216
+ flowsig_network_key = 'flowsig_network',
217
+ adjacency_key = 'adjacency_validated_filtered')
218
+ ```
219
+
220
+ ### Visualise the intercellular flow network
221
+ To plot the entire intercellular flow network, having obtained `flow_network` from `fs.tl.construct_intercellular_flow_network`, you can run something like:
222
+
223
+ ```
224
+ fig, ax = plt.subplots(figsize=(6, 4))
225
+ fs.pl.plot_intercellular_flows(adata,
226
+ flow_network = flow_network,
227
+ flowsig_network_key = 'flowsig_network',
228
+ align_mode = 'horizontal',
229
+ width_scale = 2.0,
230
+ x_margin_offset = 0.3,
231
+ y_margin_offset = 0.0,
232
+ ax=ax)
233
+ plt.show()
234
+ ```
235
+ If you want to look at the flows induced by a specific inflow variable, you can set inflow_vars, e.g.:
236
+ ```
237
+ fig, ax = plt.subplots(figsize=(6, 4))
238
+ fs.pl.plot_intercellular_flows(adata,
239
+ flow_network = flow_network,
240
+ inflow_vars = ['SSTR2'],
241
+ flowsig_network_key = 'flowsig_network',
242
+ align_mode = 'horizontal',
243
+ width_scale = 2.0,
244
+ x_margin_offset = 0.3,
245
+ y_margin_offset = 0.0,
246
+ ax=ax)
247
+ plt.show()
248
+ ```
249
+
250
+ </details>
251
+
252
+ <details>
253
+ <summary>Spatial example</summary>
254
+
255
+ ## Application to spatial Stereo-seq of E9.5 mouse embryo
256
+ Here, we show how to apply FlowSig to a spatial Stereo-seq dataset of an E9.5 mouse embryo, as originally studied in [Chen et al. (2022)](https://doi.org/10.1016/j.cell.2022.04.003).
257
+ The processed data and cell-cell communication inference, which was obtained using [COMMOT](https://commot.readthedocs.io/en/latest/tutorials.html),
258
+ can be downloaded from the following Zenodo [repository](https://zenodo.org/doi/10.5281/zenodo.10850397).
259
+
260
+ You can also look at the code in a Jupyter notebook found [here](https://github.com/axelalmet/flowsig/blob/main/flowsig/tutorials/mouse_embryo_stereoseq_example.ipynb).
261
+
262
+ ### Import packages
263
+ ```
264
+ import flowsig as fs
265
+ import scanpy as sc
266
+ import pandas as pd
267
+ ```
268
+
269
+ ### Load the data and cell-cell communication inference
270
+
271
+ We load the data as an `AnnData` object, which has been subsetted for spatially variable genes only and includes the output from COMMOT already. We note here that COMMOT uses the CellChat database by default and we need to specify where it's been stored.
272
+
273
+ ```
274
+ data_directory = '../data/'
275
+
276
+ # Load the scanpy object
277
+ adata = sc.read(data_directory + 'chen22_E9.5_svg.h5ad')
278
+ commot_output_key = 'commot-cellchat'
279
+ ```
280
+
281
+ ### Construct GEMs
282
+ We now construct gene expression modules (GEMs) from the unnormalised count data. For ST data, we use [NSF](https://github.com/willtownes/spatial-factorization-py).
283
+
284
+ ```
285
+ fs.pp.construct_gems_using_nsf(adata,
286
+ n_gems = 20,
287
+ layer_key = 'count',
288
+ n_inducing_pts = 500,
289
+ length_scale = 10)
290
+ ```
291
+
292
+ ### Construct the flow expression matrices
293
+ We construct augmented flow expression matrices for each condition that measure three types of variables:
294
+ 1. Intercellular signal inflow, i.e., how much of a signal did a cell _receive_. For ST data, signal inflow is constructed by summing the received signals for each significant ligand inferred by COMMOT.
295
+ 2. GEMs, which encapsulate intracellular information processing. We define these as cellwise membership to the GEM.
296
+ 3. Intercellular signal outflow, i.e., how much of a signal did a cell _send_. These are simply ligand gene expression.
297
+
298
+ The kay assumption of flowsig is that all intercellular information flows are directed from signal inflows to GEMs, from one GEM to another GEM, and from GEMs to signal outflows.
299
+
300
+ For spatial data, we use COMMOT output directly to construct signal inflow expression and do not need knowledge about TF databases.
301
+ ```
302
+ fs.pp.construct_flow_expressions(adata,
303
+ commot_output_key=commot_output_key,
304
+ spatial = True)
305
+ ```
306
+
307
+ For spatial data, we retain spatially informative variables, which we determine by calculating the Moran's I value for signal inflow and signal outflow variables. In case the spatial graph has not been calculated for this data yet, FlowSig will do so, meaning that we need to specify both the coordinate type, `grid` or `generic`, and in the case of the former, `n_neighs`, which in this case, is 8.
308
+
309
+ Flow expression variables are defined to be spatially informative if their Moran's I value is above a specified threshold.
310
+
311
+ ```
312
+ fs.pp.determine_informative_variables(adata,
313
+ spatial = True,
314
+ moran_threshold = 0.15,
315
+ coord_type = 'grid',
316
+ n_neighbours = 8,
317
+ library_key = None)
318
+ ```
319
+
320
+ ### Learn intercellular flows
321
+ For spatial data, where there are far fewer "control _vs._ perturbed" studies, we use the [GSP](https://graphical-model-learning.readthedocs.io/en/latest/dags/generated/graphical_model_learning.gsp.html) method, which uses conditional independence testing and a greedy algorithm to learn the CPDAG containing directed arcs and undirected edges.
322
+
323
+ For spatial data, we cannot bootstrap by resampling across individual cells because we would lose the additional layer of correlation contained in the spatial data. Rather, we divide the tissue up into spatial "blocks" and resample within blocks. This is known as block bootstrapping.
324
+
325
+ To calculate the blocks, we used scikit-learn's [k-means](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html) clustering method to generate 20 roughly equally sized spatial blocks.
326
+
327
+ ```
328
+ from sklearn.cluster import KMeans
329
+
330
+ kmeans = KMeans(n_clusters=20, random_state=0).fit(adata.obsm['spatial'])
331
+ adata.obs['spatial_kmeans'] = pd.Series(kmeans.labels_, dtype='category').values
332
+ ```
333
+ We use these blocks to learn the spatial intercellular flows.
334
+
335
+ ```
336
+ fs.tl.learn_intercellular_flows(adata,
337
+ use_spatial = True,
338
+ block_key = 'spatial_kmeans',
339
+ n_jobs = 4,
340
+ n_bootstraps = 500)
341
+ ```
342
+ ### Partially validate intercellular flow network
343
+
344
+ Finally, we will remove any "false positive" edges. Noting that the CPDAG contains directed arcs and undirected arcs we do two things.
345
+
346
+ First, we remove directed arcs that are not oriented from signal inflow to GEM, GEM to GEM, or from GEM to signal outflow and for undirected edges, we reorient them so that they obey the previous directionalities.
347
+
348
+ ```
349
+ fs.tl.apply_biological_flow(adata,
350
+ flowsig_network_key = 'flowsig_network',
351
+ adjacency_key = 'adjacency',
352
+ validated_key = 'validated')
353
+ ```
354
+
355
+ Second, we will remove directed arcs whose bootstrapped frequencies are below a specified edge threshold as well as undirected edges whose total bootstrapped frequencies are below the same threshold. Because we did not have perturbation data, we specify a more stringent edge threshold.
356
+
357
+ ```
358
+ edge_threshold = 0.8
359
+ fs.tl.filter_low_confidence_edges(adata,
360
+ edge_threshold = edge_threshold,
361
+ flowsig_network_key = 'flowsig_network',
362
+ adjacency_key = 'adjacency_validated',
363
+ filtered_key = 'filtered')
364
+ ```
365
+
366
+ We can construct the directed [NetworkX](https://networkx.org/documentation/stable/index.html) `DiGraph` object from `adjacency_validated_filtered`.
367
+
368
+ ```
369
+ flow_network = fs.tl.construct_intercellular_flow_network(adata,
370
+ flowsig_network_key = 'flowsig_network',
371
+ adjacency_key = 'adjacency_validated_filtered')
372
+ ```
373
+ </details>
374
+