OSCR

Accelerating Leigh syndrome drug discovery through deep learning screening in brain organoids.

Code ↔ Paper

4 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 4 matches
  1. [1] § Methods › Development of DL-based framework for drug repurposing › Step 3: FNNs for drug target prediction ↔ model_library.py, lines 321–412 · score 0.95 · LeakyReLU, weight decay, hidden layer, decay factor, L1, L2
  2. [2] § Methods › Development of DL-based framework for drug repurposing › Step 2: Denoising and regularization with variational autoencoder (VAE) ↔ model_library.py, lines 226–290 · score 0.94 · fully connected layers, ReLU, batch normalization, initial hidden, encoder, reparameterization
  3. [3] § Methods › Development of DL-based framework for drug repurposing › Step 1: Graph-based feature embeddings ↔ model_library.py, lines 56–80 · score 0.79 · PolynomialFeatures, min max, bias, expanded, median, sum
  4. [4] § Methods › Development of DL-based framework for drug repurposing › Step 4: Ranking drugs by Bayesian enrichment score (BES) ↔ model_library.py, lines 435–455 · score 0.53 · normalized rank, posterior, zero, BES, min, hypergeometric

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 457 lines · 22 KB · no license · 4 matches

  1. import os, sys, time, glob, fcntl, argparse
  2. from pathlib import Path
  3. import numpy as np
  4. import pandas as pd
  5. import torch
  6. import torchvision
  7. from torch import nn
  8. import torch.nn.functional as F
  9. import torch.optim as optim
  10. from torch.utils.data import Dataset, DataLoader
  11. from torch_sparse import SparseTensor
  12. import pytorch_lightning as pl
  13. from tqdm import tqdm
  14. from sklearn.metrics import confusion_matrix
  15. from sklearn.preprocessing import PolynomialFeatures, StandardScaler
  16. from igraph import *
  17. from torch_geometric.data import Batch
  18. from torch_geometric.data import DataLoader as gDataLoader
  19. from torch_geometric.utils import (
  20. to_undirected, dropout_adj, add_self_loops, degree
  21. )
  22. Dtype = 'float32'
  23. device = 'cpu'
  24. def get_adj(row, col, value, N, norm=False, asymm_norm=False, set_diag=True, remove_diag=False):
  25. print(set_diag)
  26. adj = SparseTensor(row=row, col=col, value=value, sparse_sizes=(N, N))
  27. if set_diag:
  28. print('... setting diagonal entries')
  29. adj = adj.set_diag()
  30. elif remove_diag:
  31. print('... removing diagonal entries')
  32. adj = adj.remove_diag()
  33. else:
  34. print('... keeping diag elements as they are')
  35. if norm==True:
  36. if not asymm_norm:
  37. print('... performing symmetric normalization')
  38. deg = adj.sum(dim=1).to(torch.float)
  39. deg_inv_sqrt = deg.pow(-0.5)
  40. deg_inv_sqrt[deg_inv_sqrt == float('inf')] = 0
  41. adj = deg_inv_sqrt.view(-1, 1) * adj * deg_inv_sqrt.view(1, -1)
  42. else:
  43. print('... performing asymmetric normalization')
  44. deg = adj.sum(dim=1).to(torch.float)
  45. deg_inv = deg.pow(-1.0)
  46. deg_inv[deg_inv == float('inf')] = 0
  47. adj = deg_inv.view(-1, 1) * adj
  48. else:
  49. print('... no normalization')
  50. #
  51. adj = adj.to_scipy(layout='csr')
  52. #
  53. return adj
  54. def expandAndNormalizeEmbedding(gD, normalization):
  55. num_nodes = gD[0]['op_embedding'][0].shape[0]
  56. Xtrain = torch.zeros(len(gD)*gD[0]['op_embedding'][0].shape[0], (2*len(gD[0]['op_embedding'])+len(gD[0]['properties'])) )
  57. print('All feature train shapes:')
  58. print(Xtrain.shape)
  59. for i in range(len(gD)):
  60. start = i*num_nodes
  61. end = (i+1)*num_nodes
  62. op_dict = gD[i]
  63. Xtrain[start:end,:] = torch.cat([torch.cat(op_dict['op_embedding'],dim=1), torch.cat(op_dict['properties'],dim=1)], axis=1)
  64. Xtrain = Xtrain.float()
  65. # aggregation: sum, mean, max, min, median, std, 25%, 75%, difference between sucssessive columns
  66. Xtrain = torch.cat((Xtrain, torch.sum(Xtrain,1).view(-1,1), torch.mean(Xtrain,1).view(-1,1), torch.max(Xtrain,1).values.view(-1,1), torch.min(Xtrain,1).values.view(-1,1), torch.median(Xtrain,1).values.view(-1,1), torch.quantile(Xtrain, 0.25, dim=1, keepdim=True), torch.quantile(Xtrain, 0.75, dim=1, keepdim=True), (Xtrain[:,torch.arange(4,22,2)] - Xtrain[:,torch.arange(2,20,2)]), (Xtrain[:,torch.arange(5,22,2)] - Xtrain[:,torch.arange(3,20,2)]) ) ,1)
  67. # polynomical features:
  68. pf = PolynomialFeatures(degree=2, interaction_only=False, include_bias=False)
  69. Xtrain = torch.from_numpy(pf.fit_transform(Xtrain)).float()
  70. print('feature synthesis done',flush=True)
  71. print('train shapes:')
  72. print(Xtrain)
  73. print(Xtrain.shape)
  74. if normalization=='minMax':
  75. mi,ma,r = torch.load('GNN_normalization_factors_minMax_{}.pt'.format(str(Xtrain.shape[1])) )
  76. Xtrain = (Xtrain - mi)/r
  77. Xtrain = Xtrain.float()
  78. return Xtrain
  79. def makeX2(X1, T2, Nodes):
  80. gen = [i.split('__', 1)[0] for i in T2]
  81. moa = [1 if i.split('__', 1)[1]=='act' else 2 for i in T2]
  82. X2 = np.zeros(len(Nodes))
  83. X2[[Nodes.index(i) for i in gen]] = moa
  84. X2 = np.tile(X2,(X1.shape[0],1))
  85. if len(X1.shape)==1: X1.shape=(1,X1.shape[0])
  86. if len(X2.shape)==1: X2.shape=(1,X2.shape[0])
  87. print(X1.shape); print(X2.shape)
  88. X1dim = X1.shape[1]
  89. X2dim = X2.shape[1]
  90. return X1, X2, X1dim
  91. class SimpleDataset(Dataset):
  92. def __init__(self, x, y):
  93. self.x = x
  94. self.y = y
  95. assert self.x.size(0) == self.y.size(0)
  96. def __len__(self):
  97. return self.x.size(0)
  98. def __getitem__(self, idx):
  99. return self.x[idx], self.y[idx]
  100. def prepareRealdataDataLoader(X1_file, DETF_file, removeColFile, normalization):
  101. directed_asymm_norm = True
  102. directed_set_diag = False
  103. directed_remove_diag = False
  104. num_propagations = 5
  105. num_node_features = 2
  106. num_hops = 11
  107. Nodes = open('nodeList_adjacency_PKN_sorted_GNN_nodeLabel.csv', 'r').read().splitlines()
  108. num_nodes = len(Nodes)
  109. # Graph
  110. PKN = np.loadtxt("adjacency_PKN.csv.gz", delimiter=",",dtype=Dtype)
  111. g = Graph.Weighted_Adjacency(PKN)
  112. PKN = PKN.T
  113. e = np.where(PKN!=0)
  114. edge_index = torch.cat((torch.unsqueeze(torch.from_numpy(e[0]),0), torch.unsqueeze(torch.from_numpy(e[1]),0) ), axis=0)
  115. np.sum(PKN[np.array(edge_index[0]),np.array(edge_index[1])]==0)
  116. # Reactome count
  117. RE = np.loadtxt("adjacency_Reactome_count.csv.gz", delimiter=",",dtype=Dtype)
  118. e2 = np.where(RE!=0)
  119. edge_index_RE = torch.cat((torch.unsqueeze(torch.from_numpy(e2[0]),0), torch.unsqueeze(torch.from_numpy(e2[1]),0) ), axis=0)
  120. np.sum(RE[np.array(edge_index_RE[0]),np.array(edge_index_RE[1])]==0)
  121. DETFs = []
  122. X1 = np.loadtxt(X1_file, delimiter=",")
  123. text_file = open(DETF_file, "r"); lines = text_file.read().split("\n"); DETFs = [l for l in lines if l!='']; DETFs = [x for x in DETFs if x.split("__")[0] in Nodes]
  124. ## graph embedding ##
  125. row, col = edge_index
  126. rowRE, colRE = edge_index_RE
  127. edgeRE = torch.tensor(RE[rowRE,colRE])
  128. adjRE = get_adj(rowRE, colRE, edgeRE, num_nodes, norm=False, asymm_norm=directed_asymm_norm, set_diag=directed_set_diag, remove_diag=directed_remove_diag) # only once
  129. I_TFs = open('TF_indices.csv', 'r').read().splitlines()
  130. I_TFs = [int(i) for i in I_TFs]
  131. col_to_remove = torch.load(removeColFile)
  132. X1, X2, num_nodes = makeX2(X1, DETFs, Nodes) # just 1 input statei
  133. tensor_X1 = torch.Tensor(X1)
  134. tensor_X2 = torch.Tensor(X2)
  135. # graph embedding
  136. gD = createGraphEmbedding(num_nodes, tensor_X1, tensor_X2, None, None, adjRE, num_propagations, g, edge_index, row, col, directed_asymm_norm, directed_set_diag, directed_remove_diag, I_TFs, num_hops)
  137. # expand, synthesize and normalize embedding
  138. Xdata = expandAndNormalizeEmbedding(gD, normalization)
  139. # remvoe columns
  140. Xdata = Xdata[:,~col_to_remove]
  141. Xdata = torch.nan_to_num(Xdata, nan=0.0)
  142. print(Xdata)
  143. print(Xdata.shape)
  144. # dataloader
  145. num_features = Xdata.shape[1]
  146. query_dataset = SimpleDataset(Xdata, torch.zeros([Xdata.shape[0]])) # dummy class
  147. query_loader = DataLoader(query_dataset, batch_size=1000000, shuffle=False)
  148. return(query_loader)
  149. def createGraphEmbedding(num_nodes, tensor_X1, tensor_X2, tensor_y, tensor_y2, adjRE, num_propagations, g, edge_index, row, col, directed_asymm_norm, directed_set_diag, directed_remove_diag, I_TFs, num_hops):
  150. all_idx = torch.tensor([i for i in range(num_nodes)])
  151. gD = []
  152. for i in range(tensor_X1.shape[0]):
  153. op_dict = {}
  154. batch_x = torch.stack([tensor_X1[i], tensor_X2[i]],dim=1)
  155. batch_x2 = torch.stack([tensor_X1[i], tensor_X2[i]],dim=1) # for opposite direction
  156. edge_multiple = batch_x[:,0][np.array(edge_index[0])] * batch_x[:,0][np.array(edge_index[1])]
  157. edge_multiple = edge_multiple / edge_multiple.max().item() # scaling
  158. adj = get_adj(row, col, edge_multiple, num_nodes, norm=False, asymm_norm=directed_asymm_norm, set_diag=directed_set_diag, remove_diag=directed_remove_diag)
  159. adj2 = get_adj(row, col, edge_multiple, num_nodes, norm=False, asymm_norm=directed_asymm_norm, set_diag=directed_set_diag, remove_diag=directed_remove_diag)
  160. # For reactome network
  161. absoluteDEG = torch.abs(batch_x[:,1])
  162. # For shortest paths
  163. g.es['weight'] = np.round(np.array(1 / (edge_multiple + 1)),3) # inverse edge weights for shortest paths
  164. degs = torch.where(batch_x[:,1]!=0)[0].tolist()
  165. detfs = list(set(I_TFs) & set(degs))
  166. if len(detfs)==0:
  167. detfs = degs
  168. elif len(detfs) > 10:
  169. detfs = np.array(detfs)[np.random.randint(0,len(detfs),10)].tolist()
  170. if tensor_y==None:
  171. op_dict['label'] = []
  172. else:
  173. op_dict['label'] = torch.stack([tensor_y[i].to(torch.long), tensor_y2[i].to(torch.long)],dim=1)
  174. op_dict['op_embedding'] = []
  175. op_dict['op_embedding'].append(batch_x[all_idx].to(torch.float))
  176. print('Diffusing node features')
  177. for _ in tqdm(range(num_propagations)):
  178. # 1. forward
  179. batch_x = adj @ batch_x
  180. op_dict['op_embedding'].append(torch.from_numpy(batch_x[all_idx]))
  181. # 2. transposed
  182. batch_x2 = adj2 @ batch_x2
  183. op_dict['op_embedding'].append(torch.from_numpy(batch_x2[all_idx]))
  184. # Reactome overlap
  185. op_dict['properties'] = []
  186. op_dict['properties'].append(torch.tensor(adjRE @ absoluteDEG).reshape(-1,1) )
  187. # network properties
  188. op_dict['properties'].append(torch.tensor(g.strength(weights=g.es['weight'], mode='in')).reshape(-1,1) )
  189. op_dict['properties'].append(torch.tensor(g.strength(weights=g.es['weight'], mode='out')).reshape(-1,1) )
  190. print("Computing shortest paths to DETFs...")
  191. s = g.shortest_paths(source=detfs, target=None,weights=g.es['weight'], mode='in') # the heavier the longer
  192. s = np.array(s)
  193. s[s==0] = 'inf'
  194. # reachability ratio (how many can each gene reach / total DEGs)
  195. rr = (s.shape[0] - np.sum(np.isinf(s),0)) / s.shape[0]
  196. op_dict['properties'].append(torch.tensor(rr.reshape(-1,1)))
  197. # average SP to DEGs
  198. s[np.isinf(s)] = 100
  199. op_dict['properties'].append(torch.tensor(np.mean(s,0).reshape(-1,1)))
  200. # Louvain community label
  201. g_undirected = g.as_undirected()
  202. g_undirected.es['weight'] = (torch.abs(edge_multiple) + 1e-6).cpu().numpy()
  203. community_labels = g_undirected.community_multilevel(weights=g_undirected.es['weight']).membership
  204. op_dict['properties'].append(torch.tensor(community_labels).reshape(-1, 1))
  205. # Nonlinear Transformations
  206. signed_log_transformed = torch.sign(op_dict['op_embedding'][-1]) * torch.log(torch.abs(op_dict['op_embedding'][-1]) + 1e-6) # signed Log
  207. sqrt_features = torch.sqrt(torch.clamp(op_dict['op_embedding'][-1], min=0)) # Square root
  208. quadrart_features = torch.pow(torch.clamp(op_dict['op_embedding'][-1], min=0), 1/4)
  209. op_dict['op_embedding'].extend([signed_log_transformed, sqrt_features, quadrart_features])
  210. # Pseudo-Temporal Analysis
  211. temporal_change = [ op_dict['op_embedding'][t] - op_dict['op_embedding'][t-1] for t in range(1, num_hops-1) ]
  212. op_dict['op_embedding'].extend(temporal_change)
  213. # Node Similarity
  214. cos_sim = F.cosine_similarity(torch.tensor(batch_x).unsqueeze(0), torch.tensor(batch_x).unsqueeze(1), dim=2)
  215. del batch_x, batch_x2
  216. op_dict['properties'].append(cos_sim.mean(dim=1).reshape(-1, 1))
  217. gD.append(op_dict)
  218. return gD
  219. class VAE_decrease(nn.Module):
  220. def __init__(self, in_channels, initial_hidden_size, num_layers, dropout, latent_dimension):
  221. super(VAE_decrease, self).__init__()
  222. # Encoder Layer Sizes (decreasing)
  223. self.encoder_sizes = self._generate_hidden_sizes(initial_hidden_size, num_layers, decreasing=True)
  224. self.decoder_sizes = self.encoder_sizes[::-1] # Decoder Layer Sizes (reverse of encoder)
  225. # Encoder
  226. self.encoder_layers = nn.ModuleList()
  227. prev_channels = in_channels
  228. for hidden_size in self.encoder_sizes:
  229. self.encoder_layers.append(self._build_layer(prev_channels, hidden_size, dropout, batch_norm=True))
  230. prev_channels = hidden_size
  231. self.fc_mu = nn.Linear(self.encoder_sizes[-1], latent_dimension)
  232. self.fc_logvar = nn.Linear(self.encoder_sizes[-1], latent_dimension)
  233. # Decoder
  234. self.decoder_layers = nn.ModuleList()
  235. prev_channels = latent_dimension
  236. for hidden_size in self.decoder_sizes:
  237. self.decoder_layers.append(self._build_layer(prev_channels, hidden_size, dropout, batch_norm=False)) # No BatchNorm in decoder
  238. prev_channels = hidden_size
  239. # Final output layer
  240. self.output_layer = nn.Linear(self.decoder_sizes[-1], in_channels)
  241. def _generate_hidden_sizes(self, initial_size, num_layers, decreasing=True):
  242. """Generate hidden layer sizes with an intermediate non-power-of-2 layer, then powers of 2"""
  243. sizes = [initial_size]
  244. # Find the largest power of 2 smaller than initial_size
  245. largest_power_of_2 = 2 ** (initial_size.bit_length() - 1)
  246. if largest_power_of_2 == initial_size:
  247. largest_power_of_2 //= 2 # If it's already a power of 2, go one step lower
  248. # Add the largest power of 2
  249. sizes.append(largest_power_of_2)
  250. # Progressively decrease in powers of 2
  251. size = largest_power_of_2 // 2
  252. for _ in range(num_layers - 2):
  253. sizes.append(size)
  254. size = max(size // 2, 8) # Ensure it doesn't go below 8
  255. return sizes
  256. def _build_layer(self, in_features, out_features, dropout, batch_norm):
  257. """Creates a single fully connected layer with activation & dropout"""
  258. layers = [nn.Linear(in_features, out_features)]
  259. if batch_norm:
  260. layers.append(nn.BatchNorm1d(out_features))
  261. layers.append(nn.ReLU())
  262. if dropout > 0:
  263. layers.append(nn.Dropout(dropout))
  264. return nn.Sequential(*layers)
  265. def encode(self, x):
  266. for layer in self.encoder_layers:
  267. x = layer(x)
  268. mu = self.fc_mu(x)
  269. logvar = self.fc_logvar(x)
  270. logvar = torch.clamp(logvar, min=-5, max=5) # Prevent extreme variance collapse
  271. return mu, logvar
  272. def reparameterize(self, mu, logvar):
  273. std = torch.exp(0.5 * logvar)
  274. eps = torch.randn_like(std)
  275. return mu + eps * std
  276. def decode(self, z):
  277. for layer in self.decoder_layers:
  278. z = layer(z)
  279. return torch.sigmoid(self.output_layer(z)) # Output constrained to [0,1]
  280. def forward(self, x):
  281. mu, logvar = self.encode(x)
  282. z = self.reparameterize(mu, logvar)
  283. return self.decode(z), mu, logvar
  284. def evaluate_ffn(y_true, y_pred):
  285. # Convert tensors to numpy if needed
  286. y_true = y_true.cpu().numpy() if isinstance(y_true, torch.Tensor) else np.array(y_true)
  287. y_pred = y_pred.cpu().numpy() if isinstance(y_pred, torch.Tensor) else np.array(y_pred)
  288. # Handle Class 3 as wildcard: prediction of 1 or 2 is considered correct
  289. y_true_adj = y_true.copy()
  290. class3_mask = y_true == 3
  291. if np.any(class3_mask):
  292. correct_mask = class3_mask & ((y_pred == 1) | (y_pred == 2))
  293. y_true_adj[correct_mask] = y_pred[correct_mask]
  294. y_true_adj[class3_mask & (y_pred == 0)] = -1 # Mark as invalid
  295. # Filter out invalid labels (-1)
  296. valid_mask = y_true_adj != -1
  297. y_true_adj = y_true_adj[valid_mask]
  298. y_pred = y_pred[valid_mask]
  299. # Derived stats
  300. labels = np.unique(np.concatenate((y_true_adj, y_pred)))
  301. cm = confusion_matrix(y_true_adj, y_pred, labels=labels)
  302. TP = np.diag(cm).sum()
  303. FP = cm.sum(axis=0).sum() - TP
  304. FN = cm.sum(axis=1).sum() - TP
  305. TN = cm.sum() - (TP + FP + FN)
  306. precision = TP / (TP + FP + 1e-8)
  307. recall = TP / (TP + FN + 1e-8)
  308. f1 = 2 * precision * recall / (precision + recall + 1e-8)
  309. fpr = FP / (FP + TN + 1e-8)
  310. fnr = FN / (FN + TP + 1e-8)
  311. return {"f1": f1, "fpr": fpr, "fnr": fnr}
  312. class FFN_decay(pl.LightningModule):
  313. def __init__(self, in_channels, initial_size, out_channels, num_layers, dropout=0.0, decay_factor=0.7, lr=0.005, l1_lambda=0.0, l2_lambda=0.0):
  314. super(FFN_decay, self).__init__()
  315. self.save_hyperparameters()
  316. self.hidden_layer_sizes = self._generate_hidden_sizes(num_layers, initial_size, decay_factor)
  317. self.layers = nn.ModuleList()
  318. prev_channels = in_channels
  319. for hidden_channels in self.hidden_layer_sizes:
  320. self.layers.append(nn.Sequential(
  321. nn.Linear(prev_channels, hidden_channels),
  322. nn.BatchNorm1d(hidden_channels, momentum=0.9),
  323. nn.LeakyReLU(),
  324. nn.Dropout(dropout)
  325. ))
  326. prev_channels = hidden_channels
  327. self.layers.append(nn.Linear(prev_channels, out_channels))
  328. self.lr = lr
  329. self.l1_lambda = l1_lambda
  330. self.l2_lambda = l2_lambda
  331. self.best_val_metrics = {"f1": 0, "fpr": 1, "fnr": 1}
  332. self.best_test_metrics = {"f1": 0, "fpr": 1, "fnr": 1}
  333. def _generate_hidden_sizes(self, num_layers, initial_size, decay_factor=0.7):
  334. hidden_sizes = []
  335. size = initial_size
  336. for _ in range(num_layers):
  337. hidden_sizes.append(size)
  338. size = max(int(size * decay_factor), 8)
  339. return hidden_sizes
  340. def reset_parameters(self):
  341. for layer in self.layers:
  342. if isinstance(layer, nn.Sequential):
  343. for sub_layer in layer:
  344. if hasattr(sub_layer, 'reset_parameters'):
  345. sub_layer.reset_parameters()
  346. elif hasattr(layer, 'reset_parameters'):
  347. layer.reset_parameters()
  348. def forward(self, x):
  349. for layer in self.layers[:-1]:
  350. x = layer(x)
  351. return self.layers[-1](x)
  352. def step(self, batch, mode="train"):
  353. x, labels = batch
  354. logits = self(x)
  355. loss = F.cross_entropy(logits, labels, reduction='mean')
  356. if self.l1_lambda > 0:
  357. l1_penalty = sum(p.abs().sum() for p in self.parameters() if p.requires_grad)
  358. loss = loss + self.l1_lambda * l1_penalty
  359. preds = logits.argmax(dim=1)
  360. eval_results = evaluate_ffn(labels, preds) # Updated function
  361. self.log_dict({
  362. f"{mode}_loss": loss.item(),
  363. f"{mode}_f1": eval_results["f1"],
  364. f"{mode}_fpr": eval_results["fpr"],
  365. f"{mode}_fnr": eval_results["fnr"]
  366. }, sync_dist=True, prog_bar=True)
  367. return loss, eval_results
  368. def training_step(self, batch, batch_idx):
  369. loss, eval_results = self.step(batch, mode="train")
  370. total_batches = self.trainer.num_training_batches
  371. print(f"Batch {batch_idx+1}/{total_batches}: Loss = {loss.item():.6f}", end="\r")
  372. return loss
  373. def validation_step(self, batch, batch_idx, dataloader_idx=0):
  374. loss, eval_results = self.step(batch, mode="val")
  375. return {"loss": loss, **eval_results, "dataloader_idx": dataloader_idx}
  376. def validation_epoch_end(self, outputs):
  377. if isinstance(outputs[0], list):
  378. val_outputs = outputs[0]
  379. test_outputs = outputs[1] if len(outputs) > 1 else []
  380. else:
  381. val_outputs, test_outputs = outputs, []
  382. def aggregate_metrics(output_list, prefix):
  383. if len(output_list) == 0:
  384. return {f"{prefix}_{key}": 0 for key in ["f1", "fpr", "fnr"]}
  385. return {
  386. f"{prefix}_{key}": torch.tensor([float(x[key]) for x in output_list], dtype=torch.float32).mean().item()
  387. for key in ["f1", "fpr", "fnr"]
  388. }
  389. val_metrics = aggregate_metrics(val_outputs, "val")
  390. test_metrics = aggregate_metrics(test_outputs, "test")
  391. self.log_dict(val_metrics, sync_dist=True, prog_bar=True)
  392. self.log_dict(test_metrics, sync_dist=True, prog_bar=True)
  393. train_metrics = {key: self.trainer.logged_metrics.get(f"train_{key}", 0) for key in ["f1", "fpr", "fnr"]}
  394. val_metrics = {key: val_metrics.get(f"val_{key}", 0) for key in ["f1", "fpr", "fnr"]}
  395. test_metrics = {key: test_metrics.get(f"test_{key}", 0) for key in ["f1", "fpr", "fnr"]}
  396. print(f"Epoch {self.current_epoch}: "
  397. f"train_f1 = {train_metrics['f1']:.4f}, fpr = {train_metrics['fpr']:.4f}, fnr = {train_metrics['fnr']:.4f} | "
  398. f"val_f1 = {val_metrics['f1']:.4f}, fpr = {val_metrics['fpr']:.4f}, fnr = {val_metrics['fnr']:.4f} | "
  399. f"test_f1 = {test_metrics['f1']:.4f}, fpr = {test_metrics['fpr']:.4f}, fnr = {test_metrics['fnr']:.4f}")
  400. def configure_optimizers(self):
  401. optimizer = torch.optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.l2_lambda)
  402. scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)
  403. return {"optimizer": optimizer, "lr_scheduler": scheduler}
  404. def exportPredictedProteins(outfile, sigPs):
  405. with open(outfile,'w') as wr:
  406. for i in range(len(sigPs)):
  407. wr.write(sigPs[i] +"\n")
  408. def wait_for_file(directory, filename, interval=1, timeout=60):
  409. file_path = os.path.join(directory, filename)
  410. # Pre-check if file already exists
  411. if os.path.exists(file_path):
  412. #print(f"File {filename} already exists")
  413. return True
  414. #print(f"Waiting for {filename} to appear in {directory}...")
  415. start_time = time.time()
  416. while time.time() - start_time < timeout:
  417. if os.path.exists(file_path):
  418. #print(f"File {filename} detected")
  419. return True
  420. time.sleep(interval)
  421. print("Timeout: File did not appear.")
  422. return False
  423. def compute_BES_score(pemp, hypergeo_pval, rank_hy, pi0=0.99, w_posterior=20.0, w_hypergeo=1.0, w_hypergeo_rank=1.0, pemp_penalty_multiplier=1.0):
  424. # Convert to arrays
  425. pemp = np.array(pemp, dtype=float)
  426. hypergeo_pval = np.array(hypergeo_pval, dtype=float)
  427. rank_hy = np.array(rank_hy, dtype=float)
  428. # Identify invalid scores: zero jaccard or hypergeo p = 1 (not 0!)
  429. mask_zero = hypergeo_pval == 1.0
  430. # Posterior and penalty
  431. posterior = 1 - pi0 * pemp
  432. pemp_soft_penalty = np.exp(-pemp_penalty_multiplier * (1 - pemp))
  433. s_posterior = posterior * pemp_soft_penalty
  434. # Normalized rank components (1 = best)
  435. rank_hy_norm = 1 - (rank_hy - np.min(rank_hy)) / (np.max(rank_hy) - np.min(rank_hy) + 1e-8)
  436. # BES score
  437. BES = (w_posterior * s_posterior + w_hypergeo * (1 - hypergeo_pval) + w_hypergeo_rank * rank_hy_norm)
  438. # Apply hard zero override
  439. BES[mask_zero] = 0.0
  440. # Ranking: higher score = better
  441. BES_rank = pd.Series(BES).rank(ascending=False, method='min').values
  442. BES_rank[BES == 0.0] = len(BES)
  443. return BES, BES_rank

model_library.py at commit b0cfe8b, no license · at the source

Overview

Authors: Carmen Menacho1,2, Satoshi Okawa3,4, Iris Álvarez-Merz5, Annika Wittich6, Mikel Muñoz-Oreja7, Pawel Lisowski8,9,10,11, Mario López Martín12, Tancredi Massimo Pentimalli8,9,13, Shiri Zakin14, Mathuravani Thevandavakkam14, Caleb Jerred1,2,15, Selene Lickfett1,2, Laura Petersilie5, Agnieszka Rybak-Wolf8,9, Annette Seibt1, Diran Herebian1, Gizem Inak8,16, Susanne Brodesser17, Andrea Zaliani6, Barbara Mlody8,18
and 20 other authorsJustin Donnelly13, Kasey Woleben19, Francesc Xavier Soriano20, Jose C. Fernandez-Checa21,22,23,24, Natascia Ventura15,25,26, Sidney Cambridge27, Ertan Mayatepek1, Antonella Spinazzola28, Markus Schuelke29,30, Nikolaus Rajewsky8,9,30,31,32,33, Andrea Rossi34, Alex Peralvarez-Marin12, Felix Distelmaier1, Ethan Perlstein14, Ian J. Holt7,35,36,37, Emma Puighermanal38, Ole Pless6, Christine R. Rose5, Antonio Del Sol3,35,39, Alessandro Prigione1
39 affiliations
  1. Department of General Pediatrics, Neonatology and Pediatric Cardiology, Medical Faculty and University Hospital Düsseldorf, Heinrich Heine University Düsseldorf,Düsseldorf, Germany
  2. Faculty of Mathematics and Natural Sciences, Heinrich Heine University Düsseldorf,Düsseldorf, Germany
  3. Computational Biology Group, Luxembourg Centre for Systems Biomedicine, University of Luxembourg,Esch-sur-Alzette, Luxembourg
  4. University of Pittsburgh School of Medicine, Vascular Medicine Institute,Pittsburgh, PA USA
  5. Institute of Neurobiology, Heinrich Heine University,Düsseldorf, Germany
  6. Fraunhofer Institute for Translational Medicine and Pharmacology ITMP, Discovery Research ScreeningPort,Hamburg, Germany
  7. Department of Neurosciences, Biogipuzkoa Health Research Institute,San Sebastian, Spain
  8. Max Delbrück Center for Molecular Medicine in the Helmholtz Association (MDC),Berlin, Germany
  9. Berlin Institute for Medical Systems Biology (BIMSB), Berlin, Germany
  10. Neuropsychiatry and Laboratory of Molecular Psychiatry, Department of Psychiatry and Neurosciences, Charité—Universitätsmedizin,Berlin, Germany
  11. Department of Molecular Biology, Institute of Genetics and Animal Biotechnology, Polish Academy of Sciences,Jastrzebiec n/Warsaw, Poland
  12. Unit of Biophysics, Department of Biochemistry and Molecular Biology Institute of Neurosciences, Universitat Autònoma de Barcelona,Barcelona, Spain
  13. Charité—Universitätsmedizin,Berlin, Germany
  14. Perlara PBC, Vancouver, WA USA
  15. Institute of Cell Biology, Heinrich Heine University,Düsseldorf, Germany
  16. Present Address: Axol Bioscience Ltd, Berlin, Germany
  17. Cluster of Excellence Cellular Stress Responses in Aging-associated Diseases (CECAD), Faculty of Medicine and University Hospital of Cologne, University of Cologne,Cologne, Germany
  18. Present Address: Centogene GmbH,Rostock, Germany
  19. Cure Mito Foundation, McKinney, TX USA
  20. Celltec-UB, Departament de Biologia Cellular, Fisiologia i Immunologia, Institut de Neurociències, Universitat de Barcelona,Barcelona, Spain
  21. Department of Molecular and Cellular Biomedicine, Institute of Biomedical Research of Barcelona (IIBB), CSIC,Barcelona, Spain
  22. Liver Unit, Hospital Clinic i Provincial de Barcelona, Institut d’Investigacions Biomèdiques August Pi i Sunyer (IDIBAPS),Barcelona, Spain
  23. Centro de Investigación Biomédica en Red (CIBEREHD),Barcelona, Spain
  24. Department of Medicine, Keck School of Medicine, University of Southern California,Los Angeles, CA USA
  25. IUF-Leibniz Research, Institute for Environmental Medicine,Düsseldorf, Germany
  26. Dept. for the Promotion of Human Science and Quality of Life, San Raffaele University of Rome,Rome, Italy
  27. Institute of Physiological Chemistry, University Medical Center of the Johannes Gutenberg University,Mainz, Germany
  28. Department of Clinical and Movement Neurosciences, UCL Queen Square Institute of Neurology, Royal Free Campus,London, UK
  29. Department of Neuropediatrics, Charité–Universitätsmedizin,Berlin, Germany
  30. NeuroCure Cluster of Excellence,Berlin, Germany
  31. German Center for Cardiovascular Research (DZHK),Berlin, Germany
  32. National Center for Tumor Diseases (NCT), German Cancer Consortium (DKTK),Berlin, Germany
  33. German Center for Neurodegenerative Diseases (DZNE),Berlin, Germany
  34. Genome Engineering and Model Development lab (GEMD), IUF-Leibniz Research, Institute for Environmental Medicine,Düsseldorf, Germany
  35. IKERBASQUE, Basque Foundation for Science,Bilbao, Spain
  36. University of the Basque Country-Bizkaia Campus,Bilbao, Spain
  37. CIBERNED (Center for Networked Biomedical Research on Neurodegenerative Diseases) Ministry of Economy and Competitiveness, Institute Carlos III),Madrid, Spain
  38. Neuroscience Institute, Department of Cell Biology, Physiology and Immunology, Autonomous University of Barcelona,Bellaterra, Spain
  39. CIC bioGUNE-BRTA (Basque Research and Technology Alliance), Bizkaia Technology Park,Derio, Spain
Journal: Nature communications, volume 17, issue 1, article 3570
Dates: received 7 August 2024; accepted 13 March 2026; published online 20 April 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41467-026-71391-2 · PMID 42009687 · PMCID PMC13096141 · OpenAlex W7155003735
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: human (organism)
Methods: Connectivity, Spectral & time-frequency, Statistics, Machine learning, Graphs, fMRI & imaging, Single-unit activity, calcium imaging
Keywords: Neural stem cells, Developmental disorders, Phenotypic screening
MeSH: Brain*, Deep Learning*, Drug Discovery*, Leigh Disease*, Organoids*, Drug Evaluation, Preclinical, Drug Repositioning, Humans, Lipid Metabolism, Neurons, Tretinoin, Triazoles (* major topic)
Topic: Mitochondrial Function and Pathology (Molecular Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: Deutsche Forschungsgemeinschaft (DFG) (PR1527/5-1, PR1527/6-1, PR1527/15-1, PR1527/14-1, and PR1527/13-1, AL2956/1-1, VE366/12-1, RO5380/1-1, Ro2327/13-2); Bundesministerium für Bildung, Wissenschaft, Forschung und Technologie (Federal Ministry for Education, Science, Research and Technology) (01GM2002A); Heinrich Heine University Düsseldorf | Medizinische Fakultät, Heinrich-Heine-Universität Düsseldorf (Medical Faculty, Heinrich-Heine-University); EC | Horizon 2020 Framework Programme (EU Framework Programme for Research and Innovation H2020) (SIMPATHIC #101080249); United Mitochondrial Disease Foundation (UMDF); Eva Luise und Horst Köhler Stiftung; European Joint Programme for Rare Diseases (EJPRD) the Leigh Syndrome International Consortium People Against Leigh syndrome (PALS) the Foundation Maladies Rare and Association (AMMi) Patient organizations MitoCon, Cure Mito, Cure ATP6 and MitoHelp; Studienstiftung des Deutschen Volkes (German National Academic Foundation); UK Medical Research Council (MR/X002365/1); Muscular Dystrophy UK (17GRO-PG24-0184-1, 7GRO-PG24-0184-1); Miriam Marks Senior Fellowship, Brain Research UK (202021-26), the Lily Foundation; Eusko Jaurlaritza (Basque Government) (2021111070, 2022333050, 2018111043, 2018222031); Ministry of Economy and Competitiveness | Instituto de Salud Carlos III (Institute of Health Carlos III) (PI20/00096); Ministerio de ciencia, innovación y universidades [Spain]: PID2023-151649NB-I00; CHAMP foundation; Generalitat de Catalunya (2024 LLAV 00069 to); Ministerio de ciencia, innovación y universidades [Spain]: PID2021-125079OA-I00
Citations: cited by 1 paper (Europe PMC); 151 references in the paper

Abstract

Leigh syndrome (Leigh) is an untreatable mitochondrial disorder characterized by lactic acidosis and basal ganglia and midbrain pathology, leading to psychomotor regression and early death. We previously uncovered impaired neuronal morphogenesis in Leigh cerebral organoids carrying SURF1 gene variants. Leveraging this phenotype, we here develop a deep learning algorithm tailored for cell type-specific drug repurposing screening. In parallel, we perform a survival drug screen in a yeast model of Leigh. The two approaches independently converge on azole compounds, two of which - talarozole and sertaconazole - rescue neuronal morphogenesis in Leigh neurons and lower lactate release and improve growth rate in Leigh midbrain organoids. Mechanistically, these compounds modulate the retinoic acid pathway and membrane-associate lipid metabolism. The findings highlight azoles as promising candidates for Leigh and demonstrate the potential of combining in silico screens with human brain organoids as new approach methodologies (NAMs) to advance the discovery of therapeutics addressing rare neurodevelopmental disorders.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 4 matches between paragraphs and lines of code.

osb-codes/dl_drug_repurposing

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: b0cfe8b88e7e46c7c1f4bee21f416f6e30cfbb9f, 17 December 2025
Languages: Python (4), Shell (3), R (1)
Size: 215 files, 8 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: PyTorch (5 files), NumPy (4 files), PyTorch Lightning (2 files), pandas (2 files), scikit-learn (2 files), igraph (1 file), Matplotlib (1 file), PyTorch Geometric (1 file), SciPy (1 file), TensorFlow (1 file), UMAP (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
9 files

Code availability

The program code and input files are available at: https://github.com/OSB-codes/DL_drug_repurposing/tree/main.

Reproduced under the paper's license (CC BY), from the paper cited above.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 8 scripts, each with its path and the digest of its content;
  • 4 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

Datasets cited

Data availability

There are restrictions to the availability of patient-derived iPSCs due to our ethical approval that does not support sharing with third parties without a specific amendment and does not allow performing genomic studies to respect the European privacy protection law.

Single-cell RNA sequencing (scRNAseq) data are deposited in the Sequence Read Archive (SRA) with bioproject number PRJNA1378526 and can be downloaded at: https://www.ncbi.nlm.nih.gov/bioproject/?term=PRJNA1378526.

Additional scRNAseq data used in this study have been previously deposited in the Gene Expression Omnibus (GEO) database: GSE152915 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE152915), GSE126360, (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE126360), GSE133894 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE133894), GSE271852 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE271852).

Lipidomics data are deposited in Metabolomics Workbench repository151 with project number PR002944 and can be downloaded at: 10.21228/M84C4F. Source data are provided with this paper.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 29 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 40 authors, 3 keywords, 12 MeSH terms, 16 funders, 150 references.

Cite

This paper

Menacho, C., Okawa, S., Álvarez-Merz, I., Wittich, A., Muñoz-Oreja, M., Lisowski, P., Martín, M. L., Pentimalli, T. M., Zakin, S., Thevandavakkam, M., Jerred, C., Lickfett, S., Petersilie, L., Rybak-Wolf, A., Seibt, A., Herebian, D., Inak, G., Brodesser, S., Zaliani, A., . . . Prigione, A. (2026). Accelerating Leigh syndrome drug discovery through deep learning screening in brain organoids. Nature communications, 17(1), 3570. https://doi.org/10.1038/s41467-026-71391-2

BibTeX

@article{menacho2026accelerating,
author = {Menacho, Carmen and Okawa, Satoshi and Álvarez-Merz, Iris and Wittich, Annika and Muñoz-Oreja, Mikel and Lisowski, Pawel and Martín, Mario López and Pentimalli, Tancredi Massimo and Zakin, Shiri and Thevandavakkam, Mathuravani and Jerred, Caleb and Lickfett, Selene and Petersilie, Laura and Rybak-Wolf, Agnieszka and Seibt, Annette and Herebian, Diran and Inak, Gizem and Brodesser, Susanne and Zaliani, Andrea and Mlody, Barbara and Donnelly, Justin and Woleben, Kasey and Soriano, Francesc Xavier and Fernandez-Checa, Jose C. and Ventura, Natascia and Cambridge, Sidney and Mayatepek, Ertan and Spinazzola, Antonella and Schuelke, Markus and Rajewsky, Nikolaus and Rossi, Andrea and Peralvarez-Marin, Alex and Distelmaier, Felix and Perlstein, Ethan and Holt, Ian J. and Puighermanal, Emma and Pless, Ole and Rose, Christine R. and Del Sol, Antonio and Prigione, Alessandro},
title = {{Accelerating Leigh syndrome drug discovery through deep learning screening in brain organoids}},
journal = {Nature communications},
year = {2026},
month = apr,
volume = {17},
number = {1},
pages = {3570},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-71391-2},
url = {https://doi.org/10.1038/s41467-026-71391-2},
pmid = {42009687},
pmcid = {PMC13096141}
}

RIS

TY - JOUR
AU - Menacho, Carmen
AU - Okawa, Satoshi
AU - Álvarez-Merz, Iris
AU - Wittich, Annika
AU - Muñoz-Oreja, Mikel
AU - Lisowski, Pawel
AU - Martín, Mario López
AU - Pentimalli, Tancredi Massimo
AU - Zakin, Shiri
AU - Thevandavakkam, Mathuravani
AU - Jerred, Caleb
AU - Lickfett, Selene
AU - Petersilie, Laura
AU - Rybak-Wolf, Agnieszka
AU - Seibt, Annette
AU - Herebian, Diran
AU - Inak, Gizem
AU - Brodesser, Susanne
AU - Zaliani, Andrea
AU - Mlody, Barbara
AU - Donnelly, Justin
AU - Woleben, Kasey
AU - Soriano, Francesc Xavier
AU - Fernandez-Checa, Jose C.
AU - Ventura, Natascia
AU - Cambridge, Sidney
AU - Mayatepek, Ertan
AU - Spinazzola, Antonella
AU - Schuelke, Markus
AU - Rajewsky, Nikolaus
AU - Rossi, Andrea
AU - Peralvarez-Marin, Alex
AU - Distelmaier, Felix
AU - Perlstein, Ethan
AU - Holt, Ian J.
AU - Puighermanal, Emma
AU - Pless, Ole
AU - Rose, Christine R.
AU - Del Sol, Antonio
AU - Prigione, Alessandro
TI - Accelerating Leigh syndrome drug discovery through deep learning screening in brain organoids
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/04/20
VL - 17
IS - 1
SP - 3570
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-71391-2
UR - https://doi.org/10.1038/s41467-026-71391-2
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-71391-2",
"type": "article-journal",
"title": "Accelerating Leigh syndrome drug discovery through deep learning screening in brain organoids",
"container-title": "Nature communications",
"author": [
{
"family": "Menacho",
"given": "Carmen"
},
{
"family": "Okawa",
"given": "Satoshi"
},
{
"family": "Álvarez-Merz",
"given": "Iris"
},
{
"family": "Wittich",
"given": "Annika"
},
{
"family": "Muñoz-Oreja",
"given": "Mikel"
},
{
"family": "Lisowski",
"given": "Pawel"
},
{
"family": "Martín",
"given": "Mario López"
},
{
"family": "Pentimalli",
"given": "Tancredi Massimo"
},
{
"family": "Zakin",
"given": "Shiri"
},
{
"family": "Thevandavakkam",
"given": "Mathuravani"
},
{
"family": "Jerred",
"given": "Caleb"
},
{
"family": "Lickfett",
"given": "Selene"
},
{
"family": "Petersilie",
"given": "Laura"
},
{
"family": "Rybak-Wolf",
"given": "Agnieszka"
},
{
"family": "Seibt",
"given": "Annette"
},
{
"family": "Herebian",
"given": "Diran"
},
{
"family": "Inak",
"given": "Gizem"
},
{
"family": "Brodesser",
"given": "Susanne"
},
{
"family": "Zaliani",
"given": "Andrea"
},
{
"family": "Mlody",
"given": "Barbara"
},
{
"family": "Donnelly",
"given": "Justin"
},
{
"family": "Woleben",
"given": "Kasey"
},
{
"family": "Soriano",
"given": "Francesc Xavier"
},
{
"family": "Fernandez-Checa",
"given": "Jose C."
},
{
"family": "Ventura",
"given": "Natascia"
},
{
"family": "Cambridge",
"given": "Sidney"
},
{
"family": "Mayatepek",
"given": "Ertan"
},
{
"family": "Spinazzola",
"given": "Antonella"
},
{
"family": "Schuelke",
"given": "Markus"
},
{
"family": "Rajewsky",
"given": "Nikolaus"
},
{
"family": "Rossi",
"given": "Andrea"
},
{
"family": "Peralvarez-Marin",
"given": "Alex"
},
{
"family": "Distelmaier",
"given": "Felix"
},
{
"family": "Perlstein",
"given": "Ethan"
},
{
"family": "Holt",
"given": "Ian J."
},
{
"family": "Puighermanal",
"given": "Emma"
},
{
"family": "Pless",
"given": "Ole"
},
{
"family": "Rose",
"given": "Christine R."
},
{
"family": "Del Sol",
"given": "Antonio"
},
{
"family": "Prigione",
"given": "Alessandro"
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "3570",
"DOI": "10.1038/s41467-026-71391-2",
"PMID": "42009687",
"PMCID": "PMC13096141",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-71391-2",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
20
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: UMAP, igraph, TensorFlow, 5 other tools, 4 references
[2] doi:10.1038/s44320-026-00208-7 [code]
Interpretable deep generative ensemble learning for single-cell omics with Hydra.
Journal: Molecular systems biology
In common: UMAP, igraph, TensorFlow, 6 other tools, 2 references
[3] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: PyTorch Lightning, UMAP, igraph, 7 other tools
[4] doi:10.1021/acs.biochem.5c00596 [code]
Cargo Recognition of Nesprin-2 by the Dynein Adapter Bicaudal D2 for a Nuclear Positioning Pathway That Is Important for Brain Development.
Journal: Biochemistry
In common: PyTorch Lightning, PyTorch Geometric, TensorFlow, 6 other tools, 1 reference
[5] doi:10.1038/s42003-026-10259-z [code]
Spatial transcriptomic profiling of developing mouse hearts reveals a spatially patterned signaling environment.
Journal: Communications biology
In common: PyTorch Lightning, UMAP, PyTorch, 5 other tools, 2 references
[6] doi:10.1038/s41598-026-53415-5 [code]
Computational design and immunoinformatics validation of a T cell multi-epitope vaccine targeting glioblastoma stem cells.
Journal: Scientific reports
In common: PyTorch Lightning, PyTorch Geometric, TensorFlow, 6 other tools
[7] doi:10.1038/s41586-026-10391-0 [code]
Cell-type-targeted mitochondrial transplantation rescues cell degeneration.
Journal: Nature
In common: PyTorch Lightning, PyTorch Geometric, TensorFlow, 6 other tools
[8] doi:10.3390/ijms27156614 [code]
Candidalysin Inhibits &lt;i&gt;Porphyromonas gingivalis&lt;/i&gt; Lipoprotein-Induced IL-1β Production in BV-2 Microglia via Hydrophobic Microbial Interactions.
Journal: International journal of molecular sciences
In common: PyTorch Lightning, PyTorch Geometric, TensorFlow, 6 other tools
[9] doi:10.1016/j.xcrm.2026.102651 [code]
Integrative CSF profiling identifies disease-specific immune responses in leptomeningeal disease.
Journal: Cell reports. Medicine
In common: PyTorch Lightning, UMAP, igraph, 6 other tools
[10] doi:10.1016/j.isci.2026.116055 [code]
Mapping the transcriptional diversity of calcium signaling in the mouse and human brain.
Journal: iScience
In common: PyTorch Geometric, UMAP, igraph, 6 other tools

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.