codeconv 1.0.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.
@@ -0,0 +1,49 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ First public release. Accompanies Perik-Zavodskaia et al., *iScience* **29**, 116824 (2026), and the
6
+ STAR Protocols article describing its use end to end.
7
+
8
+ ### What it does
9
+
10
+ Reconstructs discrete, individually placed cells carrying absolute whole-transcriptome counts from
11
+ spot-based spatial transcriptomics, with no external single-cell reference, and writes them in the
12
+ 10x SpaceRanger layout so the result loads directly into Seurat, scanpy and CellChat.
13
+
14
+ ### Notable behaviour
15
+
16
+ - **Automated topic-number selection.** `recommend_k()` offers five rules; the default keeps the K
17
+ values whose held-out perplexity falls in the best 5% of the sweep by rank and returns the largest
18
+ of them. `step5_ksweep()` prints the recommendation, draws it and the low-perplexity band on the
19
+ K-sweep figure, accepts a manual `n_topics=` override, and warns when the recommendation lands on
20
+ `max_k` — which means the sweep was too narrow to bound K from above. The choice is published as
21
+ `codeconv.recommended_K`, and on the result object as `.k`, with `.summary()` returning the whole
22
+ sweep as a DataFrame.
23
+ - **Built-in species profiles.** Human and mouse live in the module as `DEFAULT_CONFIG`, so a fresh
24
+ install runs with nothing else to download. An external `codeconv_config.json` takes precedence
25
+ when one is passed; `write_default_config()` dumps the built-ins for editing.
26
+ - **Platform detection.** `step1_acquisition_and_anchoring()` identifies the input layout and reports
27
+ it. 10x Visium and DBiT-seq are read natively, the DBiT-seq channel width being taken from the
28
+ sample name when it carries one. `PLATFORM_PROFILES` holds the geometry, `SliceData.platform`
29
+ records what was used, and `platform=` overrides detection. Capture units at or below the size of
30
+ one cell are deliberately out of scope: there is nothing to deconvolve, and segmentation rather
31
+ than a mixture model is the appropriate step.
32
+ - **CellChat hand-off.** `cellchat_spatial_factors()` derives the pixel-to-micron ratio and tolerance
33
+ for a spatial CellChat analysis and reports how many within-spot cell pairs a given interaction
34
+ range captures — the check that communication inference is invariant to the sub-spot cell
35
+ placement. `step9_export_results()` records all of it in `run_summary.json`, so the downstream R
36
+ session reads one file instead of re-deriving unit conversions. The ratio is calibrated from the
37
+ array's documented spot pitch divided by the pitch measured on the slide, because neither the 55 µm
38
+ physical spot diameter nor CellChat's 65 µm convention reproduces the real geometry.
39
+ - **Streaming reader with a parse cache.** A multi-gigabyte dense count table is parsed row by row
40
+ into a sparse matrix and cached beside the source, so later loads take under a second.
41
+ - **Placeholder histology.** `make_dummy_tissue_image()` writes a black canvas with matching scale
42
+ factors for platforms that ship no registered image, so the export still loads in Seurat.
43
+
44
+ ### Note for users of the pre-release script
45
+
46
+ The first argument of `step1_acquisition_and_anchoring()` is now `spatial_path`, since the pipeline
47
+ is no longer Visium-only. The old `visium_path=` keyword still works and raises a
48
+ `DeprecationWarning`. `config_path` now defaults to `None` and `species` to `"hs"` on every step that
49
+ takes them.
codeconv-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Roman Perik-Zavodskii
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include README.md
2
+ include CHANGELOG.md
3
+ include LICENSE
4
+ include codeconv_config.json
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: codeconv
3
+ Version: 1.0.0
4
+ Summary: Reference-free single-cell-resolution deconvolution of spot-based spatial transcriptomics
5
+ Author: Roman Perik-Zavodskii, Saleh Alrhmoun
6
+ Author-email: Olga Perik-Zavodskaia <perik.zavodskaia@gmail.com>, Sergey Sennikov <sennikov@niikim.ru>
7
+ Maintainer-email: Olga Perik-Zavodskaia <perik.zavodskaia@gmail.com>
8
+ License-Expression: MIT
9
+ Project-URL: Homepage, https://github.com/Perik-Zavodskii/CoexpressDeconvolve
10
+ Project-URL: Repository, https://github.com/Perik-Zavodskii/CoexpressDeconvolve
11
+ Project-URL: Publication, https://doi.org/10.1016/j.isci.2026.116824
12
+ Project-URL: Archive, https://doi.org/10.5281/zenodo.21860849
13
+ Project-URL: Issues, https://github.com/Perik-Zavodskii/CoexpressDeconvolve/issues
14
+ Keywords: spatial transcriptomics,deconvolution,single-cell,Visium,DBiT-seq,topic model,bioinformatics
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: numpy>=1.21
29
+ Requires-Dist: pandas>=1.3
30
+ Requires-Dist: scipy>=1.7
31
+ Requires-Dist: scikit-learn>=1.0
32
+ Requires-Dist: matplotlib>=3.5
33
+ Requires-Dist: seaborn>=0.11
34
+ Requires-Dist: h5py>=3.1
35
+ Requires-Dist: tqdm>=4.62
36
+ Requires-Dist: umap-learn>=0.5.3
37
+ Provides-Extra: notebook
38
+ Requires-Dist: jupyter>=1.0; extra == "notebook"
39
+ Requires-Dist: ipywidgets>=8.0; extra == "notebook"
40
+ Provides-Extra: dev
41
+ Requires-Dist: pytest>=7.0; extra == "dev"
42
+ Requires-Dist: build>=1.0; extra == "dev"
43
+ Requires-Dist: twine>=4.0; extra == "dev"
44
+ Dynamic: license-file
45
+
46
+ # CoexpressDeconvolve
47
+
48
+ Spot-based spatial transcriptomics measures whole transcriptomes in place, but every spot pools
49
+ several cells, so a spot profile is a mixture rather than a cell. CoexpressDeconvolve resolves that
50
+ mixture into single-cell-like profiles, without needing a matched single-cell dataset to learn from.
51
+
52
+ The problem it addresses is that the usual route out of the mixture is a reference atlas, and a
53
+ reference is often unavailable, mismatched to the tissue, or missing the very populations that were
54
+ lost during dissociation. CoexpressDeconvolve works from the slide alone.
55
+
56
+ Three quantities carry the method. How many cells a spot captured is estimated from the
57
+ housekeeping-gene signal together with the total UMI count. Which expression programmes are present
58
+ is learned de novo from gene co-expression across the whole slide. How the spot's transcripts belong
59
+ to those cells follows from distributing its UMIs among them, conserving the per-spot total exactly:
60
+ the reconstructed cells of a spot add back up to the transcriptome measured there.
61
+
62
+ Each cell comes out with a whole transcriptome, absolute counts and a coordinate inside its parent
63
+ spot, written in the standard 10x SpaceRanger layout, so the result opens in Seurat or scanpy like
64
+ any other single-cell object.
65
+
66
+ Method and benchmarks: Perik-Zavodskaia, O., Perik-Zavodskii, R., Alrhmoun, S. & Sennikov, S.
67
+ *iScience* **29**, 116824 (2026). https://doi.org/10.1016/j.isci.2026.116824
68
+
69
+ ## Supported platforms
70
+
71
+ The platform is detected from the input layout and announced at load. Everything downstream is
72
+ platform-agnostic: Step 1 normalizes every input to counts, coordinates, a capture footprint and a
73
+ pitch.
74
+
75
+ | Platform | Capture unit | Pitch | Layout expected | Histology |
76
+ |---|---|---|---|---|
77
+ | **10x Visium** (any capture area) | 55 µm | 100 µm | SpaceRanger: `filtered_feature_bc_matrix.h5` (or the `.mtx` folder) + `spatial/` | yes |
78
+ | **DBiT-seq** | 10 / 25 / 50 µm | 2 × channel width | one count table on the 50 × 50 grid, labels `AxB` | no |
79
+
80
+ The DBiT-seq channel width is read from the sample name when it carries one (`GSM4189611_50t` -> 50 µm),
81
+ and the pitch is twice the width. Platforms that ship no tissue image get a black placeholder canvas
82
+ sized to the capture grid, with synthesized scale factors, so `Seurat::Load10X_Spatial()` and every
83
+ spatial plot still work.
84
+
85
+ Capture units at or below the size of one cell are out of scope: there is nothing to deconvolve, and
86
+ segmentation rather than a mixture model is the right step there.
87
+
88
+ ## Installation
89
+
90
+ ```bash
91
+ pip install codeconv
92
+ ```
93
+
94
+ Human (`hs`) and mouse (`mm`) species profiles are built into the module, so nothing else has to be
95
+ downloaded to get started.
96
+
97
+ ## Usage
98
+
99
+ ```python
100
+ import codeconv
101
+ codeconv.set_seed(42)
102
+
103
+ spatial_path = "./Glioblastoma"
104
+ output_folder = "."
105
+ species = "hs" # "hs" | "mm" | anything in your config
106
+
107
+ slices = codeconv.step1_acquisition_and_anchoring(spatial_path)
108
+ slices = codeconv.step2_estimate_cell_density(slices, species=species,
109
+ min_umi=900, anchor_mean_factor=0.7)
110
+ odg_pack = codeconv.step3_feature_selection(slices, species=species, n_odg=3000)
111
+ manifold = codeconv.step4_gene_manifold(slices, odg_pack, n_components=30)
112
+
113
+ ksweep = codeconv.step5_ksweep(odg_pack, min_k=3, max_k=15)
114
+ print(ksweep.summary()) # per-K perplexity, rare topics, which K are in the low band
115
+
116
+ model = codeconv.step6_final_deconvolution(slices, odg_pack, manifold,
117
+ n_topics=codeconv.recommended_K, # or your own K
118
+ k_neighbors=3)
119
+ cells = codeconv.step7_sampling_engine(slices, model, species=species)
120
+ codeconv.step8_geometry_and_placement(cells, slices)
121
+ codeconv.step9_export_results(cells, slices, output_folder, interaction_range_um=50.0)
122
+ ```
123
+
124
+ ### Several slices at once
125
+
126
+ Pass a dict instead of a string. Topics are aligned across slices, so the reconstructed cell types
127
+ are comparable between samples:
128
+
129
+ ```python
130
+ spatial_path = {"sample_A": "./A", "sample_B": "./B"}
131
+ ```
132
+
133
+ Per-slice parameters (`min_umi`, `anchor_mean_factor`, `low_slice_quality`) take either a scalar,
134
+ broadcast to every slice, or a dict keyed by slice name:
135
+
136
+ ```python
137
+ slices = codeconv.step2_estimate_cell_density(
138
+ slices, species="hs",
139
+ min_umi={"sample_A": 900, "sample_B": 1200},
140
+ anchor_mean_factor=0.7,
141
+ )
142
+ ```
143
+
144
+ A list of paths also works, with slice names taken from the folder names.
145
+
146
+ ### Choosing K automatically
147
+
148
+ The number of topics used to be a visual judgement call. It no longer is:
149
+
150
+ ```python
151
+ ksweep = codeconv.step5_ksweep(odg_pack, min_k=3, max_k=15) # prints the recommendation
152
+ ```
153
+
154
+ The default rule keeps every K whose held-out perplexity lands in the best 5% of the sweep by rank
155
+ and returns the **largest** of them, which is the highest K still in the low-perplexity regime. That
156
+ is deliberate: because CoexpressDeconvolve returns individual cells rather than fractions, a rare
157
+ topic is a minor cell population worth recovering, not evidence of over-splitting. Alternatives:
158
+
159
+ ```python
160
+ codeconv.recommend_k(ksweep.perplexity['Glioblastoma'], rule="relative_tolerance", tol=0.01)
161
+ codeconv.recommend_k(ksweep.perplexity['Glioblastoma'], rule="lowest_perplexity")
162
+ ```
163
+
164
+ A recommendation landing on `max_k` means perplexity had not turned back up yet and the sweep is too
165
+ narrow; you get a warning. Pass `n_topics=` to record a manual choice, and it is drawn on the plot
166
+ next to the automatic one.
167
+
168
+ ### The 9 steps
169
+
170
+ 1. **Acquisition** - detect the platform, load counts and coordinates, per-spot UMI QC.
171
+ 2. **Density** - cells per spot from a hybrid housekeeping/UMI calibration. `low_slice_quality=True`
172
+ enforces a floor of one cell on every spot passing the UMI gate.
173
+ 3. **Feature selection** - noise-gene regex, presence filter, overdispersed genes from the
174
+ mean-variance trend.
175
+ 4. **Manifold** - joint gene co-expression topology via ICA + UMAP.
176
+ 5. **K-sweep** - held-out perplexity across K, rare-topic counts, automatic recommendation.
177
+ 6. **Deconvolution** - per-slice LDA, Hungarian topic alignment across slices, mean-consensus beta,
178
+ per-slice theta refit against the frozen consensus, projection onto each slice's full gene list.
179
+ 7. **Sampling** - discrete cells drawn per spot; per-spot UMI totals are conserved exactly.
180
+ 8. **Placement** - cells positioned inside their parent spot footprint by Vogel packing.
181
+ 9. **Export** - 10x layout under `output_folder/slice_<name>/deconvolved/`, one folder per slice.
182
+
183
+ ## Downstream analysis
184
+
185
+ Each slice exports a `filtered_feature_bc_matrix.h5` and a `spatial/` folder. From there the
186
+ reconstruction is an ordinary single-cell spatial object and goes wherever such objects go:
187
+
188
+ ```r
189
+ library(Seurat)
190
+ seurat_obj <- Load10X_Spatial("./slice_Glioblastoma/deconvolved")
191
+ ```
192
+
193
+ ```python
194
+ import scanpy as sc
195
+ adata = sc.read_visium("./slice_Glioblastoma/deconvolved")
196
+ ```
197
+
198
+ Clustering, annotation, trajectory inference, cell-cell communication - anything that takes a
199
+ single-cell object works, with no adapters. `Seurat Spatial.ipynb` in the repository is a worked
200
+ example. Topics are aligned across slices, so cluster comparison between samples is meaningful.
201
+
202
+ ## Citation
203
+
204
+ ```bibtex
205
+ @article{PerikZavodskaia2026CoexpressDeconvolve,
206
+ title = {CoexpressDeconvolve enables reference-free single-cell-resolution
207
+ deconvolution from spot-based spatial transcriptomics},
208
+ author = {Perik-Zavodskaia, Olga and Perik-Zavodskii, Roman and
209
+ Alrhmoun, Saleh and Sennikov, Sergey},
210
+ journal = {iScience},
211
+ volume = {29},
212
+ pages = {116824},
213
+ year = {2026},
214
+ doi = {10.1016/j.isci.2026.116824}
215
+ }
216
+ ```
217
+
218
+ ## License
219
+
220
+ MIT, see `LICENSE`.
@@ -0,0 +1,175 @@
1
+ # CoexpressDeconvolve
2
+
3
+ Spot-based spatial transcriptomics measures whole transcriptomes in place, but every spot pools
4
+ several cells, so a spot profile is a mixture rather than a cell. CoexpressDeconvolve resolves that
5
+ mixture into single-cell-like profiles, without needing a matched single-cell dataset to learn from.
6
+
7
+ The problem it addresses is that the usual route out of the mixture is a reference atlas, and a
8
+ reference is often unavailable, mismatched to the tissue, or missing the very populations that were
9
+ lost during dissociation. CoexpressDeconvolve works from the slide alone.
10
+
11
+ Three quantities carry the method. How many cells a spot captured is estimated from the
12
+ housekeeping-gene signal together with the total UMI count. Which expression programmes are present
13
+ is learned de novo from gene co-expression across the whole slide. How the spot's transcripts belong
14
+ to those cells follows from distributing its UMIs among them, conserving the per-spot total exactly:
15
+ the reconstructed cells of a spot add back up to the transcriptome measured there.
16
+
17
+ Each cell comes out with a whole transcriptome, absolute counts and a coordinate inside its parent
18
+ spot, written in the standard 10x SpaceRanger layout, so the result opens in Seurat or scanpy like
19
+ any other single-cell object.
20
+
21
+ Method and benchmarks: Perik-Zavodskaia, O., Perik-Zavodskii, R., Alrhmoun, S. & Sennikov, S.
22
+ *iScience* **29**, 116824 (2026). https://doi.org/10.1016/j.isci.2026.116824
23
+
24
+ ## Supported platforms
25
+
26
+ The platform is detected from the input layout and announced at load. Everything downstream is
27
+ platform-agnostic: Step 1 normalizes every input to counts, coordinates, a capture footprint and a
28
+ pitch.
29
+
30
+ | Platform | Capture unit | Pitch | Layout expected | Histology |
31
+ |---|---|---|---|---|
32
+ | **10x Visium** (any capture area) | 55 µm | 100 µm | SpaceRanger: `filtered_feature_bc_matrix.h5` (or the `.mtx` folder) + `spatial/` | yes |
33
+ | **DBiT-seq** | 10 / 25 / 50 µm | 2 × channel width | one count table on the 50 × 50 grid, labels `AxB` | no |
34
+
35
+ The DBiT-seq channel width is read from the sample name when it carries one (`GSM4189611_50t` -> 50 µm),
36
+ and the pitch is twice the width. Platforms that ship no tissue image get a black placeholder canvas
37
+ sized to the capture grid, with synthesized scale factors, so `Seurat::Load10X_Spatial()` and every
38
+ spatial plot still work.
39
+
40
+ Capture units at or below the size of one cell are out of scope: there is nothing to deconvolve, and
41
+ segmentation rather than a mixture model is the right step there.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install codeconv
47
+ ```
48
+
49
+ Human (`hs`) and mouse (`mm`) species profiles are built into the module, so nothing else has to be
50
+ downloaded to get started.
51
+
52
+ ## Usage
53
+
54
+ ```python
55
+ import codeconv
56
+ codeconv.set_seed(42)
57
+
58
+ spatial_path = "./Glioblastoma"
59
+ output_folder = "."
60
+ species = "hs" # "hs" | "mm" | anything in your config
61
+
62
+ slices = codeconv.step1_acquisition_and_anchoring(spatial_path)
63
+ slices = codeconv.step2_estimate_cell_density(slices, species=species,
64
+ min_umi=900, anchor_mean_factor=0.7)
65
+ odg_pack = codeconv.step3_feature_selection(slices, species=species, n_odg=3000)
66
+ manifold = codeconv.step4_gene_manifold(slices, odg_pack, n_components=30)
67
+
68
+ ksweep = codeconv.step5_ksweep(odg_pack, min_k=3, max_k=15)
69
+ print(ksweep.summary()) # per-K perplexity, rare topics, which K are in the low band
70
+
71
+ model = codeconv.step6_final_deconvolution(slices, odg_pack, manifold,
72
+ n_topics=codeconv.recommended_K, # or your own K
73
+ k_neighbors=3)
74
+ cells = codeconv.step7_sampling_engine(slices, model, species=species)
75
+ codeconv.step8_geometry_and_placement(cells, slices)
76
+ codeconv.step9_export_results(cells, slices, output_folder, interaction_range_um=50.0)
77
+ ```
78
+
79
+ ### Several slices at once
80
+
81
+ Pass a dict instead of a string. Topics are aligned across slices, so the reconstructed cell types
82
+ are comparable between samples:
83
+
84
+ ```python
85
+ spatial_path = {"sample_A": "./A", "sample_B": "./B"}
86
+ ```
87
+
88
+ Per-slice parameters (`min_umi`, `anchor_mean_factor`, `low_slice_quality`) take either a scalar,
89
+ broadcast to every slice, or a dict keyed by slice name:
90
+
91
+ ```python
92
+ slices = codeconv.step2_estimate_cell_density(
93
+ slices, species="hs",
94
+ min_umi={"sample_A": 900, "sample_B": 1200},
95
+ anchor_mean_factor=0.7,
96
+ )
97
+ ```
98
+
99
+ A list of paths also works, with slice names taken from the folder names.
100
+
101
+ ### Choosing K automatically
102
+
103
+ The number of topics used to be a visual judgement call. It no longer is:
104
+
105
+ ```python
106
+ ksweep = codeconv.step5_ksweep(odg_pack, min_k=3, max_k=15) # prints the recommendation
107
+ ```
108
+
109
+ The default rule keeps every K whose held-out perplexity lands in the best 5% of the sweep by rank
110
+ and returns the **largest** of them, which is the highest K still in the low-perplexity regime. That
111
+ is deliberate: because CoexpressDeconvolve returns individual cells rather than fractions, a rare
112
+ topic is a minor cell population worth recovering, not evidence of over-splitting. Alternatives:
113
+
114
+ ```python
115
+ codeconv.recommend_k(ksweep.perplexity['Glioblastoma'], rule="relative_tolerance", tol=0.01)
116
+ codeconv.recommend_k(ksweep.perplexity['Glioblastoma'], rule="lowest_perplexity")
117
+ ```
118
+
119
+ A recommendation landing on `max_k` means perplexity had not turned back up yet and the sweep is too
120
+ narrow; you get a warning. Pass `n_topics=` to record a manual choice, and it is drawn on the plot
121
+ next to the automatic one.
122
+
123
+ ### The 9 steps
124
+
125
+ 1. **Acquisition** - detect the platform, load counts and coordinates, per-spot UMI QC.
126
+ 2. **Density** - cells per spot from a hybrid housekeeping/UMI calibration. `low_slice_quality=True`
127
+ enforces a floor of one cell on every spot passing the UMI gate.
128
+ 3. **Feature selection** - noise-gene regex, presence filter, overdispersed genes from the
129
+ mean-variance trend.
130
+ 4. **Manifold** - joint gene co-expression topology via ICA + UMAP.
131
+ 5. **K-sweep** - held-out perplexity across K, rare-topic counts, automatic recommendation.
132
+ 6. **Deconvolution** - per-slice LDA, Hungarian topic alignment across slices, mean-consensus beta,
133
+ per-slice theta refit against the frozen consensus, projection onto each slice's full gene list.
134
+ 7. **Sampling** - discrete cells drawn per spot; per-spot UMI totals are conserved exactly.
135
+ 8. **Placement** - cells positioned inside their parent spot footprint by Vogel packing.
136
+ 9. **Export** - 10x layout under `output_folder/slice_<name>/deconvolved/`, one folder per slice.
137
+
138
+ ## Downstream analysis
139
+
140
+ Each slice exports a `filtered_feature_bc_matrix.h5` and a `spatial/` folder. From there the
141
+ reconstruction is an ordinary single-cell spatial object and goes wherever such objects go:
142
+
143
+ ```r
144
+ library(Seurat)
145
+ seurat_obj <- Load10X_Spatial("./slice_Glioblastoma/deconvolved")
146
+ ```
147
+
148
+ ```python
149
+ import scanpy as sc
150
+ adata = sc.read_visium("./slice_Glioblastoma/deconvolved")
151
+ ```
152
+
153
+ Clustering, annotation, trajectory inference, cell-cell communication - anything that takes a
154
+ single-cell object works, with no adapters. `Seurat Spatial.ipynb` in the repository is a worked
155
+ example. Topics are aligned across slices, so cluster comparison between samples is meaningful.
156
+
157
+ ## Citation
158
+
159
+ ```bibtex
160
+ @article{PerikZavodskaia2026CoexpressDeconvolve,
161
+ title = {CoexpressDeconvolve enables reference-free single-cell-resolution
162
+ deconvolution from spot-based spatial transcriptomics},
163
+ author = {Perik-Zavodskaia, Olga and Perik-Zavodskii, Roman and
164
+ Alrhmoun, Saleh and Sennikov, Sergey},
165
+ journal = {iScience},
166
+ volume = {29},
167
+ pages = {116824},
168
+ year = {2026},
169
+ doi = {10.1016/j.isci.2026.116824}
170
+ }
171
+ ```
172
+
173
+ ## License
174
+
175
+ MIT, see `LICENSE`.