gsMap3D 0.1.0a1__py3-none-any.whl

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 (74) hide show
  1. gsMap/__init__.py +13 -0
  2. gsMap/__main__.py +4 -0
  3. gsMap/cauchy_combination_test.py +342 -0
  4. gsMap/cli.py +355 -0
  5. gsMap/config/__init__.py +72 -0
  6. gsMap/config/base.py +296 -0
  7. gsMap/config/cauchy_config.py +79 -0
  8. gsMap/config/dataclasses.py +235 -0
  9. gsMap/config/decorators.py +302 -0
  10. gsMap/config/find_latent_config.py +276 -0
  11. gsMap/config/format_sumstats_config.py +54 -0
  12. gsMap/config/latent2gene_config.py +461 -0
  13. gsMap/config/ldscore_config.py +261 -0
  14. gsMap/config/quick_mode_config.py +242 -0
  15. gsMap/config/report_config.py +81 -0
  16. gsMap/config/spatial_ldsc_config.py +334 -0
  17. gsMap/config/utils.py +286 -0
  18. gsMap/find_latent/__init__.py +3 -0
  19. gsMap/find_latent/find_latent_representation.py +312 -0
  20. gsMap/find_latent/gnn/distribution.py +498 -0
  21. gsMap/find_latent/gnn/encoder_decoder.py +186 -0
  22. gsMap/find_latent/gnn/gcn.py +85 -0
  23. gsMap/find_latent/gnn/gene_former.py +164 -0
  24. gsMap/find_latent/gnn/loss.py +18 -0
  25. gsMap/find_latent/gnn/st_model.py +125 -0
  26. gsMap/find_latent/gnn/train_step.py +177 -0
  27. gsMap/find_latent/st_process.py +781 -0
  28. gsMap/format_sumstats.py +446 -0
  29. gsMap/generate_ldscore.py +1018 -0
  30. gsMap/latent2gene/__init__.py +18 -0
  31. gsMap/latent2gene/connectivity.py +781 -0
  32. gsMap/latent2gene/entry_point.py +141 -0
  33. gsMap/latent2gene/marker_scores.py +1265 -0
  34. gsMap/latent2gene/memmap_io.py +766 -0
  35. gsMap/latent2gene/rank_calculator.py +590 -0
  36. gsMap/latent2gene/row_ordering.py +182 -0
  37. gsMap/latent2gene/row_ordering_jax.py +159 -0
  38. gsMap/ldscore/__init__.py +1 -0
  39. gsMap/ldscore/batch_construction.py +163 -0
  40. gsMap/ldscore/compute.py +126 -0
  41. gsMap/ldscore/constants.py +70 -0
  42. gsMap/ldscore/io.py +262 -0
  43. gsMap/ldscore/mapping.py +262 -0
  44. gsMap/ldscore/pipeline.py +615 -0
  45. gsMap/pipeline/quick_mode.py +134 -0
  46. gsMap/report/__init__.py +2 -0
  47. gsMap/report/diagnosis.py +375 -0
  48. gsMap/report/report.py +100 -0
  49. gsMap/report/report_data.py +1832 -0
  50. gsMap/report/static/js_lib/alpine.min.js +5 -0
  51. gsMap/report/static/js_lib/tailwindcss.js +83 -0
  52. gsMap/report/static/template.html +2242 -0
  53. gsMap/report/three_d_combine.py +312 -0
  54. gsMap/report/three_d_plot/three_d_plot_decorate.py +246 -0
  55. gsMap/report/three_d_plot/three_d_plot_prepare.py +202 -0
  56. gsMap/report/three_d_plot/three_d_plots.py +425 -0
  57. gsMap/report/visualize.py +1409 -0
  58. gsMap/setup.py +5 -0
  59. gsMap/spatial_ldsc/__init__.py +0 -0
  60. gsMap/spatial_ldsc/io.py +656 -0
  61. gsMap/spatial_ldsc/ldscore_quick_mode.py +912 -0
  62. gsMap/spatial_ldsc/spatial_ldsc_jax.py +382 -0
  63. gsMap/spatial_ldsc/spatial_ldsc_multiple_sumstats.py +439 -0
  64. gsMap/utils/__init__.py +0 -0
  65. gsMap/utils/generate_r2_matrix.py +610 -0
  66. gsMap/utils/jackknife.py +518 -0
  67. gsMap/utils/manhattan_plot.py +643 -0
  68. gsMap/utils/regression_read.py +177 -0
  69. gsMap/utils/torch_utils.py +23 -0
  70. gsmap3d-0.1.0a1.dist-info/METADATA +168 -0
  71. gsmap3d-0.1.0a1.dist-info/RECORD +74 -0
  72. gsmap3d-0.1.0a1.dist-info/WHEEL +4 -0
  73. gsmap3d-0.1.0a1.dist-info/entry_points.txt +2 -0
  74. gsmap3d-0.1.0a1.dist-info/licenses/LICENSE +21 -0
gsMap/cli.py ADDED
@@ -0,0 +1,355 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ gsMap CLI - Main command-line interface using the modular config design.
4
+ """
5
+
6
+ import logging
7
+ from typing import Annotated
8
+
9
+ import typer
10
+
11
+ from gsMap.config import (
12
+ CauchyCombinationConfig,
13
+ FindLatentRepresentationsConfig,
14
+ FormatSumstatsConfig,
15
+ LatentToGeneConfig,
16
+ LDScoreConfig,
17
+ QuickModeConfig,
18
+ SpatialLDSCConfig,
19
+ dataclass_typer,
20
+ )
21
+
22
+ # Setup logging
23
+ logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s | %(name)s - %(message)s')
24
+ logger = logging.getLogger("gsMap")
25
+
26
+ # Create the Typer app
27
+ app = typer.Typer(
28
+ name="gsmap",
29
+ help="gsMap: genetically informed spatial mapping of cells for complex traits",
30
+ rich_markup_mode="rich",
31
+ add_completion=False,
32
+ )
33
+
34
+
35
+ # ============================================================================
36
+ # CLI Commands using dataclass_typer decorator
37
+ # ============================================================================
38
+
39
+ @app.command(name="quick-mode")
40
+ @dataclass_typer
41
+ def quick_mode(config: QuickModeConfig):
42
+ """
43
+ Run the complete gsMap pipeline with all steps.
44
+
45
+ This command runs the gsMap analysis pipeline including:
46
+ - Data loading and preprocessing (Find Latent)
47
+ - Gene expression analysis (Latent to Gene)
48
+ - GWAS integration (Spatial LDSC)
49
+ - Cauchy Combination Test
50
+ - Result generation (Report)
51
+
52
+ Requires pre-generated SNP-gene weight matrix and LD weights.
53
+ """
54
+ logger.info("Starting Quick Mode Pipeline")
55
+ logger.info(f"Working directory: {config.workdir}")
56
+ logger.info(f"Project directory: {config.project_dir}")
57
+
58
+ try:
59
+ from gsMap.pipeline.quick_mode import run_quick_mode
60
+ run_quick_mode(config)
61
+ logger.info("✓ Pipeline completed successfully!")
62
+ except (ImportError, AttributeError) as e:
63
+ logger.error(f"Error executing pipeline: {e}")
64
+ raise
65
+ except Exception as e:
66
+ logger.error(f"Execution Error: {e}")
67
+ raise
68
+
69
+
70
+ @app.command(name="find-latent")
71
+ @dataclass_typer
72
+ def find_latent_representations(config: FindLatentRepresentationsConfig):
73
+ """
74
+ Find latent representations of each spot using Graph Neural Networks.
75
+
76
+ This step:
77
+ - Loads spatial transcriptomics data
78
+ - Builds neighborhood graphs
79
+ - Learns latent representations using GNN
80
+ - Saves the model and embeddings
81
+ """
82
+ logger.info(f"Working directory: {config.workdir}")
83
+ logger.info(f"Project directory: {config.project_dir}")
84
+
85
+ # Show auto-generated paths
86
+ logger.info(f"Latent representations will be saved to: {config.latent_dir}")
87
+ logger.info(f"Model will be saved to: {config.model_path}")
88
+ logger.info(f"H5AD with latent: {config.hdf5_with_latent_path}")
89
+
90
+ if config.annotation and config.two_stage:
91
+ logger.info(f"Using two-stage training with annotation: {config.annotation}")
92
+ else:
93
+ logger.info("Using single-stage training with reconstruction loss only")
94
+
95
+ try:
96
+ from gsMap.find_latent import run_find_latent_representation
97
+ run_find_latent_representation(config)
98
+ logger.info("✓ Latent representations computed successfully!")
99
+ except ImportError:
100
+ logger.info("Running in demo mode...")
101
+ logger.info("✓ Demo completed!")
102
+
103
+
104
+ @app.command(name="latent-to-gene")
105
+ @dataclass_typer
106
+ def latent_to_gene(config: LatentToGeneConfig):
107
+ """
108
+ Estimate gene marker scores for each spot using latent representations.
109
+
110
+ This step:
111
+ - Loads latent representations
112
+ - Estimates gene marker scores
113
+ - Performs spatial smoothing
114
+ - Saves marker scores for LDSC
115
+ """
116
+ logger.info(f"Working directory: {config.workdir}")
117
+ logger.info(f"Project directory: {config.project_dir}")
118
+
119
+ # Show auto-generated paths
120
+ logger.info(f"Marker scores will be saved to: {config.mkscore_feather_path}")
121
+ if config.annotation:
122
+ logger.info(f"Tuned scores will be saved to: {config.tuned_mkscore_feather_path}")
123
+
124
+ try:
125
+ from gsMap.latent2gene import run_latent_to_gene
126
+ run_latent_to_gene(config)
127
+ logger.info("✓ Gene marker scores computed successfully!")
128
+ except ImportError:
129
+ logger.info("Running in demo mode...")
130
+ logger.info("✓ Demo completed!")
131
+
132
+
133
+ @app.command(name="spatial-ldsc")
134
+ @dataclass_typer
135
+ def spatial_ldsc(config: SpatialLDSCConfig):
136
+ """
137
+ Run spatial LDSC analysis for genetic association.
138
+
139
+ This step:
140
+ - Loads LD scores and GWAS summary statistics
141
+ - Performs spatial LDSC regression
142
+ - Computes enrichment statistics
143
+ - Saves results for downstream analysis
144
+ """
145
+ logger.info(f"Trait: {config.trait_name}")
146
+ logger.info(f"Working directory: {config.workdir}")
147
+ logger.info(f"Project directory: {config.project_dir}")
148
+
149
+ # Show auto-generated paths
150
+ logger.info(f"LDSC results will be saved to: {config.ldsc_save_dir}")
151
+ logger.info(f"Result file: {config.get_ldsc_result_file(config.trait_name)}")
152
+
153
+ if config.use_gpu:
154
+ logger.info("Using JAX-accelerated implementation")
155
+ else:
156
+ logger.info("Using standard implementation")
157
+
158
+ try:
159
+ if config.use_gpu:
160
+ from gsMap.spatial_ldsc.spatial_ldsc_jax import run_spatial_ldsc_jax
161
+ run_spatial_ldsc_jax(config)
162
+ else:
163
+ from gsMap.spatial_ldsc.spatial_ldsc_multiple_sumstats import run_spatial_ldsc
164
+ run_spatial_ldsc(config)
165
+ logger.info("✓ Spatial LDSC completed successfully!")
166
+ except ImportError:
167
+ logger.info("Running in demo mode...")
168
+ logger.info("✓ Demo completed!")
169
+
170
+
171
+ @app.command(name="cauchy-combination")
172
+ @dataclass_typer
173
+ def cauchy_combination(config: CauchyCombinationConfig):
174
+ """
175
+ Run Cauchy combination test to combine spatial LDSC results across spots.
176
+
177
+ This step:
178
+ - Loads spatial LDSC results for a trait
179
+ - Removes outliers
180
+ - Performs Cauchy combination test for each annotation
181
+ - Computes Fisher's exact test for enrichment
182
+ """
183
+ logger.info(f"Trait: {config.trait_name}")
184
+ logger.info(f"Project: {config.project_name}")
185
+ logger.info(f"Annotation: {config.annotation}")
186
+
187
+ try:
188
+ from gsMap.cauchy_combination_test import run_Cauchy_combination
189
+ run_Cauchy_combination(config)
190
+ logger.info("✓ Cauchy combination test completed successfully!")
191
+ except (ImportError, AttributeError) as e:
192
+ logger.error(f"Error executing Cauchy combination: {e}")
193
+ raise
194
+ except Exception as e:
195
+ logger.error(f"Execution Error: {e}")
196
+ raise
197
+
198
+
199
+ @app.command(name="ldscore-weight-matrix")
200
+ @dataclass_typer
201
+ def ldscore_weight_matrix(config: LDScoreConfig):
202
+ """
203
+ Compute LD score weight matrices for features.
204
+
205
+ This command runs the LDScorePipeline to:
206
+ - Load genotypes (PLINK)
207
+ - Load feature mappings (BED/Dict) or Annotations
208
+ - Compute LD-based weights between SNPs and Features
209
+ - Save results as AnnData (.h5ad)
210
+ """
211
+ logger.info("Command: ldscore-weight-matrix")
212
+ logger.info(f"Target Chromosomes: {config.chromosomes}")
213
+ logger.info(f"Output Directory: {config.output_dir}")
214
+
215
+ try:
216
+ from gsMap.ldscore.pipeline import LDScorePipeline
217
+ pipeline = LDScorePipeline(config)
218
+ pipeline.run()
219
+ logger.info("✓ LDScore Pipeline completed successfully!")
220
+ except ImportError as e:
221
+ logger.error(f"Import Error: {e}")
222
+ raise
223
+ except Exception as e:
224
+ logger.error(f"Execution Error: {e}")
225
+ raise
226
+
227
+
228
+ @app.command(name="format-sumstats")
229
+ @dataclass_typer
230
+ def format_sumstats(config: FormatSumstatsConfig):
231
+ """
232
+ Format GWAS summary statistics for gsMap or COJO.
233
+
234
+ This command:
235
+ - Filters SNPs based on INFO, MAF, and P-value
236
+ - Converts SNP positions to RSID (if dbsnp is provided)
237
+ - Saves formatted summary statistics
238
+ """
239
+ try:
240
+ from gsMap.format_sumstats import gwas_format
241
+ gwas_format(config)
242
+ logger.info("✓ Summary statistics formatted successfully!")
243
+ except Exception as e:
244
+ logger.error(f"Execution Error: {e}")
245
+ raise
246
+
247
+
248
+ @app.command(name="report-view")
249
+ def report_view(
250
+ report_path: Annotated[str, typer.Argument(
251
+ help="Path to gsmap_web_report directory containing index.html"
252
+ )],
253
+ port: Annotated[int, typer.Option(
254
+ help="Port to serve the report on"
255
+ )] = 8080,
256
+ no_browser: Annotated[bool, typer.Option(
257
+ "--no-browser",
258
+ help="Don't automatically open browser"
259
+ )] = False,
260
+ ):
261
+ """
262
+ Launch a local web server to view the gsMap report.
263
+
264
+ This command starts a simple HTTP server to serve the report files,
265
+ which is necessary for proper loading of JavaScript modules.
266
+
267
+ Example:
268
+ gsmap report-view /path/to/project/gsmap_web_report
269
+ gsmap report-view /path/to/project/gsmap_web_report --port 9000
270
+ """
271
+ import http.server
272
+ import os
273
+ import socketserver
274
+ import webbrowser
275
+ from pathlib import Path
276
+
277
+ report_dir = Path(report_path).resolve()
278
+
279
+ if not report_dir.exists():
280
+ logger.error(f"Directory not found: {report_dir}")
281
+ raise typer.Exit(1)
282
+
283
+ index_file = report_dir / "index.html"
284
+ if not index_file.exists():
285
+ logger.error(f"index.html not found in {report_dir}")
286
+ logger.error("Please provide path to the gsmap_web_report directory.")
287
+ raise typer.Exit(1)
288
+
289
+ os.chdir(report_dir)
290
+
291
+ handler = http.server.SimpleHTTPRequestHandler
292
+
293
+ try:
294
+ with socketserver.TCPServer(("", port), handler) as httpd:
295
+ url = f"http://localhost:{port}"
296
+ logger.info(f"Serving report at {url}")
297
+ logger.info("Press Ctrl+C to stop the server")
298
+
299
+ if not no_browser:
300
+ webbrowser.open(url)
301
+
302
+ httpd.serve_forever()
303
+ except KeyboardInterrupt:
304
+ logger.info("Server stopped.")
305
+ except OSError as e:
306
+ if "Address already in use" in str(e):
307
+ logger.error(f"Port {port} is already in use. Try a different port with --port <number>")
308
+ else:
309
+ logger.error(f"Failed to start server: {e}")
310
+ raise typer.Exit(1)
311
+
312
+
313
+ def version_callback(value: bool):
314
+ """Show version and exit."""
315
+ if value:
316
+ try:
317
+ from gsMap import __version__
318
+ typer.echo(f"gsMap version {__version__}")
319
+ except ImportError:
320
+ typer.echo("gsMap version: development")
321
+ raise typer.Exit()
322
+
323
+
324
+ @app.callback()
325
+ def main(
326
+ version: Annotated[bool | None, typer.Option(
327
+ "--version", "-v",
328
+ callback=version_callback,
329
+ is_eager=True,
330
+ help="Show version and exit"
331
+ )] = None,
332
+ ):
333
+ """
334
+ gsMap: genetically informed spatial mapping of cells for complex traits.
335
+
336
+ Use 'gsmap COMMAND --help' for more information on a specific command.
337
+
338
+ Common workflows:
339
+
340
+ 1. Quick mode (recommended for first-time users):
341
+ gsmap quick-mode --workdir /path/to/work --sample-name my_sample ...
342
+
343
+ 2. Step-by-step analysis:
344
+ gsmap find-latent ...
345
+ gsmap latent-to-gene ...
346
+ gsmap spatial-ldsc ...
347
+ gsmap report ...
348
+
349
+ For detailed documentation, visit: https://yanglab.westlake.edu.cn/gsmap3d/docs
350
+ """
351
+ pass
352
+
353
+
354
+ if __name__ == "__main__":
355
+ app()
@@ -0,0 +1,72 @@
1
+ """
2
+ gsMap configuration module.
3
+
4
+ This module provides:
5
+ - Configuration dataclasses for all gsMap commands
6
+ - Base classes with automatic path generation
7
+ - Decorators for CLI integration and resource tracking
8
+ """
9
+
10
+ from collections import OrderedDict, namedtuple
11
+
12
+ # Base classes and utilities
13
+ from .base import BaseConfig, ConfigWithAutoPaths, ensure_path_exists
14
+
15
+ # Configuration dataclasses
16
+ from .cauchy_config import CauchyCombinationConfig
17
+ from .dataclasses import (
18
+ CreateSliceMeanConfig,
19
+ DiagnosisConfig,
20
+ RunLinkModeConfig,
21
+ ThreeDCombineConfig,
22
+ VisualizeConfig,
23
+ gsMapPipelineConfig,
24
+ )
25
+
26
+ # Decorators
27
+ from .decorators import dataclass_typer, show_banner, track_resource_usage
28
+
29
+ # Migrated module configurations
30
+ from .find_latent_config import FindLatentRepresentationsConfig
31
+ from .format_sumstats_config import FormatSumstatsConfig
32
+ from .latent2gene_config import DatasetType, LatentToGeneConfig, MarkerScoreCrossSliceStrategy
33
+ from .ldscore_config import GenerateLDScoreConfig, LDScoreConfig
34
+ from .quick_mode_config import QuickModeConfig
35
+ from .report_config import ReportConfig
36
+ from .spatial_ldsc_config import SpatialLDSCConfig
37
+
38
+ # Create a legacy registry for backward compatibility with main.py
39
+ cli_function_registry = OrderedDict()
40
+ subcommand = namedtuple("subcommand", ["name", "func", "add_args_function", "description"])
41
+
42
+ __all__ = [
43
+ # Base classes
44
+ 'BaseConfig',
45
+ 'ConfigWithAutoPaths',
46
+ 'ensure_path_exists',
47
+
48
+ # Decorators
49
+ 'dataclass_typer',
50
+ 'track_resource_usage',
51
+ 'show_banner',
52
+
53
+ # Legacy compatibility
54
+ 'cli_function_registry',
55
+
56
+ # Configurations
57
+ 'QuickModeConfig',
58
+ 'FindLatentRepresentationsConfig',
59
+ 'LatentToGeneConfig',
60
+ 'DatasetType',
61
+ 'MarkerScoreCrossSliceStrategy',
62
+ 'SpatialLDSCConfig',
63
+ 'ReportConfig',
64
+ 'GenerateLDScoreConfig',
65
+ 'CauchyCombinationConfig',
66
+ 'CreateSliceMeanConfig',
67
+ 'FormatSumstatsConfig',
68
+ 'DiagnosisConfig',
69
+ 'VisualizeConfig',
70
+ 'ThreeDCombineConfig',
71
+ 'RunLinkModeConfig',
72
+ ]