OSCR

Common transcriptional changes in the brain during hibernation and Alzheimer’s disease

Code ↔ Paper

5 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 5 matches
  1. [1] § MATERIALS AND METHODS › Transcriptional network analysis (SCENIC) ↔ src/scenic/bin/export_to_loom.py, lines 718 to 767 · score 0.73 · PySCENIC, min regulon gene, tools, occurrence, loom, database · Report a mismatch
  2. [2] § MATERIALS AND METHODS › Quality control and processing of single nuclei data ↔ src/scanpy/bin/feature_selection/sc_find_variable_genes.py, lines 96 to 125 · score 0.70 · highly variable genes, min_disp, Scanpy, max, cells · Report a mismatch
  3. [3] § MATERIALS AND METHODS › Quality control and processing of single nuclei data ↔ src/scrublet/bin/sc_doublet_detection.py, lines 174 to 199 · score 0.68 · predicted doublets, highly variable, scrublet, variance, Raw, log · Report a mismatch
  4. [4] § MATERIALS AND METHODS › Transcriptional network analysis (SCENIC) ↔ src/scenic/bin/merge_motif_track_loom.py, lines 18 to 81 · score 0.65 · min regulon gene, pySCENIC, occurrence, loom, motif · Report a mismatch
  5. [5] § MATERIALS AND METHODS › Clustering and cell-type analysis ↔ src/scanpy/bin/cluster/sc_marker_genes.py, lines 76 to 121 · score 0.54 · Leiden algorithm, rank genes, resolutions, Cluster, cell · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 794 lines · 35 KB · no license · 1 match

  1. #!/usr/bin/env python3
  2. import os
  3. import numpy as np
  4. import pandas as pd
  5. import loompy as lp
  6. from sklearn.manifold.t_sne import TSNE
  7. from pyscenic.aucell import aucell
  8. from pyscenic.genesig import Regulon, GeneSignature
  9. from typing import List, Mapping, Sequence, Optional, Dict
  10. from operator import attrgetter
  11. from multiprocessing import cpu_count
  12. from pyscenic.binarization import binarize
  13. from itertools import chain, repeat, islice
  14. import networkx as nx
  15. import zlib
  16. import base64
  17. import json
  18. import re
  19. import sys
  20. from collections import OrderedDict
  21. class Embedding:
  22. def __init__(self, embedding: pd.DataFrame, embedding_name: str, is_default: bool = False):
  23. self.embedding = embedding
  24. self.embedding_name = embedding_name
  25. self._is_default = is_default
  26. def get_embedding_name(self):
  27. return self.embedding_name
  28. def get_embedding(self):
  29. return self.embedding
  30. def is_default(self):
  31. return self._is_default
  32. class SCopeLoom:
  33. def __init__(
  34. self,
  35. filename: str = None,
  36. out_fname: str = None,
  37. ex_mtx: pd.DataFrame = None,
  38. regulons: List[Regulon] = None,
  39. cell_annotations: Optional[Mapping[str, str]] = None,
  40. tree_structure: Sequence[str] = None,
  41. title: Optional[str] = None,
  42. nomenclature: str = "Unknown",
  43. num_workers: int = cpu_count(),
  44. auc_mtx=None,
  45. auc_regulon_weights_key='gene2weight',
  46. auc_thresholds=None,
  47. compress: bool = False,
  48. save_additional_regulon_meta_data: bool = False, # Should be set to true only for multi-runs SCENIC
  49. set_generic_loom: bool = False,
  50. tag: str = None, # Used when merging track and motif-based SCENIC run
  51. col_attrs: Mapping[str, np.ndarray] = None,
  52. row_attrs: Mapping[str, np.ndarray] = None,
  53. global_attrs: Dict = None,
  54. embeddings: Mapping[str, pd.DataFrame] = None
  55. ):
  56. self.filename = filename
  57. self.out_fname = out_fname
  58. self.ex_mtx = ex_mtx
  59. self.regulons = regulons
  60. self.cell_annotations = cell_annotations
  61. self.tree_structure = tree_structure if tree_structure else ()
  62. self.title = title
  63. self.nomenclature = nomenclature
  64. self.num_workers = num_workers
  65. self.auc_mtx = auc_mtx
  66. self.auc_regulon_weights_key = auc_regulon_weights_key
  67. self.auc_thresholds = auc_thresholds
  68. self.compress = compress
  69. self.save_additional_regulon_meta_data = save_additional_regulon_meta_data
  70. self.tag = tag
  71. self.regulon_filter = None
  72. # Loom representation
  73. self.col_attrs = col_attrs if col_attrs else {}
  74. self.row_attrs = row_attrs if row_attrs else {}
  75. self.global_attrs = global_attrs if global_attrs else {}
  76. # Internal representation
  77. self.embeddings = embeddings if embeddings else {}
  78. # Utils
  79. self.id2name = OrderedDict()
  80. # Set Base Loom
  81. if set_generic_loom:
  82. self.set_generic_loom()
  83. def set_generic_loom(self):
  84. if(self.regulons[0].name.find('_') == -1):
  85. print(
  86. "Regulon name does not seem to be compatible with SCOPE. It should include a space to allow selection of the TF.",
  87. "\nPlease run: \n regulons = [r.rename(r.name.replace('(+)','_('+str(len(r))+'g)')) for r in regulons]",
  88. "\nor:\n regulons = [r.rename(r.name.replace('(','_(')) for r in regulons]"
  89. )
  90. self.set_cell_annotations()
  91. if self.auc_mtx is None:
  92. self.auc_mtx = self.calculate_regulon_enrichment()
  93. if self.auc_thresholds is None:
  94. self.auc_thresholds = self.binarize_regulon_enrichment()
  95. if len(self.embeddings.keys()) == 0:
  96. self.create_loom_default_embedding()
  97. self.regulon_gene_assignment = self.create_loom_regulon_gene_assignment()
  98. self.ngenes = self.calculate_nb_genes_per_cell()
  99. self.clusterings = self.create_loom_clusterings()
  100. self.regulon_thresholds = self.create_loom_md_regulon_thresholds()
  101. self.set_generic_col_attrs()
  102. self.set_generic_row_attrs()
  103. self.set_generic_global_attrs()
  104. self.set_tree()
  105. #######
  106. # I/O #
  107. #######
  108. @staticmethod
  109. def read_loom(filename: str, tag: str = None):
  110. with lp.connect(filename, mode='r', validate=False) as loom:
  111. # Load the content into memory
  112. # Set the main matrix
  113. ex_mtx = pd.DataFrame(loom[:, :], index=loom.ra.Gene, columns=loom.ca.CellID).T
  114. # Set the column, row and global attribute using the underlying Dict of the AttributeManager
  115. col_attrs = {k: v for k, v in loom.ca.items()}
  116. row_attrs = {k: v for k, v in loom.ra.items()}
  117. global_attrs = {k: v for k, v in loom.attrs.items()}
  118. # Decompress and decode the MetaData global attribute
  119. try:
  120. global_attrs["MetaData"] = SCopeLoom.decompress_decode(value=global_attrs["MetaData"])
  121. except Exception:
  122. # MetaData is uncompressed
  123. global_attrs["MetaData"] = json.loads(global_attrs["MetaData"])
  124. scope_loom = SCopeLoom(
  125. filename=filename,
  126. ex_mtx=ex_mtx,
  127. col_attrs=col_attrs,
  128. row_attrs=row_attrs,
  129. global_attrs=global_attrs,
  130. tag=tag
  131. )
  132. if 'embeddings' in scope_loom.get_meta_data():
  133. scope_loom.convert_loom_embeddings_repr_to_internal_repr()
  134. # If multi-runs mode
  135. is_multi_runs_mode = scope_loom.has_scenic_multi_runs_data()
  136. if is_multi_runs_mode:
  137. scope_loom.set_scenic_min_genes_regulon(min_genes_regulon=global_attrs["MetaData"]["regulonSettings"]["min_genes_regulon"])
  138. scope_loom.set_scenic_min_regulon_gene_occurrence(min_regulon_gene_occurrence=global_attrs["MetaData"]["regulonSettings"]["min_regulon_gene_occurrence"])
  139. return scope_loom
  140. #############
  141. # Meta Data #
  142. #############
  143. def add_meta_data(self, _dict):
  144. md = self.global_attrs["MetaData"]
  145. md.update(_dict)
  146. self.global_attrs["MetaData"] = md
  147. def get_meta_data(self):
  148. return self.global_attrs["MetaData"]
  149. def set_tree(self):
  150. assert len(self.tree_structure) <= 3, ""
  151. self.global_attrs.update(("SCopeTreeL{}".format(idx + 1), category) for idx, category in enumerate(list(islice(chain(self.tree_structure, repeat("")), 3))))
  152. #############
  153. # Features #
  154. #############
  155. def get_genes(self):
  156. return self.row_attrs['Gene']
  157. ################
  158. # Observations #
  159. ################
  160. def get_cell_ids(self):
  161. return self.col_attrs['CellID']
  162. ###############
  163. # Annotations #
  164. ###############
  165. def set_cell_annotations(self):
  166. if self.cell_annotations is None:
  167. self.cell_annotations = dict(zip(self.ex_mtx.index.astype(str), ['-'] * self.ex_mtx.shape[0]))
  168. ###########
  169. # Metrics #
  170. ###########
  171. def calculate_nb_genes_per_cell(self):
  172. # Calculate the number of genes per cell.
  173. binary_mtx = self.ex_mtx.copy()
  174. binary_mtx[binary_mtx != 0] = 1.0
  175. return binary_mtx.sum(axis=1).astype(int)
  176. def add_metrics(self, metrics: List[str]):
  177. md_metrics = []
  178. for metric in metrics:
  179. md_metrics.append({"name": metric})
  180. self.global_attrs["MetaData"].update({'metrics': md_metrics})
  181. ##############
  182. # Embeddings #
  183. ##############
  184. @staticmethod
  185. def get_embedding_id(embedding: Embedding, _list):
  186. """ Returns the appropriate index as a string given the _list
  187. Parameters:
  188. None
  189. Returns:
  190. str: Returns -1 if the given embedding is the default, 0 if the given _list is empty and length of the given _list minus 1
  191. """
  192. if embedding.is_default():
  193. return '-1'
  194. elif len(_list) == '0':
  195. return '0'
  196. else:
  197. return str(len(_list) - 1)
  198. def convert_loom_embeddings_repr_to_internal_repr(self):
  199. for embedding in self.get_meta_data()['embeddings']:
  200. self.add_embedding(
  201. embedding=self.get_embedding_by_id(embedding_id=embedding['id']),
  202. embedding_name=embedding['name'],
  203. is_default=True if str(embedding['id']) == '-1' else False
  204. )
  205. def get_embedding_by_id(self, embedding_id):
  206. if str(embedding_id) == '-1':
  207. return self.col_attrs['Embedding']
  208. x = self.col_attrs['Embeddings_X'][str(embedding_id)]
  209. y = self.col_attrs['Embeddings_Y'][str(embedding_id)]
  210. return np.column_stack((x, y))
  211. def has_embedding(self, embedding_name):
  212. return embedding_name in self.embeddings.keys()
  213. def add_embedding(self, embedding: np.ndarray, embedding_name, is_default: bool = False):
  214. df_embedding = pd.DataFrame(embedding, columns=['_X', '_Y'], index=self.ex_mtx.index)
  215. _embedding = Embedding(embedding=df_embedding, embedding_name=embedding_name, is_default=is_default)
  216. if is_default:
  217. self.default_embedding = _embedding
  218. self.embeddings[embedding_name] = _embedding
  219. def create_loom_default_embedding(self):
  220. # Create an embedding based on tSNE.
  221. # Name of columns should be "_X" and "_Y".
  222. self.add_embedding(embedding=TSNE().fit_transform(self.auc_mtx), embedding_name="tSNE (default)", is_default=True)
  223. def create_loom_md_embeddings_repr(self):
  224. """ Returns a Dictionary (Dict) for the global meta data embeddings with preformated data to be stored in Loom file format and compatible with SCope.
  225. Parameters:
  226. None
  227. Returns:
  228. dict: A Dictionary (Dict) for the global meta data embeddings with preformated data to be stored in Loom file format and compatible with SCope.
  229. """
  230. md_embeddings = []
  231. for _, embedding in self.embeddings.items():
  232. if embedding.is_default():
  233. md_embeddings = md_embeddings + [{'id': '-1', 'name': embedding.get_embedding_name()}]
  234. else:
  235. md_embeddings = md_embeddings + [
  236. {
  237. 'id': SCopeLoom.get_embedding_id(embedding=embedding, _list=md_embeddings),
  238. 'name': embedding.get_embedding_name()
  239. }
  240. ]
  241. return {"embeddings": md_embeddings}
  242. def create_loom_ca_embeddings_repr(self):
  243. """ Returns a Dictionary (Dict) for the embeddings with preformated data to be stored in Loom file format and compatible with SCope.
  244. Parameters:
  245. None
  246. Returns:
  247. dict: A Dictionary (Dict) for the embeddings with preformated data to be stored in Loom file format and compatible with SCope.
  248. """
  249. default_embedding = None
  250. embeddings_X = pd.DataFrame(index=self.ex_mtx.index)
  251. embeddings_Y = pd.DataFrame(index=self.ex_mtx.index)
  252. for _, embedding in self.embeddings.items():
  253. if(embedding.get_embedding().shape[1] != 2):
  254. raise Exception('The embedding should have two columns.')
  255. # Set the default embedding
  256. if embedding.is_default():
  257. default_embedding = embedding.get_embedding()
  258. # Update the Embeddings_[X|Y]
  259. embedding_id = str(SCopeLoom.get_embedding_id(embedding, embeddings_X.columns))
  260. embedding = embedding.get_embedding().copy()
  261. embedding.columns = ['_X', '_Y']
  262. embeddings_X = pd.merge(
  263. embeddings_X,
  264. embedding['_X'].to_frame().rename(
  265. columns={'_X': embedding_id}
  266. ).astype('float32'), left_index=True, right_index=True)
  267. embeddings_Y = pd.merge(
  268. embeddings_Y,
  269. embedding['_Y'].to_frame().rename(
  270. columns={'_Y': embedding_id}
  271. ).astype('float32'), left_index=True, right_index=True)
  272. return {
  273. "Embedding": SCopeLoom.df_to_named_matrix(df=default_embedding),
  274. "Embeddings_X": SCopeLoom.df_to_named_matrix(df=embeddings_X),
  275. "Embeddings_Y": SCopeLoom.df_to_named_matrix(df=embeddings_Y)
  276. }
  277. ###############
  278. # Clusterings #
  279. ###############
  280. def create_loom_clusterings(self):
  281. # Encode cell type clusters.
  282. # The name of the column should match the identifier of the clustering.
  283. return pd.DataFrame(
  284. data=self.ex_mtx.index.values,
  285. index=self.ex_mtx.index,
  286. columns=['0']
  287. ).replace(self.cell_annotations).replace(self.name2idx())
  288. ##########
  289. # SCENIC #
  290. ##########
  291. def set_scenic_min_genes_regulon(self, min_genes_regulon):
  292. self.scenic_min_genes_regulon = min_genes_regulon
  293. def set_scenic_min_regulon_gene_occurrence(self, min_regulon_gene_occurrence):
  294. self.scenic_min_regulon_gene_occurrence = min_regulon_gene_occurrence
  295. def set_regulon_filter(self, regulons):
  296. self.regulon_filter = regulons
  297. def has_scenic_multi_runs_data(self):
  298. return (
  299. 'RegulonGeneOccurrences' in self.row_attrs.keys() and 'RegulonGeneWeights' in self.row_attrs.keys()
  300. ) or (
  301. 'MotifRegulonGeneOccurrences' in self.row_attrs.keys() and 'MotifRegulonGeneWeights' in self.row_attrs.keys()
  302. ) or (
  303. 'TrackRegulonGeneOccurrences' in self.row_attrs.keys() and 'TrackRegulonGeneWeights' in self.row_attrs.keys()
  304. )
  305. def scopify_md_regulon_data(self):
  306. # Fix regulon objects to display properly in SCope:
  307. # Rename regulons in the thresholds object, motif
  308. md_regulon_thresholds = self.global_attrs['MetaData']['regulonThresholds']
  309. for _, x in enumerate(md_regulon_thresholds):
  310. tmp = re.sub(r"(_?)\(", '_(', x.get('regulon')) # + '-motif'
  311. x.update({'regulon': tmp})
  312. return {
  313. 'regulonThresholds': md_regulon_thresholds
  314. }
  315. def scopify_loom_ca_regulon_data(self):
  316. regulons_auc_col_attrs = list(filter(lambda col_attrs_key: 'RegulonsAUC' in col_attrs_key, self.col_attrs.keys()))
  317. def fix(col_attrs_key):
  318. regulons = pd.DataFrame(self.col_attrs[col_attrs_key], index=self.col_attrs['CellID'])
  319. # Add underscore for SCope compatibility:
  320. regulons.columns = regulons.columns.str.replace('_?\\(', '_(')
  321. return {
  322. col_attrs_key: SCopeLoom.df_to_named_matrix(regulons)
  323. }
  324. # Update the keys
  325. regulons_auc_col_attrs_update = map(fix, regulons_auc_col_attrs)
  326. # Convert list of dict to dict
  327. return {next(iter(x)): x.get(next(iter(x))) for x in regulons_auc_col_attrs_update}
  328. def scopify_loom_ra_regulon_data(self):
  329. regulons_row_attrs = list(filter(lambda row_attrs_key: 'Regulon' in row_attrs_key, self.row_attrs.keys()))
  330. def fix(row_attrs_key):
  331. regulons = pd.DataFrame(self.row_attrs[row_attrs_key], index=self.row_attrs['Gene'])
  332. # Add underscore for SCope compatibility:
  333. regulons.columns = regulons.columns.str.replace('_?\\(', '_(')
  334. return {
  335. row_attrs_key: SCopeLoom.df_to_named_matrix(regulons)
  336. }
  337. # Update the keys
  338. regulons_row_attrs_update = map(fix, regulons_row_attrs)
  339. # Convert list of dict to dict
  340. return {next(iter(x)): x.get(next(iter(x))) for x in regulons_row_attrs_update}
  341. def calculate_regulon_enrichment(self):
  342. # Calculate regulon enrichment per cell using AUCell.
  343. # Create regulons with weight based on given key
  344. print("Using {} to weight the genes when running AUCell.".format(self.auc_regulon_weights_key))
  345. regulon_signatures = list(map(lambda x: GeneSignature(name=x.name, gene2weight=self.get_regulon_gene_data(x, self.auc_regulon_weights_key)), self.regulons))
  346. auc_mtx = aucell(self.ex_mtx, regulon_signatures, num_workers=self.num_workers) # (n_cells x n_regulons)
  347. auc_mtx = auc_mtx.loc[self.ex_mtx.index]
  348. return auc_mtx
  349. def binarize_regulon_enrichment(self):
  350. _, auc_thresholds = binarize(self.auc_mtx)
  351. return auc_thresholds
  352. @staticmethod
  353. def format_tag(tag):
  354. # return f"{tag[0]}{tag[-1]}"
  355. return tag
  356. def get_regulon_gene_weights(self):
  357. if self.regulon_filter is not None:
  358. return self.row_attrs['RegulonGeneWeights'][self.regulon_filter]
  359. return self.row_attrs["RegulonGeneWeights"]
  360. def get_regulon_gene_occurrences(self):
  361. if self.regulon_filter is not None:
  362. return self.row_attrs['RegulonGeneOccurrences'][self.regulon_filter]
  363. return self.row_attrs["RegulonGeneOccurrences"]
  364. def get_regulons(self):
  365. if self.regulon_filter is not None:
  366. return self.row_attrs['Regulons'][self.regulon_filter]
  367. return self.row_attrs["Regulons"]
  368. def merge_regulon_data(self, scope_loom):
  369. # Check if SCENIC has been run in multi-runs mode
  370. is_multi_runs_mode = self.has_scenic_multi_runs_data() and scope_loom.has_scenic_multi_runs_data()
  371. # RegulonsAUC
  372. # Relabel columns with suffix indicating the regulon source
  373. auc_mtx = pd.DataFrame(data=self.col_attrs['RegulonsAUC'], index=self.col_attrs['CellID'])
  374. auc_mtx.columns = auc_mtx.columns + '-' + SCopeLoom.format_tag(self.tag)
  375. scope_loom_auc_mtx = pd.DataFrame(data=scope_loom.col_attrs['RegulonsAUC'], index=scope_loom.col_attrs['CellID'])
  376. scope_loom_auc_mtx.columns = scope_loom_auc_mtx.columns + '-' + SCopeLoom.format_tag(scope_loom.tag)
  377. # Regulons (regulon assignment matrices)
  378. regulons = pd.DataFrame(self.get_regulons(), index=self.row_attrs['Gene'])
  379. regulons.columns = regulons.columns + '-' + SCopeLoom.format_tag(self.tag)
  380. scope_loom_regulons = pd.DataFrame(scope_loom.get_regulons(), index=scope_loom.row_attrs['Gene'])
  381. scope_loom_regulons.columns = scope_loom_regulons.columns + '-' + SCopeLoom.format_tag(scope_loom.tag)
  382. # If multi-runs SCENIC
  383. # Rename Regulons Gene Occurrences
  384. if is_multi_runs_mode:
  385. regulon_gene_occurrences = pd.DataFrame(self.get_regulon_gene_occurrences(), index=self.row_attrs['Gene'])
  386. regulon_gene_occurrences.columns = regulon_gene_occurrences.columns + '-' + SCopeLoom.format_tag(self.tag)
  387. scope_loom_regulon_gene_occurrences = pd.DataFrame(scope_loom.get_regulon_gene_occurrences(), index=scope_loom.row_attrs['Gene'])
  388. scope_loom_regulon_gene_occurrences.columns = scope_loom_regulon_gene_occurrences.columns + '-' + SCopeLoom.format_tag(scope_loom.tag)
  389. # If multi-runs SCENIC
  390. # Rename Regulons Gene Weights
  391. if is_multi_runs_mode:
  392. regulon_gene_weights = pd.DataFrame(self.get_regulon_gene_weights(), index=self.row_attrs['Gene'])
  393. regulon_gene_weights.columns = regulon_gene_weights.columns + '-' + SCopeLoom.format_tag(self.tag)
  394. scope_loom_regulon_gene_weights = pd.DataFrame(scope_loom.get_regulon_gene_weights(), index=scope_loom.row_attrs['Gene'])
  395. scope_loom_regulon_gene_weights.columns = scope_loom_regulon_gene_weights.columns + '-' + SCopeLoom.format_tag(scope_loom.tag)
  396. # Combine meta data regulons
  397. # Rename regulons in the thresholds object, motif
  398. rt = self.global_attrs["MetaData"]["regulonThresholds"]
  399. for _, x in enumerate(rt):
  400. tmp = x.get('regulon') + '-' + SCopeLoom.format_tag(self.tag)
  401. x.update({'regulon': tmp})
  402. # Rename regulons in the thresholds object, track
  403. scope_loom_rt = scope_loom.global_attrs["MetaData"]["regulonThresholds"]
  404. for _, x in enumerate(scope_loom_rt):
  405. tmp = x.get('regulon') + '-' + SCopeLoom.format_tag(scope_loom.tag)
  406. x.update({'regulon': tmp})
  407. # blank out the "motifData" field for track-based regulons:
  408. x.update({'mofitData': 'NA.png'})
  409. # merge regulon threshold dictionaries:
  410. rt_merged = rt + scope_loom_rt
  411. # Remove because we will save them separately
  412. del self.row_attrs["Regulons"]
  413. del self.col_attrs["RegulonsAUC"]
  414. if is_multi_runs_mode:
  415. del self.row_attrs["RegulonGeneOccurrences"]
  416. del self.row_attrs["RegulonGeneWeights"]
  417. # Update the attributes
  418. self.row_attrs.update({f'{self.tag.capitalize()}Regulons': SCopeLoom.df_to_named_matrix(regulons)})
  419. self.col_attrs.update({f'{self.tag.capitalize()}RegulonsAUC': SCopeLoom.df_to_named_matrix(auc_mtx)})
  420. if is_multi_runs_mode:
  421. self.row_attrs.update({f'{self.tag.capitalize()}RegulonGeneOccurrences': SCopeLoom.df_to_named_matrix(regulon_gene_occurrences)})
  422. self.row_attrs.update({f'{self.tag.capitalize()}RegulonGeneWeights': SCopeLoom.df_to_named_matrix(regulon_gene_weights)})
  423. self.row_attrs.update({f'{scope_loom.tag.capitalize()}Regulons': SCopeLoom.df_to_named_matrix(scope_loom_regulons)})
  424. self.col_attrs.update({f'{scope_loom.tag.capitalize()}RegulonsAUC': SCopeLoom.df_to_named_matrix(scope_loom_auc_mtx)})
  425. if is_multi_runs_mode:
  426. self.row_attrs.update({f'{scope_loom.tag.capitalize()}RegulonGeneOccurrences': SCopeLoom.df_to_named_matrix(scope_loom_regulon_gene_occurrences)})
  427. self.row_attrs.update({f'{scope_loom.tag.capitalize()}RegulonGeneWeights': SCopeLoom.df_to_named_matrix(scope_loom_regulon_gene_weights)})
  428. self.global_attrs["MetaData"].update({'regulonThresholds': rt_merged})
  429. def get_regulon_gene_data(self, regulon, key):
  430. if key == 'gene2occurrence':
  431. return regulon.gene2occurrence
  432. if key == 'gene2weight':
  433. return regulon.gene2weight
  434. raise Exception('Cannot retrieve {} from given regulon. Not implemented.'.format(key))
  435. def get_regulon_meta_data(self, name, threshold):
  436. def fetch_logo(context):
  437. for elem in context:
  438. if elem.endswith('.png'):
  439. return elem
  440. return ""
  441. name2logo = {reg.name: fetch_logo(reg.context) for reg in self.regulons}
  442. regulon = list(filter(lambda x: x.name == name, self.regulons))[0]
  443. regulon_meta_data = {
  444. "regulon": name,
  445. "defaultThresholdValue": (threshold if isinstance(threshold, float) else threshold[0]),
  446. "defaultThresholdName": "guassian_mixture_split",
  447. "allThresholds": {
  448. "guassian_mixture_split": (threshold if isinstance(threshold, float) else threshold[0])
  449. },
  450. "motifData": name2logo.get(name, "")
  451. }
  452. if self.save_additional_regulon_meta_data:
  453. regulon_meta_data.update({
  454. "tf": regulon.transcription_factor,
  455. "score": regulon.score if hasattr(regulon, 'score') else 0.0,
  456. "orthologousIdentity": regulon.orthologous_identity if hasattr(regulon, 'orthologous_identity') else 0.0,
  457. "annotation": regulon.annotation if hasattr(regulon, 'annotation') else '',
  458. "similarityQValue": regulon.score if hasattr(regulon, 'similarity_qvalue') else 0.0
  459. })
  460. return regulon_meta_data
  461. def create_loom_md_regulon_thresholds(self):
  462. return [self.get_regulon_meta_data(name, threshold) for name, threshold in self.auc_thresholds.iteritems()]
  463. def create_loom_regulon_gene_assignment(self):
  464. # Encode genes in regulons as "binary" membership matrix.
  465. genes = np.array(self.ex_mtx.columns)
  466. n_genes = len(genes)
  467. n_regulons = len(self.regulons)
  468. data = np.zeros(shape=(n_genes, n_regulons), dtype=int)
  469. for idx, regulon in enumerate(self.regulons):
  470. data[:, idx] = np.isin(genes, regulon.genes).astype(int)
  471. regulon_gene_assignment = pd.DataFrame(
  472. data=data,
  473. index=self.ex_mtx.columns,
  474. columns=list(map(attrgetter('name'), self.regulons))
  475. )
  476. return regulon_gene_assignment
  477. # Multi-runs SCENIC additional data
  478. def encode_regulon_gene_data(self, key):
  479. genes = np.array(self.ex_mtx.columns)
  480. n_genes = len(genes)
  481. n_regulons = len(self.regulons)
  482. data = np.zeros(shape=(n_genes, n_regulons), dtype=float)
  483. for idx, regulon in enumerate(self.regulons):
  484. regulon_data = pd.DataFrame.from_dict(self.get_regulon_gene_data(regulon, key), orient='index')
  485. data[np.isin(genes, regulon_data.index), idx] = regulon_data[0][genes[np.isin(genes, regulon_data.index)]]
  486. return data
  487. def create_loom_regulon_gene_data(self, key):
  488. return pd.DataFrame(
  489. data=self.encode_regulon_gene_data(key=key),
  490. index=self.ex_mtx.columns,
  491. columns=list(map(attrgetter('name'), self.regulons))
  492. )
  493. def add_row_attr_regulon_gene_weights(self):
  494. regulon_gene_weights = self.create_loom_regulon_gene_data(key='gene2weight')
  495. if 'RegulonGeneWeights' not in self.row_attrs.keys():
  496. print("Added 'RegulonGeneWeights' to the row attributes.")
  497. self.row_attrs['RegulonGeneWeights'] = SCopeLoom.df_to_named_matrix(regulon_gene_weights)
  498. def add_row_attr_regulon_gene_occurrences(self):
  499. regulon_gene_occurrences = self.create_loom_regulon_gene_data(key='gene2occurrence')
  500. if 'RegulonGeneOccurrences' not in self.row_attrs.keys():
  501. print("Added 'RegulonGeneOccurrences' to the row attributes.")
  502. self.row_attrs['RegulonGeneOccurrences'] = SCopeLoom.df_to_named_matrix(regulon_gene_occurrences)
  503. ###########
  504. # Generic #
  505. ###########
  506. def name2idx(self):
  507. return dict(map(reversed, enumerate(sorted(set(self.cell_annotations.values())))))
  508. def set_generic_col_attrs(self):
  509. self.col_attrs = {
  510. "CellID": self.ex_mtx.index.values.astype('str'),
  511. "nGene": self.ngenes.values,
  512. "Embedding": SCopeLoom.df_to_named_matrix(self.default_embedding.get_embedding()),
  513. "RegulonsAUC": SCopeLoom.df_to_named_matrix(self.auc_mtx),
  514. "Clusterings": SCopeLoom.df_to_named_matrix(self.clusterings),
  515. "ClusterID": self.clusterings.values
  516. }
  517. def set_generic_row_attrs(self):
  518. self.row_attrs = {
  519. "Gene": self.ex_mtx.columns.values.astype('str'),
  520. "Regulons": SCopeLoom.df_to_named_matrix(self.regulon_gene_assignment)
  521. }
  522. def set_generic_global_attrs(self):
  523. self.global_attrs = {
  524. "title": os.path.splitext(os.path.basename(self.out_fname))[0] if self.title is None else self.title,
  525. "MetaData": {
  526. "embeddings": [{'id': identifier, 'name': name} for identifier, name in self.id2name.items()],
  527. "annotations": [{
  528. "name": "",
  529. "values": []
  530. }],
  531. "clusterings": [{
  532. "id": 0,
  533. "group": "celltype",
  534. "name": "Cell Type",
  535. "clusters": [{"id": idx, "description": name} for name, idx in self.name2idx().items()]
  536. }],
  537. "regulonThresholds": self.regulon_thresholds
  538. },
  539. "Genome": self.nomenclature
  540. }
  541. def sort(self, axis, by):
  542. if(axis == 0):
  543. if by not in self.row_attrs:
  544. sys.exit(f"ERROR: Cannot sort on a row attribute that does not exist")
  545. sorted_idx = np.argsort(self.row_attrs[by])
  546. for ra_key in self.row_attrs.keys():
  547. self.row_attrs[ra_key] = self.row_attrs[ra_key][sorted_idx]
  548. self.ex_mtx = self.ex_mtx[self.row_attrs[by]]
  549. else:
  550. sys.exit(f"ERROR: Sorting by column axis is not implemented")
  551. def merge(self, loom, overwrite_embeddings=False):
  552. # Check all the cells and genes are in the same order
  553. if not np.array_equal(a1=self.get_cell_ids(), a2=loom.get_cell_ids()):
  554. sys.exit(f"ERROR: Column attribute CellIDs does not match between {os.path.basename(self.filename)} and {os.path.basename(loom.filename)}")
  555. if not np.array_equal(a1=self.get_genes(), a2=loom.get_genes()):
  556. sys.exit(f"ERROR: Row attribute 'Gene' does not match between {os.path.basename(self.filename)} and {os.path.basename(loom.filename)}")
  557. if not np.array_equal(a1=self.get_genes(), a2=self.ex_mtx.columns):
  558. sys.exit(f"ERROR: Row attribute 'Gene' does not match with the features in the matrix of {os.path.basename(self.filename)}.")
  559. if not np.array_equal(a1=loom.get_genes(), a2=loom.ex_mtx.columns):
  560. sys.exit(f"ERROR: Row attribute 'Gene' does not match with the features in the matrix of {os.path.basename(loom.filename)}.")
  561. # Add the embeddings of the given loom (SCopeLoom) to this SCopeLoom
  562. if 'embeddings' in loom.get_meta_data():
  563. print(f"Merging embeddings from {os.path.basename(loom.filename)} into {os.path.basename(self.filename)}...")
  564. for embedding in loom.get_meta_data()['embeddings']:
  565. # Only add the embedding if not present in this loom and overwrite_embeddings is False
  566. if not self.has_embedding(embedding_name=embedding['name']) or overwrite_embeddings:
  567. print(f"Adding {embedding['name']} embedding...")
  568. self.add_embedding(
  569. embedding_name=embedding['name'],
  570. embedding=loom.get_embedding_by_id(embedding_id=embedding['id'])
  571. )
  572. print("Done.")
  573. # Add SCENIC results if present in the given loom
  574. if any('Regulon' in s for s in loom.row_attrs.keys()) and any('Regulon' in s for s in loom.col_attrs.keys()):
  575. print(f"Merging SCENIC results from {os.path.basename(loom.filename)} into {os.path.basename(self.filename)}...")
  576. # Regulon information from row attributes
  577. # All the row attributes containing the substring 'Regulon' within the given SCopeLoom
  578. # will be merged with this SCopeLoom
  579. regulons_row_attrs_keys = list(filter(lambda row_attrs_key: 'Regulon' in row_attrs_key, loom.row_attrs.keys()))
  580. regulons_row_attrs = {
  581. regulons_row_attr_key: loom.row_attrs[regulons_row_attr_key] for regulons_row_attr_key in regulons_row_attrs_keys
  582. }
  583. self.row_attrs.update(regulons_row_attrs)
  584. # Regulon information from column attributes
  585. # All the column attributes containing the substring 'Regulon' within the given SCopeLoom
  586. # will be merged with this SCopeLoom
  587. regulons_auc_col_attrs_keys = list(filter(lambda col_attrs_key: 'Regulon' in col_attrs_key, loom.col_attrs.keys()))
  588. regulons_auc_col_attrs = {
  589. regulons_auc_col_attr_key: loom.col_attrs[regulons_auc_col_attr_key] for regulons_auc_col_attr_key in regulons_auc_col_attrs_keys
  590. }
  591. self.col_attrs.update(regulons_auc_col_attrs)
  592. # regulonThresholds MetaData global attribute
  593. self.global_attrs["MetaData"].update(
  594. {
  595. 'regulonThresholds': loom.get_meta_data()['regulonThresholds']
  596. }
  597. )
  598. print("Done.")
  599. # If multi-runs mode
  600. is_multi_runs_mode = self.has_scenic_multi_runs_data()
  601. if is_multi_runs_mode:
  602. self.set_scenic_min_genes_regulon(min_genes_regulon=loom.scenic_min_genes_regulon)
  603. self.set_scenic_min_regulon_gene_occurrence(min_regulon_gene_occurrence=loom.scenic_min_regulon_gene_occurrence)
  604. def export(self, out_fname: str, save_embeddings: bool = True, compress_meta_data: bool = False):
  605. if out_fname is None:
  606. raise ValueError("The given out_fname cannot be None.")
  607. ##############
  608. # Embeddings #
  609. ##############
  610. if save_embeddings:
  611. self.col_attrs.update(self.create_loom_ca_embeddings_repr())
  612. self.global_attrs["MetaData"].update(self.create_loom_md_embeddings_repr())
  613. ##########
  614. # SCENIC #
  615. ##########
  616. is_multi_runs_mode = self.has_scenic_multi_runs_data()
  617. if is_multi_runs_mode:
  618. if "regulonSettings" not in self.global_attrs["MetaData"].keys():
  619. self.add_meta_data(_dict={
  620. "regulonSettings": {
  621. "min_genes_regulon": self.scenic_min_genes_regulon,
  622. "min_regulon_gene_occurrence": self.scenic_min_regulon_gene_occurrence
  623. }
  624. })
  625. if any('Regulon' in s for s in self.row_attrs.keys()):
  626. self.row_attrs.update(self.scopify_loom_ra_regulon_data())
  627. if any('RegulonsAUC' in s for s in self.col_attrs.keys()):
  628. self.col_attrs.update(self.scopify_loom_ca_regulon_data())
  629. if 'regulonThresholds' in self.global_attrs["MetaData"].keys():
  630. self.global_attrs["MetaData"].update(self.scopify_md_regulon_data())
  631. # Compress MetaData global attribute
  632. # (Should be compressed if Loompy version 2)
  633. self.global_attrs["MetaData"] = json.dumps(self.global_attrs["MetaData"])
  634. if compress_meta_data:
  635. self.global_attrs["MetaData"] = SCopeLoom.compress_encode(value=self.global_attrs["MetaData"])
  636. # Create loom file for use with the SCope tool.
  637. # The loom file format opted for rows as genes to facilitate growth along the column axis (i.e add more cells)
  638. # PySCENIC chose a different orientation because of limitation set by the feather format: selectively reading
  639. # information from disk can only be achieved via column selection. For the ranking databases this is of utmost
  640. # importance.
  641. lp.create(
  642. filename=out_fname,
  643. layers=self.ex_mtx.T.values,
  644. row_attrs=self.row_attrs,
  645. col_attrs=self.col_attrs,
  646. file_attrs=self.global_attrs
  647. )
  648. #########
  649. # Utils #
  650. #########
  651. @staticmethod
  652. def df_to_named_matrix(df: pd.DataFrame):
  653. # Create meta-data structure.
  654. # Create a numpy structured array
  655. return np.array([tuple(row) for row in df.values],
  656. dtype=np.dtype(list(zip(df.columns, df.dtypes))))
  657. @staticmethod
  658. def compress_encode(value):
  659. '''
  660. Compress using ZLIB algorithm and encode the given value in base64.
  661. Taken from: https://github.com/aertslab/SCopeLoomPy/blob/5438da52c4bcf48f483a1cf378b1eaa788adefcb/src/scopeloompy/utils/__init__.py#L7
  662. '''
  663. return base64.b64encode(zlib.compress(value.encode('ascii'))).decode('ascii')
  664. @staticmethod
  665. def decompress_decode(value):
  666. try:
  667. value = value.decode('ascii')
  668. return json.loads(zlib.decompress(base64.b64decode(value)))
  669. except AttributeError:
  670. return json.loads(zlib.decompress(base64.b64decode(value.encode('ascii'))).decode('ascii'))

export_to_loom.py at commit 58c1304, no license · at the source

Overview

Authors: Pablo Largo-Barrientos1,2, Roman Praschberger1,2,3, Gonzalo León-Espinosa4, Pieter-Jan Bultynck1,2, Anastasia Mallopoulou1,2, João F. Machado1,2, Suresh Poovathingal1,2, Kristofer Davie1,2, Patrik Verstreken1,2
  1. VIB-KU Leuven Center for Neuroscience; Leuven, Belgium
  2. KU Leuven, Department of Neurosciences, Leuven Brain Institute, Mission Lucidity; Leuven, Belgium
  3. Medical University of Innsbruck, Institute of Human Genetics; Innsbruck, Austria
  4. Universidad San Pablo-Centro de Estudios Universitarios, Facultad de Farmacia, Departamento de Química y Bioquímica; Madrid, Spain
Journal: Science advances, volume 12, issue 45, article eaeg3486
Dates: received 11 February 2026; accepted 23 September 2026; published online 4 November 2026; in print November 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI · PMCID PMC13733825
Status: code verified (how the code is found and verified)
Categories: Alzheimer's / dementia (population), cellular / molecular (subfield)
Methods: Statistics, Smoothing, state filtering, decompositions, Connectivity
Journal subjects: Neuroscience, Cellular Neuroscience
Funding: Chan Zuckerberg Initiative (Collaborative Paris Pilot Project Award 2024-338504); Rainwater Charitable Foundation (Taupathy Challenge Workshop 522894); European Research Council (Advanced Grant 101054310); Fonds Wetenschappelijk Onderzoek (Research Foundation Flanders) (Postdoctoral Fellowship 1242225N, Research Project G045724N)
Citations: not cited yet (Europe PMC); 56 references in the paper

Abstract

Hibernation demands rapid brain adaptations, involving cycles of reduced metabolic rate during torpor, followed by brief periods of arousal. Previous studies show hibernation induces a drastic increase in Tau hyperphosphorylation, but a mechanistic connection to disease remains unclear. Using single-nucleus RNA sequencing on hippocampi of golden hamsters, we unveil large transcriptional shifts across the hibernation cycle in all cell types, especially glia. Common transcriptional changes in mitochondrial and ribosomal genes are observed in all different cell types. In addition, hibernation triggers an inflammatory-like response in microglia that in part resembles cell states observed in Alzheimer’s disease, but here in the absence of Aβ-accumulation and neurodegeneration. These findings reveal brain transformations that might help preserve vital functions under extreme conditions and they suggest that early cellular changes in AD may be a natural adaptive process.

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

Repositories

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

aertslab/create_cisTarget_databases

License: none: the authors keep all their rights
State: the link answers, verified on 2 November 2026
Evidence: files inventoried
Commit: 304d5dc1b15e5c923908a50a1ec291c3faaccf9c, 18 June 2025
Languages: Python (27), Shell (1)
Size: 30 files, 28 scripts
Software Heritage: not archived
Found in: the text, “Transcriptional network analysis (SCENIC)”
Holds: README, environment (pyproject.toml)
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (8 files), pandas (6 files), BEDTools (1 file), Numba (1 file)
Availability: 2 checks, the latest on 2 November 2026: the link answers
  • 2 November 2026: the link answers
  • 28 September 2026: the link answers
29 files

Zenodo 5751297

License: other-open
State: the link answers, verified on 7 November 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: the text, “Transcriptional network analysis (SCENIC)”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (36 files), Scanpy (35 files), pandas (28 files), Matplotlib (10 files), SciPy (5 files), seaborn (4 files), ggplot2 (2 files), scikit-learn (2 files), Seurat (2 files), SingleCellExperiment (2 files), anndata (1 file), Harmony (1 file), NetworkX (1 file), reticulate (1 file), SAMtools (1 file), tidyverse (1 file), UMAP (1 file)
Availability: 1 check, the latest on 7 November 2026: the link answers (HTTP 200)
  • 7 November 2026: the link answers (HTTP 200)
72 files

vib-singlecell-nf/scenic

License: none: the authors keep all their rights
State: the link answers, verified on 7 November 2026
Evidence: files inventoried
Commit: 58c130428e9c5a82dde06d6c2576f26f8fe27ecc, 8 December 2020
Languages: Python (10), Jupyter (1)
Size: 52 files, 11 scripts
Software Heritage: archived
Found in: the text, “Transcriptional network analysis (SCENIC)”
Holds: README, 1 notebook
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (10 files), NumPy (6 files), Matplotlib (1 file), NetworkX (1 file), Scanpy (1 file), scikit-learn (1 file), seaborn (1 file), UMAP (1 file)
Availability: 1 check, the latest on 7 November 2026: the link answers
  • 7 November 2026: the link answers
12 files

vib-singlecell-nf/vsn-pipelines

License: GPL-3.0
State: the link answers, verified on 7 November 2026
Evidence: files inventoried
Commit: 65056919560a4c82ff560c9499c199d138c8b6c7, 19 April 2023
Languages: Python (46), Jupyter (12), R (11), Shell (1)
Size: 601 files, 70 scripts
Software Heritage: archived
Found in: the Zenodo archive record
Holds: README, license file, environment (conf/singularity.config, src/archr/Dockerfile, src/bap/Dockerfile, src/bwamaptools/Dockerfile, src/celda/Dockerfile, src/celda/environment.yml, src/cellranger-atac/Dockerfile, src/cellranger/Dockerfile, src/directs/Dockerfile, src/dropletutils/Dockerfile, src/fastp/Dockerfile, src/flybaser/Dockerfile), continuous integration, documentation, 12 notebooks
Not found: CITATION.cff, tests
Tools: NumPy (36 files), Scanpy (35 files), pandas (28 files), Matplotlib (10 files), SciPy (5 files), seaborn (4 files), ggplot2 (2 files), scikit-learn (2 files), Seurat (2 files), SingleCellExperiment (2 files), anndata (1 file), Harmony (1 file), NetworkX (1 file), reticulate (1 file), SAMtools (1 file), tidyverse (1 file), UMAP (1 file)
Availability: 2 checks, the latest on 7 November 2026: the link answers
  • 7 November 2026: the link answers
  • 2 October 2026: the link answers
72 files

The paper's code and data availability statement is in the Data section.

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:

  • 4 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 179 scripts, each with its path and the digest of its content;
  • 5 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, code, and materials availability

Single-cell data is available at https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE304024. The code used in this study is described in the Materials and Methods. This study did not generate new materials.

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, 7 November 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 4 funders, 53 references.

Cite

This paper

Largo-Barrientos, P., Praschberger, R., León-Espinosa, G., Bultynck, P.-J., Mallopoulou, A., Machado, J. F., Poovathingal, S., Davie, K., & Verstreken, P. (2026). Common transcriptional changes in the brain during hibernation and Alzheimer’s disease. Science advances, 12(45), eaeg3486.

BibTeX

@article{largobarrientos2026common,
author = {Largo-Barrientos, Pablo and Praschberger, Roman and León-Espinosa, Gonzalo and Bultynck, Pieter-Jan and Mallopoulou, Anastasia and Machado, João F. and Poovathingal, Suresh and Davie, Kristofer and Verstreken, Patrik},
title = {{Common transcriptional changes in the brain during hibernation and Alzheimer’s disease}},
journal = {Science advances},
year = {2026},
month = nov,
volume = {12},
number = {45},
pages = {eaeg3486},
publisher = {American Association for the Advancement of Science},
issn = {2375-2548},
pmcid = {PMC13733825}
}

RIS

TY - JOUR
AU - Largo-Barrientos, Pablo
AU - Praschberger, Roman
AU - León-Espinosa, Gonzalo
AU - Bultynck, Pieter-Jan
AU - Mallopoulou, Anastasia
AU - Machado, João F.
AU - Poovathingal, Suresh
AU - Davie, Kristofer
AU - Verstreken, Patrik
TI - Common transcriptional changes in the brain during hibernation and Alzheimer’s disease
T2 - Science advances
J2 - Sci Adv
PY - 2026
DA - 2026/11/06
VL - 12
IS - 45
SP - eaeg3486
SN - 2375-2548
PB - American Association for the Advancement of Science
LA - en
ER -

CSL-JSON

{
"id": "pmcid:PMC13733825",
"type": "article-journal",
"title": "Common transcriptional changes in the brain during hibernation and Alzheimer’s disease",
"container-title": "Science advances",
"author": [
{
"family": "Largo-Barrientos",
"given": "Pablo"
},
{
"family": "Praschberger",
"given": "Roman"
},
{
"family": "León-Espinosa",
"given": "Gonzalo"
},
{
"family": "Bultynck",
"given": "Pieter-Jan"
},
{
"family": "Mallopoulou",
"given": "Anastasia"
},
{
"family": "Machado",
"given": "João F."
},
{
"family": "Poovathingal",
"given": "Suresh"
},
{
"family": "Davie",
"given": "Kristofer"
},
{
"family": "Verstreken",
"given": "Patrik"
}
],
"container-title-short": "Sci Adv",
"volume": "12",
"issue": "45",
"page": "eaeg3486",
"PMCID": "PMC13733825",
"ISSN": "2375-2548",
"publisher": "American Association for the Advancement of Science",
"language": "en",
"issued": {
"date-parts": [
[
2026,
11,
6
]
]
}
}

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.7554/elife.98348 [code]
Synaptic deregulation of cholinergic projection neurons causes olfactory dysfunction across five fly Parkinsonism models.
Journal: eLife
In common: Harmony, reticulate, SingleCellExperiment, 14 other tools, cellular / molecular, 3 references, 3 authors
[2] doi:10.1038/s41593-025-02075-1 [code]
C9orf72 hexanucleotide repeat expansions impair microglial response in ALS.
Journal: Nature neuroscience
In common: Harmony, reticulate, SingleCellExperiment, 14 other tools, cellular / molecular, 5 references, author Kristofer Davie
[3] doi:10.1038/s41593-023-01549-4 [code]
Single-cell transcriptomics reveals that glial cells integrate homeostatic and circadian processes to drive sleep-wake cycles.
Journal: Nature neuroscience
In common: Harmony, reticulate, SingleCellExperiment, 14 other tools, cellular / molecular, 2 references, author Kristofer Davie
[4] doi:10.1016/j.cell.2025.06.031 [code]
Single-cell multiregion epigenomic rewiring in Alzheimer's disease progression and cognitive resilience.
Journal: Cell
In common: Harmony, reticulate, BEDTools, 15 other tools, Alzheimer's / dementia, cellular / molecular, 5 references
[5] doi:10.1038/s41592-023-01938-4 [code]
SCENIC+: single-cell multiomic inference of enhancers and gene regulatory networks.
Journal: Nature methods
In common: Harmony, BEDTools, anndata, 13 other tools, cellular / molecular, 4 references, author Suresh Poovathingal
[6] doi:10.1038/s41586-026-10629-x [code]
Whole-genome duplication shaped cell-type evolution in the vertebrate brain.
Journal: Nature
In common: Harmony, reticulate, BEDTools, 14 other tools, cellular / molecular, 4 references
[7] doi:10.1038/s41593-025-02022-0 [code]
An integrated single-nucleus and spatial transcriptomics atlas reveals the molecular landscape of the human hippocampus.
Journal: Nature neuroscience
In common: Harmony, reticulate, SingleCellExperiment, 12 other tools, 5 references
[8] doi:10.1016/j.xgen.2025.101007 [code]
Single-nucleus transcriptome atlas of orbitofrontal cortex in ALS with a deep learning-based decoding of alternative polyadenylation mechanisms.
Journal: Cell genomics
In common: Harmony, reticulate, BEDTools, 11 other tools, Alzheimer's / dementia, cellular / molecular, 6 references
[9] doi:10.1016/j.neuron.2023.02.033 [code]
Neuronal identity defines α-synuclein and tau toxicity.
Journal: Neuron
In common: tidyverse, Alzheimer's / dementia, cellular / molecular, 10 references, 2 authors
[10] doi:10.1038/s41591-024-03150-z [code]
A brain cell atlas integrating single-cell transcriptomes across human brain regions.
Journal: Nature medicine
In common: reticulate, anndata, Scanpy, 10 other tools, 8 references

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.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/repo/github.com/aertslab/create_cistarget_databases.svg)](https://openscicode.org/badge/repo/github.com/aertslab/create_cistarget_databases)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/repo/github.com/aertslab/create_cistarget_databases.svg
   :target: https://openscicode.org/badge/repo/github.com/aertslab/create_cistarget_databases
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/repo/github.com/aertslab/create_cistarget_databases"><img src="https://openscicode.org/badge/repo/github.com/aertslab/create_cistarget_databases.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge 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: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.

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