gsMap 1.66__py3-none-any.whl → 1.67__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/GNN_VAE/adjacency_matrix.py +48 -68
- gsMap/GNN_VAE/model.py +68 -66
- gsMap/GNN_VAE/train.py +50 -61
- gsMap/__init__.py +1 -1
- gsMap/config.py +4 -4
- gsMap/find_latent_representation.py +103 -103
- gsMap/format_sumstats.py +20 -20
- gsMap/latent_to_gene.py +0 -7
- gsMap/spatial_ldsc_multiple_sumstats.py +0 -2
- {gsmap-1.66.dist-info → gsmap-1.67.dist-info}/METADATA +2 -2
- {gsmap-1.66.dist-info → gsmap-1.67.dist-info}/RECORD +14 -14
- {gsmap-1.66.dist-info → gsmap-1.67.dist-info}/LICENSE +0 -0
- {gsmap-1.66.dist-info → gsmap-1.67.dist-info}/WHEEL +0 -0
- {gsmap-1.66.dist-info → gsmap-1.67.dist-info}/entry_points.txt +0 -0
@@ -1,95 +1,75 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
"""
|
4
|
-
Created on Tue Jul 4 21:31:27 2023
|
5
|
-
|
6
|
-
@author: songliyang
|
7
|
-
"""
|
8
1
|
import numpy as np
|
9
2
|
import pandas as pd
|
10
3
|
import scipy.sparse as sp
|
11
|
-
|
4
|
+
from sklearn.neighbors import NearestNeighbors
|
12
5
|
import torch
|
13
6
|
|
14
|
-
|
15
|
-
|
16
|
-
"""\
|
17
|
-
Construct the spatial neighbor networks.
|
18
|
-
"""
|
19
|
-
#-
|
7
|
+
def cal_spatial_net(adata, n_neighbors=5, verbose=True):
|
8
|
+
"""Construct the spatial neighbor network."""
|
20
9
|
if verbose:
|
21
10
|
print('------Calculating spatial graph...')
|
22
|
-
coor = pd.DataFrame(adata.obsm['spatial'])
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
Spatial_Net = Spatial_Net.loc[Spatial_Net['Distance']>0,]
|
37
|
-
id_cell_trans = dict(zip(range(coor.shape[0]), np.array(coor.index), ))
|
38
|
-
Spatial_Net['Cell1'] = Spatial_Net['Cell1'].map(id_cell_trans)
|
39
|
-
Spatial_Net['Cell2'] = Spatial_Net['Cell2'].map(id_cell_trans)
|
40
|
-
#-
|
41
|
-
return Spatial_Net
|
42
|
-
|
11
|
+
coor = pd.DataFrame(adata.obsm['spatial'], index=adata.obs.index)
|
12
|
+
nbrs = NearestNeighbors(n_neighbors=n_neighbors).fit(coor)
|
13
|
+
distances, indices = nbrs.kneighbors(coor)
|
14
|
+
n_cells, n_neighbors = indices.shape
|
15
|
+
cell_indices = np.arange(n_cells)
|
16
|
+
cell1 = np.repeat(cell_indices, n_neighbors)
|
17
|
+
cell2 = indices.flatten()
|
18
|
+
distance = distances.flatten()
|
19
|
+
knn_df = pd.DataFrame({'Cell1': cell1, 'Cell2': cell2, 'Distance': distance})
|
20
|
+
knn_df = knn_df[knn_df['Distance'] > 0].copy()
|
21
|
+
cell_id_map = dict(zip(cell_indices, coor.index))
|
22
|
+
knn_df['Cell1'] = knn_df['Cell1'].map(cell_id_map)
|
23
|
+
knn_df['Cell2'] = knn_df['Cell2'].map(cell_id_map)
|
24
|
+
return knn_df
|
43
25
|
|
44
26
|
def sparse_mx_to_torch_sparse_tensor(sparse_mx):
|
45
27
|
"""Convert a scipy sparse matrix to a torch sparse tensor."""
|
46
28
|
sparse_mx = sparse_mx.tocoo().astype(np.float32)
|
47
|
-
indices = torch.from_numpy(
|
29
|
+
indices = torch.from_numpy(
|
30
|
+
np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)
|
31
|
+
)
|
48
32
|
values = torch.from_numpy(sparse_mx.data)
|
49
33
|
shape = torch.Size(sparse_mx.shape)
|
50
34
|
return torch.sparse.FloatTensor(indices, values, shape)
|
51
35
|
|
52
|
-
|
53
36
|
def preprocess_graph(adj):
|
37
|
+
"""Symmetrically normalize the adjacency matrix."""
|
54
38
|
adj = sp.coo_matrix(adj)
|
55
39
|
adj_ = adj + sp.eye(adj.shape[0])
|
56
|
-
rowsum = np.array(adj_.sum(1))
|
57
|
-
degree_mat_inv_sqrt = sp.diags(np.power(rowsum, -0.5)
|
40
|
+
rowsum = np.array(adj_.sum(1)).flatten()
|
41
|
+
degree_mat_inv_sqrt = sp.diags(np.power(rowsum, -0.5))
|
58
42
|
adj_normalized = adj_.dot(degree_mat_inv_sqrt).transpose().dot(degree_mat_inv_sqrt).tocoo()
|
59
43
|
return sparse_mx_to_torch_sparse_tensor(adj_normalized)
|
60
44
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# Construct the neighbor graph
|
65
|
-
Spatial_Net = Cal_Spatial_Net(adata, n_neighbors=Params.n_neighbors)
|
66
|
-
#-
|
45
|
+
def construct_adjacency_matrix(adata, params, verbose=True):
|
46
|
+
"""Construct the adjacency matrix from spatial data."""
|
47
|
+
spatial_net = cal_spatial_net(adata, n_neighbors=params.n_neighbors, verbose=verbose)
|
67
48
|
if verbose:
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
49
|
+
num_edges = spatial_net.shape[0]
|
50
|
+
num_cells = adata.n_obs
|
51
|
+
print(f'The graph contains {num_edges} edges, {num_cells} cells.')
|
52
|
+
print(f'{num_edges / num_cells:.2f} neighbors per cell on average.')
|
53
|
+
cell_ids = {cell: idx for idx, cell in enumerate(adata.obs.index)}
|
54
|
+
spatial_net['Cell1'] = spatial_net['Cell1'].map(cell_ids)
|
55
|
+
spatial_net['Cell2'] = spatial_net['Cell2'].map(cell_ids)
|
56
|
+
if params.weighted_adj:
|
57
|
+
distance_normalized = spatial_net['Distance'] / (spatial_net['Distance'].max() + 1)
|
58
|
+
weights = np.exp(-0.5 * distance_normalized ** 2)
|
59
|
+
adj_org = sp.coo_matrix(
|
60
|
+
(weights, (spatial_net['Cell1'], spatial_net['Cell2'])),
|
61
|
+
shape=(adata.n_obs, adata.n_obs)
|
62
|
+
)
|
81
63
|
else:
|
82
|
-
adj_org = sp.coo_matrix(
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
#-
|
64
|
+
adj_org = sp.coo_matrix(
|
65
|
+
(np.ones(spatial_net.shape[0]), (spatial_net['Cell1'], spatial_net['Cell2'])),
|
66
|
+
shape=(adata.n_obs, adata.n_obs)
|
67
|
+
)
|
68
|
+
adj_norm = preprocess_graph(adj_org)
|
69
|
+
norm_value = adj_org.shape[0] ** 2 / ((adj_org.shape[0] ** 2 - adj_org.sum()) * 2)
|
89
70
|
graph_dict = {
|
90
71
|
"adj_org": adj_org,
|
91
|
-
"adj_norm":
|
92
|
-
"norm_value":
|
72
|
+
"adj_norm": adj_norm,
|
73
|
+
"norm_value": norm_value
|
93
74
|
}
|
94
|
-
#-
|
95
75
|
return graph_dict
|
gsMap/GNN_VAE/model.py
CHANGED
@@ -1,87 +1,89 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
"""
|
4
|
-
Created on Mon Jul 3 11:42:44 2023
|
5
|
-
|
6
|
-
@author: songliyang
|
7
|
-
"""
|
8
|
-
|
9
1
|
import torch
|
10
2
|
import torch.nn as nn
|
11
3
|
import torch.nn.functional as F
|
12
4
|
from torch_geometric.nn import GATConv
|
13
5
|
|
14
|
-
|
15
6
|
def full_block(in_features, out_features, p_drop):
|
16
|
-
return nn.Sequential(
|
17
|
-
|
18
|
-
|
19
|
-
|
7
|
+
return nn.Sequential(
|
8
|
+
nn.Linear(in_features, out_features),
|
9
|
+
nn.BatchNorm1d(out_features),
|
10
|
+
nn.ELU(),
|
11
|
+
nn.Dropout(p=p_drop)
|
12
|
+
)
|
20
13
|
|
21
|
-
|
22
|
-
|
23
|
-
def __init__(self, in_features, out_features, dr=0, act=F.relu,heads=1):
|
14
|
+
class GATModel(nn.Module):
|
15
|
+
def __init__(self, input_dim, params, num_classes=1):
|
24
16
|
super().__init__()
|
25
|
-
self.conv1 = GATConv(in_features, out_features,heads)
|
26
|
-
self.act = act
|
27
|
-
self.dr = dr
|
28
|
-
#-
|
29
|
-
def forward(self, x, edge_index):
|
30
|
-
out = self.conv1(x, edge_index)
|
31
|
-
out = self.act(out)
|
32
|
-
out = F.dropout(out, self.dr, self.training)
|
33
|
-
return out
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
class GNN_VAE_Model(nn.Module):
|
38
|
-
def __init__(self, input_dim,params,num_classes=1):
|
39
|
-
super(GNN_VAE_Model, self).__init__()
|
40
17
|
self.var = params.var
|
41
18
|
self.num_classes = num_classes
|
42
|
-
|
19
|
+
self.params = params
|
20
|
+
|
43
21
|
# Encoder
|
44
|
-
self.encoder = nn.Sequential(
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
self.
|
51
|
-
|
52
|
-
|
22
|
+
self.encoder = nn.Sequential(
|
23
|
+
full_block(input_dim, params.feat_hidden1, params.p_drop),
|
24
|
+
full_block(params.feat_hidden1, params.feat_hidden2, params.p_drop)
|
25
|
+
)
|
26
|
+
|
27
|
+
# GAT Layers
|
28
|
+
self.gat1 = GATConv(
|
29
|
+
in_channels=params.feat_hidden2,
|
30
|
+
out_channels=params.gat_hidden1,
|
31
|
+
heads=params.nheads,
|
32
|
+
dropout=params.p_drop
|
33
|
+
)
|
34
|
+
self.gat2 = GATConv(
|
35
|
+
in_channels=params.gat_hidden1 * params.nheads,
|
36
|
+
out_channels=params.gat_hidden2,
|
37
|
+
heads=1,
|
38
|
+
concat=False,
|
39
|
+
dropout=params.p_drop
|
40
|
+
)
|
41
|
+
if self.var:
|
42
|
+
self.gat3 = GATConv(
|
43
|
+
in_channels=params.gat_hidden1 * params.nheads,
|
44
|
+
out_channels=params.gat_hidden2,
|
45
|
+
heads=1,
|
46
|
+
concat=False,
|
47
|
+
dropout=params.p_drop
|
48
|
+
)
|
49
|
+
|
53
50
|
# Decoder
|
54
|
-
self.decoder = nn.Sequential(
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
self.cluster
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
51
|
+
self.decoder = nn.Sequential(
|
52
|
+
full_block(params.gat_hidden2, params.feat_hidden2, params.p_drop),
|
53
|
+
full_block(params.feat_hidden2, params.feat_hidden1, params.p_drop),
|
54
|
+
nn.Linear(params.feat_hidden1, input_dim)
|
55
|
+
)
|
56
|
+
|
57
|
+
# Clustering Layer
|
58
|
+
self.cluster = nn.Sequential(
|
59
|
+
full_block(params.gat_hidden2, params.feat_hidden2, params.p_drop),
|
60
|
+
nn.Linear(params.feat_hidden2, self.num_classes)
|
61
|
+
)
|
62
|
+
|
63
|
+
def encode(self, x, edge_index):
|
64
|
+
x = self.encoder(x)
|
65
|
+
x = self.gat1(x, edge_index)
|
66
|
+
x = F.relu(x)
|
67
|
+
x = F.dropout(x, p=self.params.p_drop, training=self.training)
|
68
|
+
|
69
|
+
mu = self.gat2(x, edge_index)
|
68
70
|
if self.var:
|
69
|
-
logvar = self.
|
71
|
+
logvar = self.gat3(x, edge_index)
|
70
72
|
return mu, logvar
|
71
73
|
else:
|
72
74
|
return mu, None
|
73
|
-
|
75
|
+
|
74
76
|
def reparameterize(self, mu, logvar):
|
75
77
|
if self.training and logvar is not None:
|
76
|
-
std = torch.exp(logvar)
|
78
|
+
std = torch.exp(0.5 * logvar)
|
77
79
|
eps = torch.randn_like(std)
|
78
|
-
return eps
|
80
|
+
return eps * std + mu
|
79
81
|
else:
|
80
82
|
return mu
|
81
|
-
|
82
|
-
def forward(self, x,
|
83
|
-
mu, logvar = self.encode(x,
|
84
|
-
|
85
|
-
x_reconstructed = self.decoder(
|
86
|
-
pred_label = F.softmax(self.cluster(
|
87
|
-
return pred_label, x_reconstructed,
|
83
|
+
|
84
|
+
def forward(self, x, edge_index):
|
85
|
+
mu, logvar = self.encode(x, edge_index)
|
86
|
+
z = self.reparameterize(mu, logvar)
|
87
|
+
x_reconstructed = self.decoder(z)
|
88
|
+
pred_label = F.softmax(self.cluster(z), dim=1)
|
89
|
+
return pred_label, x_reconstructed, z, mu, logvar
|
gsMap/GNN_VAE/train.py
CHANGED
@@ -1,97 +1,86 @@
|
|
1
|
-
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
"""
|
4
|
-
Created on Tue Jul 4 19:58:58 2023
|
5
|
-
|
6
|
-
@author: songliyang
|
7
|
-
"""
|
1
|
+
import logging
|
8
2
|
import time
|
9
3
|
|
10
4
|
import torch
|
5
|
+
import torch.nn.functional as F
|
11
6
|
from progress.bar import Bar
|
12
7
|
|
13
|
-
from gsMap.GNN_VAE.model import
|
8
|
+
from gsMap.GNN_VAE.model import GATModel
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
14
11
|
|
15
12
|
|
16
13
|
def reconstruction_loss(decoded, x):
|
17
|
-
|
18
|
-
|
19
|
-
return loss
|
14
|
+
"""Compute the mean squared error loss."""
|
15
|
+
return F.mse_loss(decoded, x)
|
20
16
|
|
21
17
|
|
22
18
|
def label_loss(pred_label, true_label):
|
23
|
-
|
24
|
-
|
25
|
-
return loss
|
26
|
-
|
27
|
-
|
28
|
-
class Model_Train:
|
29
|
-
def __init__(self, node_X, graph_dict, params, label=None):
|
30
|
-
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
31
|
-
torch.cuda.empty_cache()
|
19
|
+
"""Compute the cross-entropy loss."""
|
20
|
+
return F.cross_entropy(pred_label, true_label)
|
32
21
|
|
22
|
+
class ModelTrainer:
|
23
|
+
def __init__(self, node_x, graph_dict, params, label=None):
|
24
|
+
"""Initialize the ModelTrainer with data and hyperparameters."""
|
25
|
+
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
33
26
|
self.params = params
|
34
|
-
self.device = device
|
35
27
|
self.epochs = params.epochs
|
36
|
-
self.
|
37
|
-
self.adj_norm = graph_dict["adj_norm"].to(device).coalesce()
|
28
|
+
self.node_x = torch.FloatTensor(node_x).to(self.device)
|
29
|
+
self.adj_norm = graph_dict["adj_norm"].to(self.device).coalesce()
|
38
30
|
self.label = label
|
39
31
|
self.num_classes = 1
|
40
|
-
|
41
|
-
if
|
32
|
+
|
33
|
+
if self.label is not None:
|
42
34
|
self.label = torch.tensor(self.label).to(self.device)
|
43
|
-
self.num_classes = len(self.label
|
44
|
-
|
45
|
-
# Set
|
46
|
-
self.model =
|
47
|
-
self.optimizer = torch.optim.Adam(
|
48
|
-
|
49
|
-
|
50
|
-
|
35
|
+
self.num_classes = len(torch.unique(self.label))
|
36
|
+
|
37
|
+
# Set up the model
|
38
|
+
self.model = GATModel(self.params.feat_cell, self.params, self.num_classes).to(self.device)
|
39
|
+
self.optimizer = torch.optim.Adam(
|
40
|
+
self.model.parameters(),
|
41
|
+
lr=self.params.gat_lr,
|
42
|
+
weight_decay=self.params.gcn_decay
|
43
|
+
)
|
44
|
+
|
51
45
|
def run_train(self):
|
46
|
+
"""Train the model."""
|
52
47
|
self.model.train()
|
53
48
|
prev_loss = float('inf')
|
54
|
-
|
55
|
-
bar =
|
56
|
-
|
49
|
+
bar = Bar('GAT-AE model train:', max=self.epochs)
|
50
|
+
bar.check_tty = False
|
51
|
+
|
52
|
+
logger.info('Start training...')
|
57
53
|
for epoch in range(self.epochs):
|
58
54
|
start_time = time.time()
|
59
|
-
self.model.train()
|
60
55
|
self.optimizer.zero_grad()
|
61
|
-
pred_label, de_feat, latent_z, mu, logvar = self.model(self.
|
62
|
-
loss_rec = reconstruction_loss(de_feat, self.
|
63
|
-
|
64
|
-
|
65
|
-
if not self.label is None:
|
56
|
+
pred_label, de_feat, latent_z, mu, logvar = self.model(self.node_x, self.adj_norm)
|
57
|
+
loss_rec = reconstruction_loss(de_feat, self.node_x)
|
58
|
+
|
59
|
+
if self.label is not None:
|
66
60
|
loss_pre = label_loss(pred_label, self.label)
|
67
|
-
loss =
|
61
|
+
loss = self.params.rec_w * loss_rec + self.params.label_w * loss_pre
|
68
62
|
else:
|
69
63
|
loss = loss_rec
|
70
|
-
|
64
|
+
|
71
65
|
loss.backward()
|
72
66
|
self.optimizer.step()
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
bar_str = '{} / {} | Left time: {batch_time:.2f} mins| Loss: {loss:.4f}'
|
80
|
-
bar.suffix = bar_str.format(epoch + 1,self.epochs,
|
81
|
-
batch_time = batch_time * (self.epochs - epoch) / 60, loss=loss.item())
|
67
|
+
|
68
|
+
batch_time = time.time() - start_time
|
69
|
+
left_time = batch_time * (self.epochs - epoch - 1) / 60 # in minutes
|
70
|
+
|
71
|
+
bar.suffix = f'{epoch + 1} / {self.epochs} | Left time: {left_time:.2f} mins | Loss: {loss.item():.4f}'
|
82
72
|
bar.next()
|
83
|
-
|
84
|
-
# Check convergence
|
73
|
+
|
85
74
|
if abs(loss.item() - prev_loss) <= self.params.convergence_threshold and epoch >= 200:
|
86
|
-
|
75
|
+
logger.info('\nConvergence reached. Training stopped.')
|
87
76
|
break
|
88
77
|
|
89
78
|
prev_loss = loss.item()
|
90
|
-
|
91
79
|
bar.finish()
|
92
|
-
|
80
|
+
|
93
81
|
def get_latent(self):
|
82
|
+
"""Retrieve the latent representation from the model."""
|
94
83
|
self.model.eval()
|
95
|
-
|
96
|
-
|
97
|
-
return latent_z
|
84
|
+
with torch.no_grad():
|
85
|
+
_, _, latent_z, _, _ = self.model(self.node_x, self.adj_norm)
|
86
|
+
return latent_z.cpu().numpy()
|
gsMap/__init__.py
CHANGED
gsMap/config.py
CHANGED
@@ -55,7 +55,8 @@ def add_find_latent_representations_args(parser):
|
|
55
55
|
add_shared_args(parser)
|
56
56
|
parser.add_argument('--input_hdf5_path', required=True, type=str, help='Path to the input HDF5 file.')
|
57
57
|
parser.add_argument('--annotation', required=True, type=str, help='Name of the annotation in adata.obs to use.')
|
58
|
-
parser.add_argument('--data_layer',
|
58
|
+
parser.add_argument('--data_layer', type=str, default='counts', required=True,
|
59
|
+
help='Data layer for gene expression (e.g., "count", "counts", "log1p").')
|
59
60
|
parser.add_argument('--epochs', type=int, default=300, help='Number of training epochs.')
|
60
61
|
parser.add_argument('--feat_hidden1', type=int, default=256, help='Neurons in the first hidden layer.')
|
61
62
|
parser.add_argument('--feat_hidden2', type=int, default=128, help='Neurons in the second hidden layer.')
|
@@ -66,7 +67,6 @@ def add_find_latent_representations_args(parser):
|
|
66
67
|
parser.add_argument('--n_neighbors', type=int, default=11, help='Number of neighbors for GAT.')
|
67
68
|
parser.add_argument('--n_comps', type=int, default=300, help='Number of principal components for PCA.')
|
68
69
|
parser.add_argument('--weighted_adj', action='store_true', help='Use weighted adjacency in GAT.')
|
69
|
-
parser.add_argument('--var', action='store_true', help='Enable variance calculations.')
|
70
70
|
parser.add_argument('--convergence_threshold', type=float, default=1e-4, help='Threshold for convergence.')
|
71
71
|
parser.add_argument('--hierarchically', action='store_true', help='Enable hierarchical latent representation finding.')
|
72
72
|
|
@@ -236,8 +236,8 @@ def add_run_all_mode_args(parser):
|
|
236
236
|
help='Path to the input spatial transcriptomics data (H5AD format).')
|
237
237
|
parser.add_argument('--annotation', type=str, required=True,
|
238
238
|
help='Name of the annotation in adata.obs to use.')
|
239
|
-
parser.add_argument('--data_layer', type=str, default='
|
240
|
-
help='Data layer
|
239
|
+
parser.add_argument('--data_layer', type=str, default='counts', required=True,
|
240
|
+
help='Data layer for gene expression (e.g., "count", "counts", "log1p").')
|
241
241
|
|
242
242
|
# GWAS Data Parameters
|
243
243
|
parser.add_argument('--trait_name', type=str, help='Name of the trait for GWAS analysis (required if sumstats_file is provided).')
|
@@ -1,145 +1,145 @@
|
|
1
1
|
import logging
|
2
2
|
import random
|
3
|
-
|
4
3
|
import numpy as np
|
5
|
-
import pandas as pd
|
6
4
|
import scanpy as sc
|
7
5
|
import torch
|
8
|
-
from sklearn import
|
9
|
-
|
10
|
-
from gsMap.GNN_VAE.adjacency_matrix import
|
11
|
-
from gsMap.GNN_VAE.train import
|
6
|
+
from sklearn.decomposition import PCA
|
7
|
+
from sklearn.preprocessing import LabelEncoder
|
8
|
+
from gsMap.GNN_VAE.adjacency_matrix import construct_adjacency_matrix
|
9
|
+
from gsMap.GNN_VAE.train import ModelTrainer
|
12
10
|
from gsMap.config import FindLatentRepresentationsConfig
|
13
11
|
|
14
12
|
logger = logging.getLogger(__name__)
|
15
13
|
|
14
|
+
|
16
15
|
def set_seed(seed_value):
|
17
16
|
"""
|
18
|
-
Set seed for reproducibility in PyTorch.
|
17
|
+
Set seed for reproducibility in PyTorch and other libraries.
|
19
18
|
"""
|
20
|
-
torch.manual_seed(seed_value)
|
21
|
-
np.random.seed(seed_value)
|
22
|
-
random.seed(seed_value)
|
19
|
+
torch.manual_seed(seed_value)
|
20
|
+
np.random.seed(seed_value)
|
21
|
+
random.seed(seed_value)
|
23
22
|
if torch.cuda.is_available():
|
24
|
-
logger.info('
|
25
|
-
torch.cuda.manual_seed(seed_value)
|
26
|
-
torch.cuda.manual_seed_all(seed_value)
|
23
|
+
logger.info('Using GPU for computations.')
|
24
|
+
torch.cuda.manual_seed(seed_value)
|
25
|
+
torch.cuda.manual_seed_all(seed_value)
|
27
26
|
else:
|
28
|
-
logger.info('
|
27
|
+
logger.info('Using CPU for computations.')
|
29
28
|
|
29
|
+
def preprocess_data(adata, params):
|
30
|
+
"""
|
31
|
+
Preprocess the AnnData
|
32
|
+
"""
|
33
|
+
logger.info('Preprocessing data...')
|
34
|
+
adata.var_names_make_unique()
|
35
|
+
|
36
|
+
sc.pp.filter_genes(adata, min_cells=30)
|
37
|
+
if params.data_layer in adata.layers.keys():
|
38
|
+
adata.X = adata.layers[params.data_layer]
|
39
|
+
else:
|
40
|
+
raise ValueError(f'Invalid data layer: {params.data_layer}, please check the input data.')
|
30
41
|
|
31
|
-
|
32
|
-
class Latent_Representation_Finder:
|
42
|
+
if params.data_layer in ['count', 'counts']:
|
33
43
|
|
34
|
-
|
35
|
-
|
36
|
-
self.Params = args
|
44
|
+
sc.pp.normalize_total(adata, target_sum=1e4)
|
45
|
+
sc.pp.log1p(adata)
|
37
46
|
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
sc.pp.scale(self.adata)
|
45
|
-
else:
|
46
|
-
if self.Params.data_layer != 'X':
|
47
|
-
self.adata.X = self.adata.layers[self.Params.data_layer]
|
48
|
-
sc.pp.highly_variable_genes(self.adata, n_top_genes=self.Params.feat_cell)
|
47
|
+
# Identify highly variable genes
|
48
|
+
sc.pp.highly_variable_genes(
|
49
|
+
adata,
|
50
|
+
flavor="seurat_v3",
|
51
|
+
n_top_genes=params.feat_cell,
|
52
|
+
)
|
49
53
|
|
50
|
-
|
54
|
+
elif params.data_layer in adata.layers.keys():
|
55
|
+
logger.info(f'Using {params.data_layer} data...')
|
56
|
+
sc.pp.highly_variable_genes(
|
57
|
+
adata,
|
58
|
+
flavor="seurat",
|
59
|
+
n_top_genes=params.feat_cell,
|
60
|
+
)
|
51
61
|
|
52
|
-
|
53
|
-
graph_dict = Construct_Adjacency_Matrix(self.adata, self.Params)
|
62
|
+
return adata
|
54
63
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
64
|
+
|
65
|
+
class LatentRepresentationFinder:
|
66
|
+
def __init__(self, adata, args: FindLatentRepresentationsConfig):
|
67
|
+
self.params = args
|
68
|
+
|
69
|
+
self.expression_array = adata[:, adata.var.highly_variable].X.copy()
|
70
|
+
|
71
|
+
if self.params.data_layer in ['count', 'counts']:
|
72
|
+
self.expression_array = sc.pp.scale(self.expression_array, max_value=10)
|
73
|
+
|
74
|
+
# Construct the neighboring graph
|
75
|
+
self.graph_dict = construct_adjacency_matrix(adata, self.params)
|
76
|
+
|
77
|
+
def compute_pca(self):
|
78
|
+
self.latent_pca = PCA(n_components=self.params.feat_cell).fit_transform(self.expression_array)
|
79
|
+
return self.latent_pca
|
80
|
+
|
81
|
+
def run_gnn_vae(self, label, verbose='whole ST data'):
|
82
|
+
|
83
|
+
# Use PCA if specified
|
84
|
+
if self.params.input_pca:
|
85
|
+
node_X = self.compute_pca()
|
86
|
+
else:
|
87
|
+
node_X = self.expression_array
|
60
88
|
|
61
89
|
# Update the input shape
|
62
|
-
self.
|
63
|
-
self.
|
90
|
+
self.params.n_nodes = node_X.shape[0]
|
91
|
+
self.params.feat_cell = node_X.shape[1]
|
64
92
|
|
65
|
-
# Run GNN
|
66
|
-
logger.info(f'
|
67
|
-
gvae =
|
93
|
+
# Run GNN
|
94
|
+
logger.info(f'Finding latent representations for {verbose}...')
|
95
|
+
gvae = ModelTrainer(node_X, self.graph_dict, self.params, label)
|
68
96
|
gvae.run_train()
|
69
97
|
|
70
|
-
|
98
|
+
del self.graph_dict
|
71
99
|
|
72
|
-
|
73
|
-
sc.tl.pca(self.adata)
|
74
|
-
return self.adata.obsm['X_pca'][:, 0:self.Params.n_comps]
|
100
|
+
return gvae.get_latent()
|
75
101
|
|
76
102
|
|
77
|
-
def run_find_latent_representation(args:FindLatentRepresentationsConfig):
|
103
|
+
def run_find_latent_representation(args: FindLatentRepresentationsConfig):
|
78
104
|
set_seed(2024)
|
79
|
-
|
80
|
-
args.hdf5_with_latent_path.parent.mkdir(parents=True, exist_ok=True,mode=0o755)
|
105
|
+
|
81
106
|
# Load the ST data
|
82
|
-
logger.info(f'
|
83
|
-
adata = sc.read_h5ad(
|
84
|
-
adata.
|
85
|
-
|
86
|
-
logger.info('The ST data contains %d cells, %d genes.' % (adata.shape[0], adata.shape[1]))
|
107
|
+
logger.info(f'Loading ST data of {args.sample_name}...')
|
108
|
+
adata = sc.read_h5ad(args.input_hdf5_path)
|
109
|
+
logger.info(f'The ST data contains {adata.shape[0]} cells, {adata.shape[1]} genes.')
|
110
|
+
|
87
111
|
# Load the cell type annotation
|
88
|
-
if
|
89
|
-
#
|
90
|
-
adata = adata[~
|
112
|
+
if args.annotation is not None:
|
113
|
+
# Remove cells without enough annotations
|
114
|
+
adata = adata[~adata.obs[args.annotation].isnull()]
|
91
115
|
num = adata.obs[args.annotation].value_counts()
|
92
|
-
|
116
|
+
valid_annotations = num[num >= 30].index.to_list()
|
117
|
+
adata = adata[adata.obs[args.annotation].isin(valid_annotations)]
|
93
118
|
|
94
|
-
le =
|
95
|
-
le.
|
96
|
-
adata.obs['categorical_label']
|
97
|
-
label = adata.obs['categorical_label'].to_list()
|
119
|
+
le = LabelEncoder()
|
120
|
+
adata.obs['categorical_label'] = le.fit_transform(adata.obs[args.annotation])
|
121
|
+
label = adata.obs['categorical_label'].to_numpy()
|
98
122
|
else:
|
99
123
|
label = None
|
100
|
-
# Find latent representations
|
101
|
-
latent_rep = Latent_Representation_Finder(adata, args)
|
102
|
-
latent_GVAE = latent_rep.Run_GNN_VAE(label)
|
103
|
-
latent_PCA = latent_rep.Run_PCA()
|
104
|
-
# Add latent representations to the spe data
|
105
|
-
logger.info(f'------Adding latent representations...')
|
106
|
-
adata.obsm["latent_GVAE"] = latent_GVAE
|
107
|
-
adata.obsm["latent_PCA"] = latent_PCA
|
108
|
-
# Run umap based on latent representations
|
109
|
-
for name in ['latent_GVAE', 'latent_PCA']:
|
110
|
-
sc.pp.neighbors(adata, n_neighbors=10, use_rep=name)
|
111
|
-
sc.tl.umap(adata)
|
112
|
-
adata.obsm['X_umap_' + name] = adata.obsm['X_umap']
|
113
124
|
|
114
|
-
|
115
|
-
|
116
|
-
logger.info(f'------Finding latent representations hierarchically...')
|
117
|
-
PCA_all = pd.DataFrame()
|
118
|
-
GVAE_all = pd.DataFrame()
|
125
|
+
# Preprocess data
|
126
|
+
adata = preprocess_data(adata, args)
|
119
127
|
|
120
|
-
|
121
|
-
|
122
|
-
|
128
|
+
latent_rep = LatentRepresentationFinder(adata, args)
|
129
|
+
latent_gvae = latent_rep.run_gnn_vae(label)
|
130
|
+
latent_pca = latent_rep.compute_pca()
|
123
131
|
|
124
|
-
|
125
|
-
|
132
|
+
# Add latent representations to the AnnData object
|
133
|
+
logger.info('Adding latent representations...')
|
134
|
+
adata.obsm["latent_GVAE"] = latent_gvae
|
135
|
+
adata.obsm["latent_PCA"] = latent_pca
|
126
136
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
latent_GVAE_part.index = adata_part.obs_names
|
134
|
-
latent_PCA_part.index = adata_part.obs_names
|
135
|
-
|
136
|
-
GVAE_all = pd.concat((GVAE_all, latent_GVAE_part), axis=0)
|
137
|
-
PCA_all = pd.concat((PCA_all, latent_PCA_part), axis=0)
|
138
|
-
|
139
|
-
args.feat_cell = num_features
|
137
|
+
# Run UMAP based on latent representations
|
138
|
+
for name in ['latent_GVAE', 'latent_PCA']:
|
139
|
+
sc.pp.neighbors(adata, n_neighbors=10, use_rep=name)
|
140
|
+
sc.tl.umap(adata)
|
141
|
+
adata.obsm['X_umap_' + name] = adata.obsm['X_umap']
|
140
142
|
|
141
|
-
|
142
|
-
|
143
|
-
logger.info(f'------Saving ST data...')
|
143
|
+
# Save the AnnData object
|
144
|
+
logger.info('Saving ST data...')
|
144
145
|
adata.write(args.hdf5_with_latent_path)
|
145
|
-
|
gsMap/format_sumstats.py
CHANGED
@@ -150,10 +150,10 @@ def gwas_checkname(gwas, config):
|
|
150
150
|
'Pos': 'SNP positions.'
|
151
151
|
}
|
152
152
|
|
153
|
-
|
153
|
+
logger.info(f'\nIterpreting column names as follows:')
|
154
154
|
for key, value in interpreting.items():
|
155
155
|
if key in new_name:
|
156
|
-
|
156
|
+
logger.info(f'{name_dict[key]}: {interpreting[key]}')
|
157
157
|
|
158
158
|
return gwas
|
159
159
|
|
@@ -242,7 +242,7 @@ def gwas_qc(gwas, config):
|
|
242
242
|
Filter out SNPs based on INFO, FRQ, MAF, N, and Genotypes.
|
243
243
|
'''
|
244
244
|
old = len(gwas)
|
245
|
-
|
245
|
+
logger.info(f'\nFiltering SNPs as follows:')
|
246
246
|
# filter: SNPs with missing values
|
247
247
|
drops = {'NA': 0, 'P': 0, 'INFO': 0, 'FRQ': 0, 'A': 0, 'SNP': 0, 'Dup': 0, 'N': 0}
|
248
248
|
|
@@ -250,28 +250,28 @@ def gwas_qc(gwas, config):
|
|
250
250
|
lambda x: x != 'INFO', gwas.columns)).reset_index(drop=True)
|
251
251
|
|
252
252
|
drops['NA'] = old - len(gwas)
|
253
|
-
|
253
|
+
logger.info(f'Removed {drops["NA"]} SNPs with missing values.')
|
254
254
|
|
255
255
|
# filter: SNPs with Info < 0.9
|
256
256
|
if 'INFO' in gwas.columns:
|
257
257
|
old = len(gwas)
|
258
258
|
gwas = gwas.loc[filter_info(gwas['INFO'], config)]
|
259
259
|
drops['INFO'] = old - len(gwas)
|
260
|
-
|
260
|
+
logger.info(f'Removed {drops["INFO"]} SNPs with INFO <= 0.9.')
|
261
261
|
|
262
262
|
# filter: SNPs with MAF <= 0.01
|
263
263
|
if 'FRQ' in gwas.columns:
|
264
264
|
old = len(gwas)
|
265
265
|
gwas = gwas.loc[filter_frq(gwas['FRQ'], config)]
|
266
266
|
drops['FRQ'] += old - len(gwas)
|
267
|
-
|
267
|
+
logger.info(f'Removed {drops["FRQ"]} SNPs with MAF <= 0.01.')
|
268
268
|
|
269
269
|
# filter: P-value that out-of-bounds [0,1]
|
270
270
|
if 'P' in gwas.columns:
|
271
271
|
old = len(gwas)
|
272
272
|
gwas = gwas.loc[filter_pvals(gwas['P'], config)]
|
273
273
|
drops['P'] += old - len(gwas)
|
274
|
-
|
274
|
+
logger.info(f'Removed {drops["P"]} SNPs with out-of-bounds p-values.')
|
275
275
|
|
276
276
|
# filter: Variants that are strand-ambiguous
|
277
277
|
if 'A1' in gwas.columns and 'A2' in gwas.columns:
|
@@ -279,21 +279,21 @@ def gwas_qc(gwas, config):
|
|
279
279
|
gwas.A2 = gwas.A2.str.upper()
|
280
280
|
gwas = gwas.loc[filter_alleles(gwas.A1 + gwas.A2)]
|
281
281
|
drops['A'] += old - len(gwas)
|
282
|
-
|
282
|
+
logger.info(f'Removed {drops["A"]} variants that were not SNPs or were strand-ambiguous.')
|
283
283
|
|
284
284
|
# filter: Duplicated rs numbers
|
285
285
|
if 'SNP' in gwas.columns:
|
286
286
|
old = len(gwas)
|
287
287
|
gwas = gwas.drop_duplicates(subset='SNP').reset_index(drop=True)
|
288
288
|
drops['Dup'] += old - len(gwas)
|
289
|
-
|
289
|
+
logger.info(f'Removed {drops["Dup"]} SNPs with duplicated rs numbers.')
|
290
290
|
|
291
291
|
# filter:Sample size
|
292
292
|
n_min = gwas.N.quantile(0.9) / 1.5
|
293
293
|
old = len(gwas)
|
294
294
|
gwas = gwas[gwas.N >= n_min].reset_index(drop=True)
|
295
295
|
drops['N'] += old - len(gwas)
|
296
|
-
|
296
|
+
logger.info(f'Removed {drops["N"]} SNPs with N < {n_min}.')
|
297
297
|
|
298
298
|
return gwas
|
299
299
|
|
@@ -302,7 +302,7 @@ def variant_to_rsid(gwas, config):
|
|
302
302
|
'''
|
303
303
|
Convert variant id (Chr, Pos) to rsid
|
304
304
|
'''
|
305
|
-
|
305
|
+
logger.info("\nConverting the SNP position to rsid. This process may take some time.")
|
306
306
|
unique_ids = set(gwas['id'])
|
307
307
|
chr_format = gwas['Chr'].unique().astype(str)
|
308
308
|
chr_format = [re.sub(r'\d+', '', value) for value in chr_format][1]
|
@@ -347,7 +347,7 @@ def clean_SNP_id(gwas, config):
|
|
347
347
|
gwas = gwas.loc[matching_id.id]
|
348
348
|
gwas['SNP'] = matching_id.dbsnp
|
349
349
|
num_fail = old - len(gwas)
|
350
|
-
|
350
|
+
logger.info(f'Removed {num_fail} SNPs that did not convert to rsid.')
|
351
351
|
|
352
352
|
return gwas
|
353
353
|
|
@@ -356,27 +356,27 @@ def gwas_metadata(gwas, config):
|
|
356
356
|
'''
|
357
357
|
Report key features of GWAS data
|
358
358
|
'''
|
359
|
-
|
359
|
+
logger.info('\nSummary of GWAS data:')
|
360
360
|
CHISQ = (gwas.Z ** 2)
|
361
361
|
mean_chisq = CHISQ.mean()
|
362
|
-
|
362
|
+
logger.info('Mean chi^2 = ' + str(round(mean_chisq, 3)))
|
363
363
|
if mean_chisq < 1.02:
|
364
364
|
logger.warning("Mean chi^2 may be too small.")
|
365
365
|
|
366
|
-
|
367
|
-
|
368
|
-
|
366
|
+
logger.info('Lambda GC = ' + str(round(CHISQ.median() / 0.4549, 3)))
|
367
|
+
logger.info('Max chi^2 = ' + str(round(CHISQ.max(), 3)))
|
368
|
+
logger.info('{N} Genome-wide significant SNPs (some may have been removed by filtering).'.format(N=(CHISQ > 29).sum()))
|
369
369
|
|
370
370
|
|
371
371
|
def gwas_format(config: FormatSumstatsConfig):
|
372
372
|
'''
|
373
373
|
Format GWAS data
|
374
374
|
'''
|
375
|
-
|
375
|
+
logger.info(f'------Formating gwas data for {config.sumstats}...')
|
376
376
|
compression_type = get_compression(config.sumstats)
|
377
377
|
gwas = pd.read_csv(config.sumstats, delim_whitespace=True, header=0, compression=compression_type,
|
378
378
|
na_values=['.', 'NA'])
|
379
|
-
|
379
|
+
logger.info(f'Read {len(gwas)} SNPs from {config.sumstats}.')
|
380
380
|
|
381
381
|
# Check name and format
|
382
382
|
gwas = gwas_checkname(gwas, config)
|
@@ -402,6 +402,6 @@ def gwas_format(config: FormatSumstatsConfig):
|
|
402
402
|
gwas = gwas[keep]
|
403
403
|
out_name = config.out + appendix + '.gz'
|
404
404
|
|
405
|
-
|
405
|
+
logger.info(f'\nWriting summary statistics for {len(gwas)} SNPs to {out_name}.')
|
406
406
|
gwas.to_csv(out_name, sep="\t", index=False,
|
407
407
|
float_format='%.3f', compression='gzip')
|
gsMap/latent_to_gene.py
CHANGED
@@ -4,12 +4,10 @@ from pathlib import Path
|
|
4
4
|
import numpy as np
|
5
5
|
import pandas as pd
|
6
6
|
import scanpy as sc
|
7
|
-
from scipy.sparse import csr_matrix
|
8
7
|
from scipy.stats import gmean
|
9
8
|
from scipy.stats import rankdata
|
10
9
|
from sklearn.metrics.pairwise import cosine_similarity
|
11
10
|
from sklearn.neighbors import NearestNeighbors
|
12
|
-
from joblib import Parallel, delayed
|
13
11
|
from tqdm import tqdm
|
14
12
|
|
15
13
|
from gsMap.config import LatentToGeneConfig
|
@@ -152,11 +150,6 @@ def run_latent_to_gene(config: LatentToGeneConfig):
|
|
152
150
|
adata.var_names = homologs.loc[adata.var_names, 'HUMAN_GENE_SYM'].values
|
153
151
|
adata = adata[:, ~adata.var_names.duplicated()]
|
154
152
|
|
155
|
-
# Remove cells and genes that are not expressed
|
156
|
-
logger.info(f'Number of cells, genes of the input data: {adata.shape[0]},{adata.shape[1]}')
|
157
|
-
adata = adata[adata.X.sum(axis=1) > 0, adata.X.sum(axis=0) > 0]
|
158
|
-
logger.info(f'Number of cells, genes after transformation: {adata.shape[0]},{adata.shape[1]}')
|
159
|
-
|
160
153
|
# Create mappings
|
161
154
|
n_cells = adata.n_obs
|
162
155
|
n_genes = adata.n_vars
|
@@ -20,8 +20,6 @@ logger = logging.getLogger('gsMap.spatial_ldsc')
|
|
20
20
|
|
21
21
|
# %%
|
22
22
|
def _coef_new(jknife):
|
23
|
-
# return coef[0], coef_se[0], z[0]]
|
24
|
-
# est_ = jknife.est[0, 0] / Nbar
|
25
23
|
est_ = jknife.jknife_est[0, 0] / Nbar
|
26
24
|
se_ = jknife.jknife_se[0, 0] / Nbar
|
27
25
|
return est_, se_
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: gsMap
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.67
|
4
4
|
Summary: Genetics-informed pathogenic spatial mapping
|
5
5
|
Author-email: liyang <songliyang@westlake.edu.cn>, wenhao <chenwenhao@westlake.edu.cn>
|
6
6
|
Requires-Python: >=3.8
|
@@ -27,7 +27,7 @@ Requires-Dist: pyfiglet
|
|
27
27
|
Requires-Dist: plotly
|
28
28
|
Requires-Dist: kaleido
|
29
29
|
Requires-Dist: jinja2
|
30
|
-
Requires-Dist: scanpy
|
30
|
+
Requires-Dist: scanpy >=1.8.0
|
31
31
|
Requires-Dist: zarr
|
32
32
|
Requires-Dist: bitarray
|
33
33
|
Requires-Dist: pyarrow
|
@@ -1,22 +1,22 @@
|
|
1
|
-
gsMap/__init__.py,sha256=
|
1
|
+
gsMap/__init__.py,sha256=dO26Gwp-UoxhNp0ZHWuBVMGsjg6EVy09d93LGJ7pjqA,78
|
2
2
|
gsMap/__main__.py,sha256=jR-HT42Zzfj2f-7kFJy0bkWjNxcV1MyfQHXFpef2nSE,62
|
3
3
|
gsMap/cauchy_combination_test.py,sha256=zBPR7DOaNkr7rRoua4tAjRZL7ArjCyMRSQlPSUdHNSE,5694
|
4
|
-
gsMap/config.py,sha256=
|
4
|
+
gsMap/config.py,sha256=xHSIAdt5_4Vdr_2CA-YR1Wbn7i0FW70Eokd0cbi4hqU,41109
|
5
5
|
gsMap/diagnosis.py,sha256=pp3ONVaWCOoNCog1_6eud38yicBFxL-XhH7D8iTBgF4,13220
|
6
|
-
gsMap/find_latent_representation.py,sha256=
|
7
|
-
gsMap/format_sumstats.py,sha256=
|
6
|
+
gsMap/find_latent_representation.py,sha256=SOGSEHyi7XAPJnTUIRWHv-fCXHR3K9UYcyJI_nuPHFY,4834
|
7
|
+
gsMap/format_sumstats.py,sha256=00VLNbfjXRqIgFn44WM-mMIboLTYTRn_3JiEtqJDfeQ,13846
|
8
8
|
gsMap/generate_ldscore.py,sha256=2JfQoMWeQ0-B-zRHakmwq8ovkeewlnWHUCnih6od6ZE,29089
|
9
|
-
gsMap/latent_to_gene.py,sha256=
|
9
|
+
gsMap/latent_to_gene.py,sha256=oRYtRcq1TLXpzkoP_l93CwPDPc6LZvw6_MGrdPJhC_o,9686
|
10
10
|
gsMap/main.py,sha256=skyBtESdjvuXd9HNq5c83OPxQTNgLVErkYhwuJm8tE4,1285
|
11
11
|
gsMap/report.py,sha256=H0uYAru2L5-d41_LFHPPdoJbtiTzP4f8kX-mirUNAfc,6963
|
12
12
|
gsMap/run_all_mode.py,sha256=sPEct9fRw7aAQuU7BNChxk-I8YQcXuq--mtBn-2wTTY,8388
|
13
13
|
gsMap/setup.py,sha256=eOoPalGAHTY06_7a35nvbOaKQhq0SBE5GK4pc4bp3wc,102
|
14
|
-
gsMap/spatial_ldsc_multiple_sumstats.py,sha256=
|
14
|
+
gsMap/spatial_ldsc_multiple_sumstats.py,sha256=qyKLeWz-_78WMjkpnMtoSJyJcDLnfp-armyY_mzlwkI,18391
|
15
15
|
gsMap/visualize.py,sha256=FLIRHHj1KntLMFDjAhg1jZnJUdvrncR74pCW2Kj5pus,7453
|
16
16
|
gsMap/GNN_VAE/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
gsMap/GNN_VAE/adjacency_matrix.py,sha256=
|
18
|
-
gsMap/GNN_VAE/model.py,sha256=
|
19
|
-
gsMap/GNN_VAE/train.py,sha256=
|
17
|
+
gsMap/GNN_VAE/adjacency_matrix.py,sha256=TJzf5JGPDfC0-50xRP1Tdf7xqEPBLBl9E9VvQq5FE1g,3333
|
18
|
+
gsMap/GNN_VAE/model.py,sha256=6c_zw_PTg9uBnRng9fNoU3HlbrjEP1j5cxFzwPJEW5s,2959
|
19
|
+
gsMap/GNN_VAE/train.py,sha256=Etro9QKA5jU14uO17wI_gzV0Nl4YFubk9A--jpRrM4w,3095
|
20
20
|
gsMap/templates/report_template.html,sha256=pdxHFl_W0W351NUzuJTf_Ay_BfKlEbD_fztNabAGmmg,8214
|
21
21
|
gsMap/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
gsMap/utils/generate_r2_matrix.py,sha256=A1BrUnlTrYjRwEKxK0I1FbZ5SCQzcviWVM-JzFHHRkw,29352
|
@@ -24,8 +24,8 @@ gsMap/utils/jackknife.py,sha256=nEDPVQJOPQ_uqfUCGX_v5cQwokgCqUmJTT_8rVFuIQo,1824
|
|
24
24
|
gsMap/utils/make_annotations.py,sha256=lCbtahT27WFOwLgZrEUE5QcNRuMXmAFYUfsFR-cT-m0,22197
|
25
25
|
gsMap/utils/manhattan_plot.py,sha256=k3n-NNgMsov9-8UQrirVqG560FUfJ4d6wNG8C0OeCjY,26235
|
26
26
|
gsMap/utils/regression_read.py,sha256=n_hZZzQXHU-CSLvSofXmQM5Jw4Zpufv3U2HoUW344ko,8768
|
27
|
-
gsmap-1.
|
28
|
-
gsmap-1.
|
29
|
-
gsmap-1.
|
30
|
-
gsmap-1.
|
31
|
-
gsmap-1.
|
27
|
+
gsmap-1.67.dist-info/entry_points.txt,sha256=s_P2Za22O077tc1FPLKMinbdRVXaN_HTcDBgWMYpqA4,41
|
28
|
+
gsmap-1.67.dist-info/LICENSE,sha256=Ni2F-lLSv_H1xaVT3CoSrkiKzMvlgwh-dq8PE1esGyI,1094
|
29
|
+
gsmap-1.67.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
30
|
+
gsmap-1.67.dist-info/METADATA,sha256=YgGfS9s8cnWLy7fWpptkcMUKsMqcFdMod_V_RlMp0dM,3384
|
31
|
+
gsmap-1.67.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|