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.
- gsMap/__init__.py +13 -0
- gsMap/__main__.py +4 -0
- gsMap/cauchy_combination_test.py +342 -0
- gsMap/cli.py +355 -0
- gsMap/config/__init__.py +72 -0
- gsMap/config/base.py +296 -0
- gsMap/config/cauchy_config.py +79 -0
- gsMap/config/dataclasses.py +235 -0
- gsMap/config/decorators.py +302 -0
- gsMap/config/find_latent_config.py +276 -0
- gsMap/config/format_sumstats_config.py +54 -0
- gsMap/config/latent2gene_config.py +461 -0
- gsMap/config/ldscore_config.py +261 -0
- gsMap/config/quick_mode_config.py +242 -0
- gsMap/config/report_config.py +81 -0
- gsMap/config/spatial_ldsc_config.py +334 -0
- gsMap/config/utils.py +286 -0
- gsMap/find_latent/__init__.py +3 -0
- gsMap/find_latent/find_latent_representation.py +312 -0
- gsMap/find_latent/gnn/distribution.py +498 -0
- gsMap/find_latent/gnn/encoder_decoder.py +186 -0
- gsMap/find_latent/gnn/gcn.py +85 -0
- gsMap/find_latent/gnn/gene_former.py +164 -0
- gsMap/find_latent/gnn/loss.py +18 -0
- gsMap/find_latent/gnn/st_model.py +125 -0
- gsMap/find_latent/gnn/train_step.py +177 -0
- gsMap/find_latent/st_process.py +781 -0
- gsMap/format_sumstats.py +446 -0
- gsMap/generate_ldscore.py +1018 -0
- gsMap/latent2gene/__init__.py +18 -0
- gsMap/latent2gene/connectivity.py +781 -0
- gsMap/latent2gene/entry_point.py +141 -0
- gsMap/latent2gene/marker_scores.py +1265 -0
- gsMap/latent2gene/memmap_io.py +766 -0
- gsMap/latent2gene/rank_calculator.py +590 -0
- gsMap/latent2gene/row_ordering.py +182 -0
- gsMap/latent2gene/row_ordering_jax.py +159 -0
- gsMap/ldscore/__init__.py +1 -0
- gsMap/ldscore/batch_construction.py +163 -0
- gsMap/ldscore/compute.py +126 -0
- gsMap/ldscore/constants.py +70 -0
- gsMap/ldscore/io.py +262 -0
- gsMap/ldscore/mapping.py +262 -0
- gsMap/ldscore/pipeline.py +615 -0
- gsMap/pipeline/quick_mode.py +134 -0
- gsMap/report/__init__.py +2 -0
- gsMap/report/diagnosis.py +375 -0
- gsMap/report/report.py +100 -0
- gsMap/report/report_data.py +1832 -0
- gsMap/report/static/js_lib/alpine.min.js +5 -0
- gsMap/report/static/js_lib/tailwindcss.js +83 -0
- gsMap/report/static/template.html +2242 -0
- gsMap/report/three_d_combine.py +312 -0
- gsMap/report/three_d_plot/three_d_plot_decorate.py +246 -0
- gsMap/report/three_d_plot/three_d_plot_prepare.py +202 -0
- gsMap/report/three_d_plot/three_d_plots.py +425 -0
- gsMap/report/visualize.py +1409 -0
- gsMap/setup.py +5 -0
- gsMap/spatial_ldsc/__init__.py +0 -0
- gsMap/spatial_ldsc/io.py +656 -0
- gsMap/spatial_ldsc/ldscore_quick_mode.py +912 -0
- gsMap/spatial_ldsc/spatial_ldsc_jax.py +382 -0
- gsMap/spatial_ldsc/spatial_ldsc_multiple_sumstats.py +439 -0
- gsMap/utils/__init__.py +0 -0
- gsMap/utils/generate_r2_matrix.py +610 -0
- gsMap/utils/jackknife.py +518 -0
- gsMap/utils/manhattan_plot.py +643 -0
- gsMap/utils/regression_read.py +177 -0
- gsMap/utils/torch_utils.py +23 -0
- gsmap3d-0.1.0a1.dist-info/METADATA +168 -0
- gsmap3d-0.1.0a1.dist-info/RECORD +74 -0
- gsmap3d-0.1.0a1.dist-info/WHEEL +4 -0
- gsmap3d-0.1.0a1.dist-info/entry_points.txt +2 -0
- gsmap3d-0.1.0a1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import glob
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger("gsMap.utils.regression_read")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _read_sumstats(fh, alleles=False, dropna=False):
|
|
11
|
+
"""Parse GWAS summary statistics."""
|
|
12
|
+
fh = str(fh)
|
|
13
|
+
logger.info(f"Reading summary statistics from {fh} ...")
|
|
14
|
+
|
|
15
|
+
# Determine compression type
|
|
16
|
+
compression = None
|
|
17
|
+
if fh.endswith("gz"):
|
|
18
|
+
compression = "gzip"
|
|
19
|
+
elif fh.endswith("bz2"):
|
|
20
|
+
compression = "bz2"
|
|
21
|
+
|
|
22
|
+
# Define columns and dtypes
|
|
23
|
+
dtype_dict = {"SNP": str, "Z": float, "N": float, "A1": str, "A2": str}
|
|
24
|
+
usecols = ["SNP", "Z", "N"]
|
|
25
|
+
if alleles:
|
|
26
|
+
usecols += ["A1", "A2"]
|
|
27
|
+
|
|
28
|
+
# Read the file
|
|
29
|
+
try:
|
|
30
|
+
sumstats = pd.read_csv(
|
|
31
|
+
fh,
|
|
32
|
+
sep=r"\s+",
|
|
33
|
+
na_values=".",
|
|
34
|
+
usecols=usecols,
|
|
35
|
+
dtype=dtype_dict,
|
|
36
|
+
compression=compression,
|
|
37
|
+
)
|
|
38
|
+
except (AttributeError, ValueError) as e:
|
|
39
|
+
logger.error(f"Failed to parse sumstats file: {str(e.args)}")
|
|
40
|
+
raise ValueError("Improperly formatted sumstats file: " + str(e.args)) from e
|
|
41
|
+
|
|
42
|
+
# Drop NA values if specified
|
|
43
|
+
if dropna:
|
|
44
|
+
sumstats = sumstats.dropna(how="any")
|
|
45
|
+
|
|
46
|
+
logger.info(f"Read summary statistics for {len(sumstats)} SNPs.")
|
|
47
|
+
|
|
48
|
+
# Drop duplicates
|
|
49
|
+
m = len(sumstats)
|
|
50
|
+
sumstats = sumstats.drop_duplicates(subset="SNP")
|
|
51
|
+
if m > len(sumstats):
|
|
52
|
+
logger.info(f"Dropped {m - len(sumstats)} SNPs with duplicated rs numbers.")
|
|
53
|
+
|
|
54
|
+
return sumstats
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _read_chr_files(base_path, suffix, expected_count=22):
|
|
58
|
+
"""Read chromosome files using glob pattern matching."""
|
|
59
|
+
# Create the pattern to search for files
|
|
60
|
+
file_pattern = f"{base_path}[1-9]*{suffix}*"
|
|
61
|
+
|
|
62
|
+
# Find all matching files
|
|
63
|
+
all_files = glob.glob(file_pattern)
|
|
64
|
+
|
|
65
|
+
# Extract chromosome numbers
|
|
66
|
+
chr_files = []
|
|
67
|
+
for file in all_files:
|
|
68
|
+
try:
|
|
69
|
+
# Extract the chromosome number from filename
|
|
70
|
+
file_name = os.path.basename(file)
|
|
71
|
+
base_name = os.path.basename(base_path)
|
|
72
|
+
chr_part = file_name.replace(base_name, "").split(suffix)[0]
|
|
73
|
+
chr_num = int(chr_part)
|
|
74
|
+
if 1 <= chr_num <= expected_count:
|
|
75
|
+
chr_files.append((chr_num, file))
|
|
76
|
+
except (ValueError, IndexError):
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
# Check if we have the expected number of chromosome files
|
|
80
|
+
if len(chr_files) != expected_count:
|
|
81
|
+
logger.warning(
|
|
82
|
+
f"❗ SEVERE WARNING ❗ Expected {expected_count} chromosome files, but found {len(chr_files)}! "
|
|
83
|
+
f"⚠️ For human GWAS data, all 22 autosomes must be present. Please verify your input files."
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Sort by chromosome number and return file paths
|
|
87
|
+
chr_files.sort()
|
|
88
|
+
return [file for _, file in chr_files]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _read_file(file_path):
|
|
92
|
+
"""Read a file based on its format/extension."""
|
|
93
|
+
file_path = str(file_path)
|
|
94
|
+
try:
|
|
95
|
+
if file_path.endswith(".feather"):
|
|
96
|
+
return pd.read_feather(file_path)
|
|
97
|
+
elif file_path.endswith(".parquet"):
|
|
98
|
+
return pd.read_parquet(file_path)
|
|
99
|
+
elif file_path.endswith(".gz"):
|
|
100
|
+
return pd.read_csv(file_path, compression="gzip", sep="\t")
|
|
101
|
+
elif file_path.endswith(".bz2"):
|
|
102
|
+
return pd.read_csv(file_path, compression="bz2", sep="\t")
|
|
103
|
+
else:
|
|
104
|
+
return pd.read_csv(file_path, sep="\t")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.error(f"Failed to read file {file_path}: {str(e)}")
|
|
107
|
+
raise
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _read_ref_ld_v2(ld_file):
|
|
111
|
+
"""Read reference LD scores for all chromosomes."""
|
|
112
|
+
suffix = ".l2.ldscore"
|
|
113
|
+
logger.info(f"Reading LD score annotations from {ld_file}[1-22]{suffix}...")
|
|
114
|
+
|
|
115
|
+
# Get the chromosome files
|
|
116
|
+
chr_files = _read_chr_files(ld_file, suffix)
|
|
117
|
+
|
|
118
|
+
# Read and concatenate all files
|
|
119
|
+
df_list = [_read_file(file) for file in chr_files]
|
|
120
|
+
|
|
121
|
+
if not df_list:
|
|
122
|
+
logger.error(f"No LD score files found matching pattern: {ld_file}*{suffix}*")
|
|
123
|
+
raise FileNotFoundError(f"No LD score files found matching pattern: {ld_file}*{suffix}*")
|
|
124
|
+
|
|
125
|
+
ref_ld = pd.concat(df_list, axis=0)
|
|
126
|
+
logger.info(f"Loaded {len(ref_ld)} SNPs from LD score files")
|
|
127
|
+
|
|
128
|
+
# Set SNP as index
|
|
129
|
+
if "index" in ref_ld.columns:
|
|
130
|
+
ref_ld.rename(columns={"index": "SNP"}, inplace=True)
|
|
131
|
+
if "SNP" in ref_ld.columns:
|
|
132
|
+
ref_ld.set_index("SNP", inplace=True)
|
|
133
|
+
|
|
134
|
+
return ref_ld
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _read_w_ld(w_file):
|
|
138
|
+
"""Read LD weights for all chromosomes."""
|
|
139
|
+
suffix = ".l2.ldscore"
|
|
140
|
+
logger.info(f"Reading LD score annotations from {w_file}[1-22]{suffix}...")
|
|
141
|
+
|
|
142
|
+
# Get the chromosome files
|
|
143
|
+
chr_files = _read_chr_files(w_file, suffix)
|
|
144
|
+
|
|
145
|
+
if not chr_files:
|
|
146
|
+
logger.error(f"No LD score files found matching pattern: {w_file}*{suffix}*")
|
|
147
|
+
raise FileNotFoundError(f"No LD score files found matching pattern: {w_file}*{suffix}*")
|
|
148
|
+
|
|
149
|
+
# Read and process each file
|
|
150
|
+
w_array = []
|
|
151
|
+
for file in chr_files:
|
|
152
|
+
x = _read_file(file)
|
|
153
|
+
|
|
154
|
+
# Sort if possible
|
|
155
|
+
if "CHR" in x.columns and "BP" in x.columns:
|
|
156
|
+
x = x.sort_values(by=["CHR", "BP"])
|
|
157
|
+
|
|
158
|
+
# Drop unnecessary columns
|
|
159
|
+
columns_to_drop = ["MAF", "CM", "Gene", "TSS", "CHR", "BP"]
|
|
160
|
+
columns_to_drop = [col for col in columns_to_drop if col in x.columns]
|
|
161
|
+
if columns_to_drop:
|
|
162
|
+
x = x.drop(columns=columns_to_drop, axis=1)
|
|
163
|
+
|
|
164
|
+
w_array.append(x)
|
|
165
|
+
|
|
166
|
+
# Concatenate and set column names
|
|
167
|
+
w_ld = pd.concat(w_array, axis=0)
|
|
168
|
+
logger.info(f"Loaded {len(w_ld)} SNPs from LD weight files")
|
|
169
|
+
|
|
170
|
+
# Set column names
|
|
171
|
+
w_ld.columns = (
|
|
172
|
+
["SNP", "LD_weights"] + list(w_ld.columns[2:])
|
|
173
|
+
if len(w_ld.columns) > 2
|
|
174
|
+
else ["SNP", "LD_weights"]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return w_ld
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Wrapper functions for pytorch.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def torch_device(index=-1):
|
|
9
|
+
if torch.cuda.is_available():
|
|
10
|
+
if index >= 0:
|
|
11
|
+
return torch.device(f"cuda:{index}")
|
|
12
|
+
return torch.device("cuda")
|
|
13
|
+
elif torch.backends.mps.is_available() and torch.backends.mps.is_built():
|
|
14
|
+
return torch.device("mps")
|
|
15
|
+
else:
|
|
16
|
+
return torch.device("cpu")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def torch_sync():
|
|
20
|
+
if torch.backends.mps.is_available() and torch.backends.mps.is_built():
|
|
21
|
+
torch.mps.synchronize()
|
|
22
|
+
elif torch.cuda.is_available():
|
|
23
|
+
torch.cuda.synchronize()
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gsMap3D
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Genetically informed spatial mapping of cells for complex traits
|
|
5
|
+
Project-URL: Home, https://github.com/Ganten-Hornby/gsMap3D
|
|
6
|
+
Project-URL: Documentation, https://yanglab.westlake.edu.cn/gsmap3d/docs
|
|
7
|
+
Project-URL: Website, https://yanglab.westlake.edu.cn/gsmap3d
|
|
8
|
+
Author-email: liyang <songliyang@westlake.edu.cn>, wenhao <chenwenhao@westlake.edu.cn>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 JianYang-Lab
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Requires-Python: >=3.12
|
|
38
|
+
Requires-Dist: anndata>=0.8.0
|
|
39
|
+
Requires-Dist: bitarray<3.0.0,>=2.9.2
|
|
40
|
+
Requires-Dist: distinctipy>=1.3.4
|
|
41
|
+
Requires-Dist: einops
|
|
42
|
+
Requires-Dist: h5py>=3.0.0
|
|
43
|
+
Requires-Dist: jax~=0.9.0
|
|
44
|
+
Requires-Dist: jinja2
|
|
45
|
+
Requires-Dist: kaleido
|
|
46
|
+
Requires-Dist: matplotlib
|
|
47
|
+
Requires-Dist: numba
|
|
48
|
+
Requires-Dist: numpy~=2.2
|
|
49
|
+
Requires-Dist: pandas
|
|
50
|
+
Requires-Dist: pandas-plink
|
|
51
|
+
Requires-Dist: plotly
|
|
52
|
+
Requires-Dist: psutil>=5.8.0
|
|
53
|
+
Requires-Dist: pyarrow
|
|
54
|
+
Requires-Dist: pyfiglet
|
|
55
|
+
Requires-Dist: pyranges
|
|
56
|
+
Requires-Dist: pyvista>=0.35.0
|
|
57
|
+
Requires-Dist: pyyaml
|
|
58
|
+
Requires-Dist: rich>=14.1.0
|
|
59
|
+
Requires-Dist: scanpy>=1.11.0
|
|
60
|
+
Requires-Dist: scikit-learn
|
|
61
|
+
Requires-Dist: scipy
|
|
62
|
+
Requires-Dist: statsmodels>=0.13.0
|
|
63
|
+
Requires-Dist: torch-geometric~=2.7
|
|
64
|
+
Requires-Dist: torch~=2.5
|
|
65
|
+
Requires-Dist: tqdm
|
|
66
|
+
Requires-Dist: typer~=0.20.0
|
|
67
|
+
Requires-Dist: zarr>=2.18.0
|
|
68
|
+
Provides-Extra: cuda
|
|
69
|
+
Requires-Dist: jax[cuda12]>=0.8.1; extra == 'cuda'
|
|
70
|
+
Provides-Extra: doc
|
|
71
|
+
Requires-Dist: furo; extra == 'doc'
|
|
72
|
+
Requires-Dist: myst-parser; extra == 'doc'
|
|
73
|
+
Requires-Dist: nbsphinx; extra == 'doc'
|
|
74
|
+
Requires-Dist: sphinx; extra == 'doc'
|
|
75
|
+
Requires-Dist: sphinx-argparse; extra == 'doc'
|
|
76
|
+
Requires-Dist: sphinx-autobuild; extra == 'doc'
|
|
77
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == 'doc'
|
|
78
|
+
Requires-Dist: sphinx-basic-ng; extra == 'doc'
|
|
79
|
+
Requires-Dist: sphinx-charts; extra == 'doc'
|
|
80
|
+
Requires-Dist: sphinx-copybutton; extra == 'doc'
|
|
81
|
+
Requires-Dist: sphinx-inline-tabs; extra == 'doc'
|
|
82
|
+
Requires-Dist: sphinx-markdown-tables; extra == 'doc'
|
|
83
|
+
Requires-Dist: sphinx-rtd-theme; extra == 'doc'
|
|
84
|
+
Requires-Dist: sphinxcontrib-applehelp; extra == 'doc'
|
|
85
|
+
Requires-Dist: sphinxcontrib-devhelp; extra == 'doc'
|
|
86
|
+
Requires-Dist: sphinxcontrib-htmlhelp; extra == 'doc'
|
|
87
|
+
Requires-Dist: sphinxcontrib-jquery; extra == 'doc'
|
|
88
|
+
Requires-Dist: sphinxcontrib-jsmath; extra == 'doc'
|
|
89
|
+
Requires-Dist: sphinxcontrib-mermaid; extra == 'doc'
|
|
90
|
+
Requires-Dist: sphinxcontrib-qthelp; extra == 'doc'
|
|
91
|
+
Requires-Dist: sphinxcontrib-serializinghtml; extra == 'doc'
|
|
92
|
+
Provides-Extra: tests
|
|
93
|
+
Requires-Dist: coverage; extra == 'tests'
|
|
94
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'tests'
|
|
95
|
+
Requires-Dist: pytest>=7.0.0; extra == 'tests'
|
|
96
|
+
Description-Content-Type: text/markdown
|
|
97
|
+
|
|
98
|
+
# gsMap3D
|
|
99
|
+
|
|
100
|
+
**gsMap3D** integrates 3D spatial transcriptomics (ST) data with genome-wide association study (GWAS) summary statistics to map cells associated with human complex traits and diseases.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## ✨ What's New
|
|
105
|
+
|
|
106
|
+
- Support for 3D ST data mapping
|
|
107
|
+
- Dual-embedding strategy for more accurate gene specificity scoring
|
|
108
|
+
- Full GPU acceleration across all analysis steps
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## 🚀 Features
|
|
113
|
+
|
|
114
|
+
- **Spatially-aware High-Resolution Trait Mapping**
|
|
115
|
+
Maps trait-associated cells at single-cell resolution, offering insights into their spatial distributions.
|
|
116
|
+
|
|
117
|
+
- **Spatial Region Identification**
|
|
118
|
+
Aggregates trait–cell association p-values into trait–tissue region association p-values, prioritizing tissue regions relevant to traits of interest.
|
|
119
|
+
|
|
120
|
+
- **Putative Causal Genes Identification**
|
|
121
|
+
Prioritizes putative causal genes by associating gene expression levels with cell–trait relevance.
|
|
122
|
+
|
|
123
|
+
- **Scalability**
|
|
124
|
+
Employs [JAX](https://github.com/google/jax) JIT and GPU/TPU acceleration to scale to million-scale cells (spots) spatial omics datasets.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
## 🧠 Overview of `gsMap3D`
|
|
130
|
+
|
|
131
|
+
`gsMap3D` operates on a four-step process:
|
|
132
|
+
|
|
133
|
+
#### 1. Gene Specificity Assessment in 3D Spatial Contexts
|
|
134
|
+
To address technical noise and capture spatial correlations of gene expression across consecutive ST sections,
|
|
135
|
+
`gsMap3D` constructs batch-corrected dual embeddings of molecular and spatial features. These embeddings jointly model transcriptomic similarity and local spatial context to identify homogeneous cells in 3D space. Gene specificity scores (GSS) are then computed by aggregating normalized gene expression ranks across these 3D homogeneous cells, enabling robust identification of genes that are both highly and specifically expressed in focal cells.
|
|
136
|
+
|
|
137
|
+
#### 2. Linking Gene Specificity to Genetic Variants
|
|
138
|
+
`gsMap3D` links gene specificity scores to single nucleotide polymorphisms (SNPs) by assigning GSS to SNPs based on their proximity to gene transcription start sites (TSS) and SNP-to-gene epigenetic linking maps, thereby connecting spatially resolved gene expression patterns with trait-associated genetic variation.
|
|
139
|
+
|
|
140
|
+
#### 3. 3D Spatial S-LDSC for Cell–Trait Association
|
|
141
|
+
To quantify cell–trait associations in 3D space, `gsMap3D` integrates the 3D gene specificity scores with GWAS summary statistics using stratified LD score regression (S-LDSC). This framework enables the estimation of trait relevance for individual cells by associating their stratified LD scores with GWAS signals.
|
|
142
|
+
|
|
143
|
+
#### 4. Spatial Region–Trait Association Analysis
|
|
144
|
+
To evaluate associations between traits and spatial regions, `gsMap3D` aggregates p-values from cells within a given 3D spatial region using the Cauchy combination test, yielding region-level association statistics that reflect coordinated genetic effects across spatially organized cell populations.
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 📚 Documentation
|
|
152
|
+
Please see [URL]
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 📝 How to Cite
|
|
157
|
+
|
|
158
|
+
If you use `gsMap` in your studies, please cite:
|
|
159
|
+
|
|
160
|
+
- **gsMap3D**: *to be updated.*
|
|
161
|
+
|
|
162
|
+
- **gsMap**:
|
|
163
|
+
Song, L., Chen, W., Hou, J., Guo, M. & Yang, J.
|
|
164
|
+
*Spatially resolved mapping of cells associated with human complex traits.*
|
|
165
|
+
**Nature** (2025).
|
|
166
|
+
[https://doi.org/10.1038/s41586-025-08757-x](https://doi.org/10.1038/s41586-025-08757-x)
|
|
167
|
+
|
|
168
|
+
---
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
gsMap/__init__.py,sha256=IjTQweEX-8_2ZyexXTlDFSzmfupmo56ZrRoYNuyuHvs,335
|
|
2
|
+
gsMap/__main__.py,sha256=Qd-f8z2Q2vpiEP2x6PBFsJrpACWDVxFKQk820MhFmHo,59
|
|
3
|
+
gsMap/cauchy_combination_test.py,sha256=IahPjZ0g88QwamGG_djiV85YoKvOR5SRftHJS6ge_lo,12723
|
|
4
|
+
gsMap/cli.py,sha256=IYXahk4PRmXKvNzQf_7dHdV05Rqrm0jJ4KxrWe9Xx2g,11259
|
|
5
|
+
gsMap/format_sumstats.py,sha256=4VsU2qOym-m5AiuSzWRvJrrRACyZnf0bwr5buanUuLM,13784
|
|
6
|
+
gsMap/generate_ldscore.py,sha256=af_ABnioNPSda44pwfdLMz4vpHAReDAkIvEDEo9k_sw,35375
|
|
7
|
+
gsMap/setup.py,sha256=lsIQCChHwR0ojWZs7xay8rukRaLlueuLkc83bp-B2ZE,103
|
|
8
|
+
gsMap/config/__init__.py,sha256=QUn-RcvqYTJNlmx4_t6V8neB8xrsFhQ0m8PNe76lsNc,2027
|
|
9
|
+
gsMap/config/base.py,sha256=TGOiLoa7M_boTqDO_j7dxPELFVt_TpmPAlVkhy1sfbc,10103
|
|
10
|
+
gsMap/config/cauchy_config.py,sha256=0tm1ZMrdwa1JRqirw1xqngefquJ7nDgkOlVxutt8uhw,2952
|
|
11
|
+
gsMap/config/dataclasses.py,sha256=mER5RDr6z1gfZOJcjaX5DxmNTYQ1D3a8NywT_KwUYj0,8515
|
|
12
|
+
gsMap/config/decorators.py,sha256=3QScTfNx7x71fo3dYjdFY4dFUWV9iJXDjkA0tzOd0Aw,10210
|
|
13
|
+
gsMap/config/find_latent_config.py,sha256=PTe0_j9VjjBr_k0HVv7xwLvcHbN7E81tXtwyTXu4_UM,7868
|
|
14
|
+
gsMap/config/format_sumstats_config.py,sha256=LNmyIu_dFZ9vaeeYPlRcL3N7EVchLQVY1hYXOfyhvMc,2766
|
|
15
|
+
gsMap/config/latent2gene_config.py,sha256=XnFDzR_OZpDZEAHf2enMKroG15jDq3jyks1BZDRMjHM,18820
|
|
16
|
+
gsMap/config/ldscore_config.py,sha256=yntZPspjcPbvrwhYNZ6WkAGJiQifOULKJBZtqVSlh-0,7680
|
|
17
|
+
gsMap/config/quick_mode_config.py,sha256=JkUjb0p-SqkxyPTbKebvJhHrTzFFud8MRwkJZUkctzY,9001
|
|
18
|
+
gsMap/config/report_config.py,sha256=9N-JiGFfJ3Lly8J9a1PpmCRUyBfFFijIp_X6iODkUdU,2730
|
|
19
|
+
gsMap/config/spatial_ldsc_config.py,sha256=5idEw6IyL52ANC8SrPR29lC65xySjPV0-H8x-t1PTwE,13012
|
|
20
|
+
gsMap/config/utils.py,sha256=LuZsVQFj7gPRD-KByBmncR6HzCqfJP7_w7kwS1fLjTU,12070
|
|
21
|
+
gsMap/find_latent/__init__.py,sha256=bgXUn8hd9RAZwR4tA8JJQ9b751dDlLC4K-9GuEr11Q4,117
|
|
22
|
+
gsMap/find_latent/find_latent_representation.py,sha256=zzMLKDWTpE1zKZ1jPUNfS3atTf7RhTDrdeuLHC0hRn8,11566
|
|
23
|
+
gsMap/find_latent/st_process.py,sha256=C5Cpa5Q1gvl4iZ0BUd1OS58z6AHhEak_Y-hE39oom8c,29706
|
|
24
|
+
gsMap/find_latent/gnn/distribution.py,sha256=vBEMtGlEISrAlvR9vjXp-x4SkuZyv7uUwcqERAv5WDI,15479
|
|
25
|
+
gsMap/find_latent/gnn/encoder_decoder.py,sha256=5MqYvcTDKoBedv4k0ihe3rQiSCF4oYLntj_53Subf00,5514
|
|
26
|
+
gsMap/find_latent/gnn/gcn.py,sha256=0BIup-uPS5ODU760Wg03_Bhrn1ICF9vNpKZwKGVvVDA,2427
|
|
27
|
+
gsMap/find_latent/gnn/gene_former.py,sha256=e5669fvVzSrAVfjyrGQzuK8mk1or_w8qtgVa15-0MPU,5524
|
|
28
|
+
gsMap/find_latent/gnn/loss.py,sha256=htKJLCwnaxl8n5ykgkCXwtFt4P7KqQh_KN50iJsHHK4,621
|
|
29
|
+
gsMap/find_latent/gnn/st_model.py,sha256=AGuXTVtGjhdpa4uEOc_AuViNqMbz5fJhSmyIYkhExgY,4680
|
|
30
|
+
gsMap/find_latent/gnn/train_step.py,sha256=1vv0Yf7ZR7obp6fM7CpLbmZ91AEpoUR4TcprfWVttJI,5783
|
|
31
|
+
gsMap/latent2gene/__init__.py,sha256=7mfRiqjFNzYrBJVqZu4Gu9Go9lGXIMWMphHtvcOJ1EA,546
|
|
32
|
+
gsMap/latent2gene/connectivity.py,sha256=NWb-owIvr2eVGWFQKCxjFeOQ_BgE7PhKt9D_s-3mN-I,37315
|
|
33
|
+
gsMap/latent2gene/entry_point.py,sha256=0arxzqhFY-UTIfhMlIaUVlz4KyYQ6ABffoXZf4YjlNE,5465
|
|
34
|
+
gsMap/latent2gene/marker_scores.py,sha256=EMKzqI6PhNq_ZLJ2M6nD8Xlme6xq6Wb9woP5Mmr1Ttw,52562
|
|
35
|
+
gsMap/latent2gene/memmap_io.py,sha256=QuGFIIA0_4DbGXgWltLUO5CJGiQ0T5VF05iAu2rM0CE,28383
|
|
36
|
+
gsMap/latent2gene/rank_calculator.py,sha256=2VXHTUanqPf1x0IbEgHSSpD8rCq1Mm6338dgIxaf7Pc,24000
|
|
37
|
+
gsMap/latent2gene/row_ordering.py,sha256=9ph7pB6mbcRuzcJouRraW8Ahp8qgSFOOTYvG7VYDf0I,6986
|
|
38
|
+
gsMap/latent2gene/row_ordering_jax.py,sha256=p6OsTu1AfbfvovIysvLgI5HuTN3VJ1GKEFreW00B-X0,5775
|
|
39
|
+
gsMap/ldscore/__init__.py,sha256=9alBPfw1TI4kHO-VwtulyavMilCllFcFznr6Xq2X5VU,39
|
|
40
|
+
gsMap/ldscore/batch_construction.py,sha256=VpM6f3Gf5jxutEAgUSlpWdjSGH3DE6uBl7L85PJc76s,5267
|
|
41
|
+
gsMap/ldscore/compute.py,sha256=Mm5mmqQWszkW3DpFEiX1n75-s62F50guoprTsW-itxM,3739
|
|
42
|
+
gsMap/ldscore/constants.py,sha256=I8jiwmS64V0HvfwMPPZjSvdFr5Ruqox_F6jolYGgqvs,2103
|
|
43
|
+
gsMap/ldscore/io.py,sha256=ufrJd39NAZ1nGVhkYpfPZ7Ne_JYzhO6F9muk4_5fHnM,9119
|
|
44
|
+
gsMap/ldscore/mapping.py,sha256=6UgZ3HpYnLDTVJTuy4uZAik1Ifmwc2_tZlJxNUrJbsw,11374
|
|
45
|
+
gsMap/ldscore/pipeline.py,sha256=YQf6RJlVe1rjWl6o1ADGSLbQsFfizzzx-Jsc_4onIuM,24217
|
|
46
|
+
gsMap/pipeline/quick_mode.py,sha256=sPutxA94jYvWpg_zjtuDkZryDXGJlKITeuzGcId_oys,5174
|
|
47
|
+
gsMap/report/__init__.py,sha256=Bo80Y_4o6w4Ag1ZA5NQAE2NJ6MNmsiw7FWp1tB80GCQ,74
|
|
48
|
+
gsMap/report/diagnosis.py,sha256=RYCRM0-nrR0olYQKHwpH8ygN0df9WXUEyE2wYWbPtl0,13931
|
|
49
|
+
gsMap/report/report.py,sha256=6fnVwbYZYwWvOK-c6AcBTDvWIKdeMm4TNB064MGo0vg,3949
|
|
50
|
+
gsMap/report/report_data.py,sha256=F2tYFD77353klYqQj8KQE6T8KBXjUBm37akJmIQ-ceE,74275
|
|
51
|
+
gsMap/report/three_d_combine.py,sha256=4QASJjfzjhxARrcOawTSgwCZNdu0k-DiDVcznmecffA,12606
|
|
52
|
+
gsMap/report/visualize.py,sha256=zQBHN2ahZfBWbY_oQ59zlDjXkEU-FB9-TfY5NSxLttk,60590
|
|
53
|
+
gsMap/report/static/template.html,sha256=HA9LbHtcSllM2o6RdlE8nYBlNCRdFdIsn1baJ0Xqmyw,121514
|
|
54
|
+
gsMap/report/static/js_lib/alpine.min.js,sha256=yPqP9Fer3NIS83oH7y8pLJmQEd_6vKpXf7Hh4Adsplg,43441
|
|
55
|
+
gsMap/report/static/js_lib/tailwindcss.js,sha256=F26JRmGqnNyaXLpscgBEy797i9gNHJoUKnwksbbFDRU,407279
|
|
56
|
+
gsMap/report/three_d_plot/three_d_plot_decorate.py,sha256=WGWQzbpXDH4PZMVJgYMYi_zk3k_8L4bt2qAM8TjMPbA,7204
|
|
57
|
+
gsMap/report/three_d_plot/three_d_plot_prepare.py,sha256=1CSG_orWgoPaEizCFFsW7-GJA1C3iEgueL8QwbRFiI4,7229
|
|
58
|
+
gsMap/report/three_d_plot/three_d_plots.py,sha256=vJ4S0nffArTXYdlMma4Aq2FUD64Alh3LB2nssYb90Fs,16166
|
|
59
|
+
gsMap/spatial_ldsc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
+
gsMap/spatial_ldsc/io.py,sha256=jZbIIQ5mfRIPTYZ5OQhC3qveuA4DX3p_eTg-1pRymt0,24764
|
|
61
|
+
gsMap/spatial_ldsc/ldscore_quick_mode.py,sha256=qIV9n_onHn7-hC51pK-Oj1ZMpj4kt_6Hj6ShXC8EN7c,35496
|
|
62
|
+
gsMap/spatial_ldsc/spatial_ldsc_jax.py,sha256=hfGiikKDyN-eqLRe-8OgUQOGyJ02xVEluDctM7-KNJc,16150
|
|
63
|
+
gsMap/spatial_ldsc/spatial_ldsc_multiple_sumstats.py,sha256=cfUoatfenCQgOx4SAleWwyGflgxoqs7ubDwiKQABT10,18600
|
|
64
|
+
gsMap/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
|
+
gsMap/utils/generate_r2_matrix.py,sha256=4ewkK2Foe7TLwVYQKmuUjuJ7w3i7lvM_ddS367RpAPo,20396
|
|
66
|
+
gsMap/utils/jackknife.py,sha256=w_qMj9GlqViouHuOw1U80N6doWuCTXuPoAVU4P-5mm8,17673
|
|
67
|
+
gsMap/utils/manhattan_plot.py,sha256=fi-ee9pyXuJOu9VYsAJCNDGQSc86ZLDBIwNotUVdxhc,26509
|
|
68
|
+
gsMap/utils/regression_read.py,sha256=aHU44SdQyzMR7OcbxrmS8aNbv8jKT0rmjaf11joox34,5697
|
|
69
|
+
gsMap/utils/torch_utils.py,sha256=baHIoAlBcfEvoGOM2sH-oQLKVo5V0M5ZqzObgjm2I40,580
|
|
70
|
+
gsmap3d-0.1.0a1.dist-info/METADATA,sha256=nkrU-7t_sRzpciNpB3t-8oz6DfdL0PNKYvSQ5aPPCrg,7493
|
|
71
|
+
gsmap3d-0.1.0a1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
72
|
+
gsmap3d-0.1.0a1.dist-info/entry_points.txt,sha256=EQ0WSo2RzyouAf3_mtECypKTd4TIrIMUZM1iRsDRPd0,40
|
|
73
|
+
gsmap3d-0.1.0a1.dist-info/licenses/LICENSE,sha256=F9Vd0M0bhtsefCFMCTzsR1n-sy6UhBa8OWk41HT_Rf8,1069
|
|
74
|
+
gsmap3d-0.1.0a1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JianYang-Lab
|
|
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.
|