OSCR

Endocytic turnover of endothelial cell-membrane proteins as a driver of rat blood-brain barrier specialization and dysfunction.

Code ↔ Paper

2 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 2 matches
  1. [1] § STAR★Methods › Method details › Non-parametric ETOR profile analysis ↔ bin/DP_GP_cluster.py, lines 48–64 · score 0.83 · Dirichlet Process Gaussian, dp gp cluster, sampling iterations, Gibbs sampling, Neal, Posterior
  2. [2] § STAR★Methods › Method details › Non-parametric ETOR profile analysis ↔ bin/DP_GP_cluster.py, lines 42–64 · score 0.83 · Dirichlet Process Gaussian, dp gp cluster, sampling iterations, Gibbs sampling, Neal, Posterior

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 · 705 lines · 30 KB · BSD-3-Clause · 1 match

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. ##############################################################################
  4. #
  5. # DP_GP_cluster.py
  6. #
  7. # Authors: Ian McDowell, Dinesh Manandhar
  8. # Last Updated: 09/14/2016
  9. #
  10. # Requires the following Python packages:
  11. # GPy (> 0.8), pandas, numpy, scipy (>= 0.14), matplotlib.pyplot
  12. #
  13. ##############################################################################
  14. #
  15. # Import dependencies
  16. #
  17. ##############################################################################
  18. # import matplotlib
  19. # matplotlib.use('Agg')
  20. # font = {'size' : 8}
  21. # matplotlib.rc('font', **font)
  22. import matplotlib.pyplot as plt
  23. from DP_GP import plot
  24. from DP_GP import utils
  25. from DP_GP import core
  26. from DP_GP import cluster_tools
  27. import pandas as pd
  28. import numpy as np
  29. import numpy.linalg as nl
  30. import scipy
  31. import GPy
  32. # import standard library dependencies:
  33. import collections
  34. import time
  35. import copy
  36. import argparse
  37. import os
  38. ##############################################################################
  39. #
  40. # Description of script
  41. #
  42. ##############################################################################
  43. parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, \
  44. description="""
  45. DP_GP_cluster.py takes a gene expression matrix as input and runs Gibbs
  46. Sampling through a Dirichlet process Gaussian process model according to Neal's
  47. algorithm 8 (DOI:10.1080/10618600.2000.10474879).
  48. The script returns the sampled clusterings, optimal clustering, and a
  49. posterior similarity matrix that can be used for downstream
  50. analyses like clustering, plotting and distance matrix creation.
  51. The script can also plot expression in clusters over time along with
  52. the Gaussian Process parameters of each cluster, size of clusters over
  53. sampling iterations, and the posterior similarity matrix in the form
  54. of a heatmap with dendrogram.
  55. """)
  56. ##############################################################################
  57. #
  58. # Required arguments
  59. #
  60. ##############################################################################
  61. parser.add_argument("-i", "--input", nargs='+', dest="gene_expression_matrix", action="store", \
  62. help="""required, e.g. /path/to/gene_expression_matrix.txt
  63. or /path/to/gene_expression_matrix.rep1.txt /path/to/gene_expression_matrix.rep2.txt etc.
  64. if there are replicates.
  65. where the format of the gene_expression_matrix.txt is:
  66. gene 1 2 3 ... time_t
  67. gene_1 10 20 5 ... 8
  68. gene_2 3 2 50 ... 8
  69. gene_3 18 100 10 ... 22
  70. ...
  71. gene_n 45 22 15 ... 60
  72. Note that the first row is a header containing the
  73. time points and the first column is an index
  74. containing all gene names. Entries are delimited
  75. by whitespace (space or tab), and for this reason,
  76. do not include spaces in gene names or time point names.
  77. """)
  78. parser.add_argument("-o", "--output", dest="output_path_prefix", action="store", \
  79. help="""required, e.g. /path/to/my_gene_clustering_results
  80. Output files automatically generated (note suffices added):
  81. Posterior similarity matrix (frequency of gene-by-gene cluster
  82. co-occurrence during Gibbs Sampling):
  83. /path/to/my_gene_clustering_results_posterior_similarity_matrix.txt
  84. Cluster assignment over Gibbs Sampling iterations (after burn-in and thinning):
  85. /path/to/my_gene_clustering_results_clusterings.txt
  86. Log likelihoods of sampled clusterings (after burn-in and thinning):
  87. /path/to/my_gene_clustering_results_log_likelihoods.txt
  88. tab-delimited file listing (col 1) optimal cluster number (col 2) gene name
  89. /path/to/output_path_prefix_optimal_clustering.txt
  90. Output files optionally generated (if --plot; note suffices added):
  91. Heatmap of posterior similarity matrix, to which complete-linkage hierarchical clustering
  92. has been applied for the purposes of attractiveness and intelligibility:
  93. /path/to/my_gene_clustering_results_posterior_similarity_matrix_heatmap.{pdf/png/svg}
  94. Key to ordering of genes in heatmap of posterior similarity matrix:
  95. /path/to/my_gene_clustering_results_posterior_similarity_matrix_heatmap_key.txt
  96. Cluster assignment over Gibbs Sampling iterations (after burn-in and thinning):
  97. /path/to/my_gene_clustering_results_posterior_similarity_matrix_heatmap.{pdf/png/svg}
  98. Cluster sizes over course of Gibbs Sampling (including burn-in phase I):
  99. /path/to/my_gene_clustering_results_cluster_sizes.{pdf/png/svg}
  100. Plot of gene expression over the time-course, for all optimal clusters
  101. with six panels/clusters per figure:
  102. /path/to/output_path_prefix_gene_expression_fig_1.{pdf/png/svg}
  103. .
  104. .
  105. .
  106. /path/to/output_path_prefix_gene_expression_fig_N.{pdf/png/svg}
  107. """)
  108. ##############################################################################
  109. #
  110. # Optional sampling arguments
  111. #
  112. ##############################################################################
  113. parser.add_argument("-n", "--max_num_iters", dest="max_num_iterations", type=int, default=1000, \
  114. help="""optional, [default=1000]
  115. Maximum number of Gibbs sampling iterations.
  116. """)
  117. parser.add_argument("-s", "--thinning_param", dest="s", type=int, default=3, \
  118. help="""optional, [default=3]
  119. Take every sth sample during Gibbs iterations to ensure independence between
  120. samples.
  121. """)
  122. parser.add_argument("--optimizer", dest="optimizer", type=str, default='lbfgsb', \
  123. help="""optional, [default=lbfgsb]
  124. Specify the optimization technique used to update GP hyperparameters
  125. lbfgsb = L-BFGS-B
  126. fmin_tnc = truncated Newton algorithm
  127. simplex = Nelder-Mead simplex
  128. scg = stochastic conjugate gradient
  129. """)
  130. parser.add_argument("--max_iters", dest="max_iters", type=int, default=1000, \
  131. help="""optional, [default=1000]
  132. Maximum number of optimization iterations.
  133. """)
  134. parser.add_argument("-a", "--alpha", dest="alpha", type=float, default=1., \
  135. help="""optional, [default=1.0]
  136. alpha, or the concentration parameter, determines how likely it is that
  137. a new cluster is chosen at a given iteration of the Chinese restaurant process,
  138. where a higher value for alpha will tend to produce more clusters.
  139. """)
  140. parser.add_argument("-m", "--num_empty_clusters", dest="m", type=int, default=4, \
  141. help="""optional, [default=4]
  142. Number of empty clusters available at each iteration, or new "tables"
  143. in terms of the Chinese restaurant process.
  144. """)
  145. parser.add_argument("--fast", action='store_true', \
  146. help="""optional, run in fast mode for very large datasets.
  147. Cannot be run with large datasets.
  148. """)
  149. parser.add_argument("--check_convergence", action='store_true', \
  150. help="""optional, [default=do not check for convergence but run until max iterations]
  151. If --check_convergence, then check for convergence, else run until max iterations.
  152. """)
  153. parser.add_argument("--check_burnin_convergence", action='store_true', \
  154. help="""optional, [default=do not check for burn-in convergence but
  155. run burn-in until predetermined number of iterations]
  156. """)
  157. parser.add_argument("--sparse_regression", action='store_true', \
  158. help="""optional, may be useful to run sparse regression
  159. for large data sets.
  160. """)
  161. parser.add_argument("-c", "--criterion", dest="criterion", type=str, default='MAP', \
  162. help="""optional, [default=MAP]
  163. Specify the criterion by which you would like to select the optimal clustering
  164. among "MAP", "MPEAR", "least_squares", "h_clust_avg", and "h_clust_comp" where:
  165. MAP = maximum a posteriori
  166. MPEAR = Posterior expected adjusted Rand (see Fritsch and Ickstadt 2009, DOI:10.1214/09-BA414)
  167. least_squares = minimize squared distance between clustering and posterior similarity matrix
  168. (see Dahl 2006, "Model-Based Clustering...")
  169. h_clust_avg = hierarchical clustering by average linkage
  170. h_clust_comp = hierarchical clustering by complete linkage
  171. Or, you may cluster genes post-hoc according to a criterion not implemented here
  172. using the "_posterior_similarity_matrix.txt" or "_clusterings.txt" file.
  173. """)
  174. ##############################################################################
  175. #
  176. # Optional input transformation arguments
  177. #
  178. ##############################################################################
  179. parser.add_argument("--true_times", action='store_true', dest="true_times", \
  180. help="""optional, [default=False]
  181. Set this flag if the header contains true time values (e.g. 0, 0.5, 4, 8,...)
  182. and it is desired that the covariance kernel recognizes the true
  183. time spacing between sampling points, which need not be constant.
  184. Otherwise, it is assumed that the sampling times are equally spaced,
  185. or in other words, that the rate of change in expression is roughly equivalent
  186. between all neighboring time points.
  187. """)
  188. parser.add_argument("--unscaled", action='store_true', dest="unscaled", \
  189. help="""optional, [default=False]
  190. Set this flag if you desire the gene expression data to be clustered
  191. without scaling (do not divide by standard deviation).
  192. """)
  193. parser.add_argument("--do_not_mean_center", action='store_true', dest="do_not_mean_center", \
  194. help="""optional, [default=False]
  195. Set this flag if you desire the gene expression data to be clustered
  196. without mean-centering (do not subtract mean).
  197. """)
  198. ##############################################################################
  199. #
  200. # Optional hyperprior arguments
  201. #
  202. ##############################################################################
  203. parser.add_argument("--sigma_n2_shape", dest="sigma_n2_shape", type=float, default=12.,
  204. help="""optional, [default=12 or estimated from replicates]
  205. sigma_n2_shape is shape parameter for the inverse gamma prior on the cluster noise variance.
  206. """)
  207. parser.add_argument("--sigma_n2_rate", dest="sigma_n2_rate", type=float, default=2.,
  208. help="""optional, [default=2 or estimated from replicates]
  209. sigma_n2_rate is rate parameter for the inverse gamma prior on the cluster noise variance.
  210. """)
  211. parser.add_argument("--length_scale_mu", dest="length_scale_mu", type=float, default=0.,
  212. help="""optional, Log normal mean (mu, according to Bishop 2006 conventions)
  213. for length scale [default=0]
  214. """)
  215. parser.add_argument("--length_scale_sigma", dest="length_scale_sigma", type=float, default=1.,
  216. help="""optional, Log normal standard deviation (sigma, according to Bishop 2006 convention)
  217. for length scale [default=1]
  218. """)
  219. parser.add_argument("--sigma_f_mu", dest="sigma_f_mu", type=float, default=0.,
  220. help="""optional, Log normal mean (mu, according to Bishop 2006 convention)
  221. for signal variance [default=0]
  222. """)
  223. parser.add_argument("--sigma_f_sigma", dest="sigma_f_sigma", type=float, default=1.,
  224. help="""optional, Log normal standard deviation (sigma, according to Bishop 2006 conventions)
  225. for signal variance [default=1]
  226. """)
  227. ##############################################################################
  228. #
  229. # Optional output arguments
  230. #
  231. ##############################################################################
  232. parser.add_argument("--plot", action='store_true', \
  233. help="""optional, [default=False] Do not plot anything. if --plot indicated, then plot.
  234. """)
  235. parser.add_argument("-p", "--plot_types", nargs='+', dest="plot_types", type=str, default='pdf', \
  236. help="""optional, [default=pdf] plot type, e.g. pdf.
  237. If multiple plot types are desired then separate by commas, e.g. pdf,png
  238. and, for each generated plot, one plot of each specified kind will be generated.
  239. """)
  240. parser.add_argument("-t", "--time_unit", dest="time_unit", type=str, default='', \
  241. help="""optional, [default=None] time unit, used solely for plotting purposes.
  242. """)
  243. parser.add_argument("--save_cluster_GPs", action='store_true', \
  244. help="""optional, [default=False] if --save_cluster_GPs indicated, then save tab-separated file
  245. of optimal cluster GP parameters.
  246. """)
  247. parser.add_argument("--save_residuals", action='store_true', \
  248. help="""optional, [default=False] if --save_residuals indicated, then save tab-separated file
  249. of residuals for each gene at each time point using cluster-specific parameters.
  250. """)
  251. parser.add_argument("--do_not_plot_sim_mat", action='store_true', \
  252. help="""optional, [default=False] if --do_not_plot_sim_mat indicated, then
  253. similarity matrix heatmap is not plotted.
  254. """)
  255. parser.add_argument("--cluster_uncertainty_estimate", action='store_true', \
  256. help="""optional, [default=False] if --cluster_uncertainty_estimate indicated, then
  257. estimate the probability, for each gene, that assigned cluster is true.
  258. """)
  259. ##############################################################################
  260. #
  261. # Optional post-processing arguments
  262. #
  263. ##############################################################################
  264. parser.add_argument("--post_process", action='store_true', \
  265. help="""optional, [default=False] Sampling already completed, now post-process
  266. by choosing optimal clustering and plotting expression.
  267. """)
  268. parser.add_argument("--sim_mat", dest="sim_mat", action="store", default=None, \
  269. help="""optional, e.g. /path/to/similarity_matrix.txt
  270. If DP_GP_cluster.py has already been run, user can
  271. choose to use similarity matrix to return an optimal
  272. clustering according to one of the following criteria:
  273. h_clust_avg, h_clust_comp, least_squares.
  274. The format of the similarity_matrix.txt is:
  275. gene_0 gene_1 gene_2 gene_n
  276. gene_0 1.0 0.89 0.12 ... 0.0
  277. gene_1 0.89 1.0 0.2 ... 0.01
  278. gene_2 0.12 0.2 1.0 ... 0.7
  279. ... ... ... ... ... ...
  280. gene_n 0.0 0.01 0.7 ... 1.0
  281. Note that the first row is a header and the first
  282. column is an index, both of which contains an identical
  283. list of genes. In each cell, S[i,j], is the fraction of
  284. samples that gene_i was in the same cluster as gene_j.
  285. Thus, all entries are in the unit interval [0,1].
  286. Entries are delimited by whitespace (space or tab),
  287. and for this reason, do not include spaces in gene names.
  288. """)
  289. parser.add_argument("--clusterings", dest="clusterings", action="store", default=None, \
  290. help="""optional, e.g. /path/to/clusterings.txt
  291. If DP_GP_cluster.py has already been run, user can
  292. choose to use clusterings to return an optimal
  293. clustering according to one of the following criteria:
  294. MPEAR, MAP (with log_likelihoods.txt), least_squares.
  295. The format of the clusterings.txt is:
  296. gene_0 gene_1 gene_2 gene_n
  297. 1 1 2 ... 33
  298. 10 10 2 ... 33
  299. 13 13 13 ... 33
  300. ... ... ... ... ...
  301. 49 17 17 ... 100
  302. Note that the first row is a header that lists all genes.
  303. Each row is a different sample from the posterior distribution
  304. of clusterings. Integer values denote cluster membership.
  305. Cluster numbers need not correspond across rows/samples, and
  306. only necessarily apply within row/sample.
  307. """)
  308. parser.add_argument("--log_likelihoods", dest="log_likelihoods", action="store", default=None, \
  309. help="""optional, e.g. /path/to/log_likelihoods.txt
  310. If DP_GP_cluster.py has already been run, user can
  311. choose to use log likelihoods to return an optimal
  312. clustering according to MAP (with clusterings.txt).
  313. where the format of the log_likelihoods.txt is:
  314. -10200.322
  315. -9987.452
  316. -12291.992
  317. ...
  318. -10002.403
  319. Each row corresponds to the posterior log-likelihood and also
  320. corresponds to each row in clusterings.txt.
  321. """)
  322. parser.add_argument('--version', action='version', version='DP_GP_cluster.py v.0.1')
  323. #############################################################################################
  324. #
  325. # Parse and check arguments
  326. #
  327. #############################################################################################
  328. args = parser.parse_args()
  329. #if one of the required args is not given, print help message
  330. if (args.gene_expression_matrix is None) | (args.output_path_prefix is None):
  331. parser.print_help()
  332. exit()
  333. if args.criterion not in ["MAP", "MPEAR", "least_squares", "h_clust_avg", "h_clust_comp"]:
  334. raise ValueError("""incorrect criterion. Please choose from among the following options:
  335. MPEAR, MAP, least_squares, h_clust_avg, h_clust_comp""")
  336. #############################################################################################
  337. #
  338. # Parse args for script's usage for post-processing.
  339. # Used after sampling has been completed.
  340. #
  341. #############################################################################################
  342. if args.post_process:
  343. print("Reading sampling results.")
  344. if args.criterion == 'MPEAR' or args.criterion == 'least_squares':
  345. if not args.clusterings or not args.sim_mat:
  346. print("ERROR: if criterion = MPEAR or least_squares, must provide both clusterings and similarity_matrix")
  347. exit()
  348. elif args.criterion == 'MAP':
  349. if not args.clusterings or not args.log_likelihoods:
  350. print("ERROR: if criterion = MAP, must provide both clusterings and log_likelihoods")
  351. exit()
  352. elif args.criterion == 'h_clust_avg' or args.criterion == 'h_clust_comp':
  353. if not args.sim_mat:
  354. print("ERROR: if criterion = h_clust_avg or h_clust_comp, must provide similarity_matrix")
  355. exit()
  356. if args.clusterings:
  357. sampled_clusterings = pd.read_csv(args.clusterings, delim_whitespace=True)
  358. gene_names = list(sampled_clusterings.columns)
  359. if args.sim_mat:
  360. sim_mat = pd.read_csv(args.sim_mat, delim_whitespace=True, index_col=0)
  361. gene_names = list(sim_mat.columns)
  362. sim_mat = np.array(sim_mat)
  363. if args.log_likelihoods:
  364. with open(args.log_likelihoods, 'r') as f:
  365. log_likelihoods = [float(line.strip()) for line in f]
  366. # set random seed to make random calls reproducible
  367. np.random.seed(1234)
  368. #############################################################################################
  369. #
  370. # Import gene expression (and estimate noise variance from data if replicates available)
  371. #
  372. #############################################################################################
  373. gene_expression_matrix, gene_names, t, t_labels = \
  374. core.read_gene_expression_matrices(args.gene_expression_matrix,
  375. args.true_times,
  376. args.unscaled,
  377. args.do_not_mean_center)
  378. # take median of inverse gamma distribution to yield point
  379. # estimate of sigma_n
  380. sigma_n2_shape, sigma_n2_rate = args.sigma_n2_shape, args.sigma_n2_rate
  381. sigma_n = np.sqrt(1 / ((sigma_n2_shape + 1) * sigma_n2_rate))
  382. # scale t such that the mean time interval between sampling points is one unit
  383. # this ensures that initial parameters for length-scale and signal variance are reasonable
  384. t /= np.mean(np.diff(t))
  385. #############################################################################################
  386. #
  387. # Define global variables, which are potentially modifiable parameters
  388. #
  389. #############################################################################################
  390. # first phase of burn-in, expression trajectories cluster under initial length-scale and sigma_n parameters.
  391. burnIn_phaseI = int(np.floor(args.max_num_iterations/5) * 1.2)
  392. # second phase of burn-in, clusters optimize their hyperparameters.
  393. burnIn_phaseII = burnIn_phaseI * 2
  394. # after burnIn_phaseII, samples are taken from the posterior
  395. # epsilon for similarity matrix squared distance convergence
  396. # and epsilon for posterior log likelihood convergence
  397. # only used if --check_convergence
  398. sq_dist_eps, post_eps = 0.01, 1e-5
  399. #############################################################################################
  400. #
  401. # Run Gibbs Sampler
  402. #
  403. #############################################################################################
  404. if not args.post_process:
  405. print("Begin sampling")
  406. GS = core.gibbs_sampler(gene_expression_matrix,t, args.max_num_iterations, args.max_iters, \
  407. args.optimizer, burnIn_phaseI, burnIn_phaseII, args.alpha, args.m, \
  408. args.s, args.check_convergence, args.check_burnin_convergence, args.sparse_regression, args.fast, \
  409. sigma_n, sigma_n2_shape, sigma_n2_rate, \
  410. args.length_scale_mu, args.length_scale_sigma, args.sigma_f_mu, \
  411. args.sigma_f_sigma, sq_dist_eps, post_eps)
  412. sim_mat, all_clusterings, sampled_clusterings, log_likelihoods, iter_num = GS.sampler()
  413. sampled_clusterings.columns = gene_names
  414. all_clusterings.columns = gene_names
  415. else:
  416. iter_num = 0
  417. #############################################################################################
  418. #
  419. # Find optimal clustering
  420. #
  421. ##############################################################################################
  422. # Find an optimal "clusters" list, sorted by gene in order of "gene_names" object
  423. if args.criterion == 'MPEAR':
  424. optimal_clusters = cluster_tools.best_clustering_by_mpear(np.array(sampled_clusterings), sim_mat)
  425. elif args.criterion == 'MAP':
  426. optimal_clusters = cluster_tools.best_clustering_by_log_likelihood(np.array(sampled_clusterings), log_likelihoods)
  427. elif args.criterion == 'least_squares':
  428. optimal_clusters = cluster_tools.best_clustering_by_sq_dist(np.array(sampled_clusterings), sim_mat)
  429. elif args.criterion == 'h_clust_avg':
  430. optimal_clusters = cluster_tools.best_clustering_by_h_clust(sim_mat, 'average')
  431. elif args.criterion == 'h_clust_comp':
  432. optimal_clusters = cluster_tools.best_clustering_by_h_clust(sim_mat, 'complete')
  433. # Given an optimal clustering, optimize the hyperparameters once again
  434. # because (1) hyperparameters are re-written at every iteration and (2) the particular clustering
  435. # may never have actually occurred during sampling, as may happen for h_clust_avg/h_clust_comp.
  436. optimal_cluster_labels = collections.defaultdict(list)
  437. optimal_cluster_labels_original_gene_names = collections.defaultdict(list)
  438. for gene, (gene_name, cluster) in enumerate(zip(gene_names, optimal_clusters)):
  439. optimal_cluster_labels[cluster].append(gene)
  440. optimal_cluster_labels_original_gene_names[cluster].append(gene_name)
  441. if args.cluster_uncertainty_estimate:
  442. gene_to_prob = {}
  443. for gene_i_k, (gene_name, cluster) in enumerate(zip(gene_names, optimal_clusters)):
  444. genes_in_cluster = set(optimal_cluster_labels[cluster])
  445. genes_j_k = genes_in_cluster - set([gene_i_k])
  446. if len(genes_j_k) > 0:
  447. gene_to_prob[gene_name] = sum([sim_mat[gene_i_k,gene_j_k] for gene_j_k in genes_j_k])/len(genes_j_k)
  448. else:
  449. gene_to_prob[gene_name] = 1.
  450. if args.cluster_uncertainty_estimate:
  451. print("Estimating cluster probability for each gene, loop:", end=' ')
  452. uncertainty_converged,last_gene_to_prob,prob_eps_cutoff,c,c_max=False,False,1e-8,0,200
  453. while uncertainty_converged == False:
  454. print(c, end=' ')
  455. gene_to_prob = {}
  456. for gene_i_k, (gene_name, cluster) in enumerate(zip(gene_names, optimal_clusters)):
  457. genes_in_cluster = set(optimal_cluster_labels[cluster])
  458. genes_j_k = genes_in_cluster - set([gene_i_k])
  459. if len(genes_j_k) > 0:
  460. if last_gene_to_prob is False:
  461. # first loop through iterative process estimates the
  462. # probability that gene belongs to cluster by taking
  463. # the mean proportion of times gene co-clusters
  464. # with every other gene in cluster
  465. denominator = len(genes_j_k)
  466. gene_to_prob[gene_i_k] = sum([sim_mat[gene_i_k,gene_j_k] for gene_j_k in genes_j_k])/denominator
  467. else:
  468. # in subsequent loops, genes are weighted by how
  469. # likely they are to belong to a cluster. In this way,
  470. # the likelihood that a gene i belongs to cluster k
  471. # depends less on a gene j that is unlikely to belong to cluster k
  472. # and depends more on gene l that is likely to belong to cluster k
  473. denominator = sum([last_gene_to_prob[gene_j_k] for gene_j_k in genes_j_k])
  474. gene_to_prob[gene_i_k] = sum([sim_mat[gene_i_k,gene_j_k] * last_gene_to_prob[gene_j_k] for gene_j_k in genes_j_k])/denominator
  475. else:
  476. gene_to_prob[gene_i_k] = 1.
  477. if last_gene_to_prob is not False:
  478. # find overall sum in absolute change in probability estimates
  479. prob_eps = sum([np.abs(gene_to_prob[g] - last_gene_to_prob[g]) for g in sorted(gene_to_prob)])
  480. # check for convergence
  481. if prob_eps < prob_eps_cutoff:
  482. print("converged")
  483. for gene_i_k, gene_name in enumerate(gene_names):
  484. gene_to_prob[gene_name] = gene_to_prob[gene_i_k]
  485. del gene_to_prob[gene_i_k]
  486. break
  487. last_gene_to_prob = gene_to_prob.copy()
  488. c+=1
  489. if c > c_max:
  490. print("WARNING: iterative cluster_uncertainty_estimate did not converge")
  491. for gene_i_k, gene_name in enumerate(zip(gene_names)):
  492. gene_to_prob[gene_name] = "NA"
  493. break
  494. if args.save_residuals:
  495. name_d = {gene:gene_name for gene, gene_name in enumerate(gene_names)}
  496. residuals_by_gene = {}
  497. optimal_clusters_GP = {}
  498. print("Optimizing parameters for optimal clusters.")
  499. for cluster, genes in optimal_cluster_labels.items():
  500. print("Cluster %s, %s genes"%(cluster, len(genes)))
  501. optimal_clusters_GP[cluster] = core.dp_cluster(members=genes,
  502. sigma_n=sigma_n,
  503. X=np.vstack(t),
  504. Y=np.array(np.mat(gene_expression_matrix[genes,:])).T,
  505. iter_num_at_birth=iter_num)
  506. optimal_clusters_GP[cluster] = optimal_clusters_GP[cluster].update_cluster_attributes(gene_expression_matrix,
  507. sigma_n2_shape,
  508. sigma_n2_rate,
  509. args.length_scale_mu,
  510. args.length_scale_sigma,
  511. args.sigma_f_mu,
  512. args.sigma_f_sigma,
  513. iter_num,
  514. args.max_iters,
  515. args.optimizer)
  516. if args.save_residuals:
  517. for gene in genes:
  518. resids = ( gene_expression_matrix[gene,:] - optimal_clusters_GP[cluster].mean )**2
  519. residuals_by_gene[name_d[gene]] = resids
  520. if args.save_residuals:
  521. residuals_df = pd.DataFrame(np.array([residuals_by_gene[gene_name] for gene_name in gene_names]))
  522. residuals_df.columns = t_labels
  523. residuals_df.index = gene_names
  524. residuals_df.to_csv(args.output_path_prefix + "_residuals.txt", sep='\t', index=True, header=True)
  525. #############################################################################################
  526. #
  527. # Report
  528. #
  529. ##############################################################################################
  530. if not args.post_process:
  531. print("Saving sampling results.")
  532. core.save_posterior_similarity_matrix(sim_mat, gene_names, args.output_path_prefix)
  533. core.save_clusterings(sampled_clusterings, args.output_path_prefix)
  534. core.save_log_likelihoods(log_likelihoods, args.output_path_prefix)
  535. if not args.cluster_uncertainty_estimate:
  536. cluster_tools.save_cluster_membership_information(optimal_cluster_labels_original_gene_names,
  537. args.output_path_prefix + "_optimal_clustering.txt")
  538. else:
  539. cluster_tools.save_cluster_membership_information(optimal_cluster_labels_original_gene_names,
  540. args.output_path_prefix + "_optimal_clustering.txt",
  541. gene_to_prob)
  542. #############################################################################################
  543. #
  544. # Plot
  545. #
  546. ##############################################################################################
  547. if args.plot:
  548. print("Plotting expression and sampling results.")
  549. plot_types = args.plot_types
  550. if not args.post_process or args.sim_mat and not args.do_not_plot_sim_mat:
  551. try:
  552. sim_mat_key = plot.plot_similarity_matrix(sim_mat, args.output_path_prefix, plot_types)
  553. except RuntimeError:
  554. print("WARNING: skipping heatmap plot generation, too many dendrogram recursions for scipy to handle")
  555. if not args.post_process:
  556. core.save_posterior_similarity_matrix_key([gene_names[idx] for idx in sim_mat_key], args.output_path_prefix)
  557. plot.plot_cluster_sizes_over_iterations(np.array(all_clusterings), burnIn_phaseI, burnIn_phaseII, args.m, args.output_path_prefix, plot_types)
  558. plot.plot_cluster_gene_expression(optimal_clusters_GP,
  559. pd.DataFrame(gene_expression_matrix, index=gene_names, columns=t),
  560. t,
  561. t_labels,
  562. args.time_unit,
  563. args.output_path_prefix,
  564. plot_types,
  565. args.unscaled,
  566. args.do_not_mean_center)
  567. #############################################################################################
  568. #
  569. # Save clusters
  570. #
  571. ##############################################################################################
  572. if args.save_cluster_GPs:
  573. param_df = pd.DataFrame({name:dp_cluster.model.param_array for name, dp_cluster in optimal_clusters_GP.items()})
  574. param_df.index = dp_cluster.model.parameter_names()
  575. param_df.to_csv(args.output_path_prefix + "_cluster_model_params.txt", sep='\t', index=True, header=True)

DP_GP_cluster.py at commit a9c856d, under BSD-3-Clause · at the source

Overview

Authors: Alba Tomás-Sitjes1,2, Gianluca Arauz-Garofalo2, Marina Gay2, Sònia Jarió2, Marta Vilaseca2, Valentina Schastlivaia1, Maaike Kessen1,3, Nicola Manicardi1, Giuseppe Battaglia1,4, Daniel Gonzalez-Carter1
  1. Institute for Bioengineering of Catalonia (IBEC), Barcelona Institute of Science and Technology (BIST), Barcelona, Spain
  2. Institute for Research in Biomedicine (IRB Barcelona), Barcelona Institute of Science and Technology (BIST), Barcelona, Spain
  3. Faculty of Science and Engineering, Maastricht University, Maastricht, the Netherlands
  4. Catalan Institution for Research and Advanced Studies (ICREA), Barcelona, Spain
Journal: iScience, volume 29, issue 6, article 116231
Dates: received 3 December 2025; accepted 19 May 2026; published online 5 June 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1016/j.isci.2026.116231 · PMID 42291236 · PMCID PMC13264249 · OpenAlex W7163707475
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), rat (organism), cellular / molecular (subfield)
Methods: Statistics, Smoothing, state filtering, decompositions
Keywords: Cellular physiology, Proteomics
Topic: Barrier Structure and Function Studies (Neurology, Neuroscience), according to OpenAlex
Funding: State Agency of Research (RYC2022-036623-I); European Regional Development Fund (IU16-015983)
Citations: not cited yet (Europe PMC); 30 references in the paper

Abstract

The blood-brain barrier (BBB), formed primarily by specialized brain endothelial cells (BEC), is essential for nutrient transport, signal transduction, immune cell migration, and pathogen restriction. Although these functions are influenced by the identity and abundance of cell-membrane proteins, the role of protein endocytic turnover rate (ETOR, the dynamics of protein internalization, recycling, and degradation) governing BBB physiology remains poorly understood. Using in vitro proteomics, we analyzed ETOR across approximately 1,000 proteins in rat endothelial cells under healthy and pathological conditions to investigate BBB specialization and dysfunction. We found that BEC display a distinct ETOR profile that differentiates them from peripheral endothelial cells beyond membrane protein composition. Inflammatory conditions shifted the BEC ETOR profile towards a peripheral phenotype. Moreover, inflammation-induced abundance changes highlighted immune-response proteins, whereas ETOR alterations identified proteins associated with vascular remodeling. These findings establish ETOR as a dynamic regulator of BBB specialization and inflammatory dysfunction.

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 2 matches between paragraphs and lines of code.

Molecular-Bionics-Labs/DP_GP_cluster_proteomics

License: BSD-3-Clause
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: a9c856d1b8d7ec187c14e0e0882c71cc6cee2176, 12 June 2026
Languages: Python (8), Shell (3), Jupyter (2)
Size: 50 files, 13 scripts
Software Heritage: not archived
Found in: “Data and code availability”
Holds: README, license file, environment (requirements.txt, setup.py), continuous integration, documentation, 2 notebooks
Not found: CITATION.cff, tests
Tools: NumPy (7 files), Matplotlib (6 files), pandas (6 files), SciPy (6 files), scikit-learn (2 files), seaborn (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
15 files

PrincetonUniversity/DP_GP_cluster

License: BSD-3-Clause
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: eec12e74219f916aa86e253783905f7b5e30f6f4, 22 September 2017
Languages: Python (7), C (2)
Size: 37 files, 9 scripts
Software Heritage: not archived
Found in: the text, “Non-parametric ETOR profile analysis”
Holds: README, license file, environment (requirements.txt, setup.py), continuous integration, documentation
Not found: CITATION.cff, tests
Tools: NumPy (4 files), Matplotlib (3 files), SciPy (3 files), pandas (2 files), scikit-learn (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
11 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:

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

No dataset and no data link were found in the paper.

Data and code availability

Data: All mass spectrometry proteomics data are available through the ProteomeXchange Consortium via PRIDE partner repository with the dataset identifier PXD067112 (https://www.ebi.ac.uk/pride/archive/projects/https://www.ebi.ac.uk/pride/PXD067112). All data reported in this paper will be shared by the lead contact upon request.

Code: Code developed for non-parametric analysis accessed through https://github.com/Molecular-Bionics-Labs/DP_GP_cluster_proteomics.

Other items: Any additional information required to reanalyze the data reported in this paper is available from the lead contact upon request.

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 2, 28 September 2026

  • Authors: added Daniel Gonzalez-Carter (0000-0003-4249-7062); removed Daniel Gonzalez-Carter

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 10 authors, 2 keywords, 2 funders, 30 references.

Cite

This paper

Tomás-Sitjes, A., Arauz-Garofalo, G., Gay, M., Jarió, S., Vilaseca, M., Schastlivaia, V., Kessen, M., Manicardi, N., Battaglia, G., & Gonzalez-Carter, D. (2026). Endocytic turnover of endothelial cell-membrane proteins as a driver of rat blood-brain barrier specialization and dysfunction. iScience, 29(6), 116231. https://doi.org/10.1016/j.isci.2026.116231

BibTeX

@article{tomassitjes2026endocytic,
author = {Tomás-Sitjes, Alba and Arauz-Garofalo, Gianluca and Gay, Marina and Jarió, Sònia and Vilaseca, Marta and Schastlivaia, Valentina and Kessen, Maaike and Manicardi, Nicola and Battaglia, Giuseppe and Gonzalez-Carter, Daniel},
title = {{Endocytic turnover of endothelial cell-membrane proteins as a driver of rat blood-brain barrier specialization and dysfunction}},
journal = {iScience},
year = {2026},
month = jun,
volume = {29},
number = {6},
pages = {116231},
publisher = {Elsevier},
issn = {2589-0042},
doi = {10.1016/j.isci.2026.116231},
url = {https://doi.org/10.1016/j.isci.2026.116231},
pmid = {42291236},
pmcid = {PMC13264249}
}

RIS

TY - JOUR
AU - Tomás-Sitjes, Alba
AU - Arauz-Garofalo, Gianluca
AU - Gay, Marina
AU - Jarió, Sònia
AU - Vilaseca, Marta
AU - Schastlivaia, Valentina
AU - Kessen, Maaike
AU - Manicardi, Nicola
AU - Battaglia, Giuseppe
AU - Gonzalez-Carter, Daniel
TI - Endocytic turnover of endothelial cell-membrane proteins as a driver of rat blood-brain barrier specialization and dysfunction
T2 - iScience
J2 - iScience
PY - 2026
DA - 2026/06/05
VL - 29
IS - 6
SP - 116231
SN - 2589-0042
PB - Elsevier
DO - 10.1016/j.isci.2026.116231
UR - https://doi.org/10.1016/j.isci.2026.116231
LA - en
ER -

CSL-JSON

{
"id": "10.1016/j.isci.2026.116231",
"type": "article-journal",
"title": "Endocytic turnover of endothelial cell-membrane proteins as a driver of rat blood-brain barrier specialization and dysfunction",
"container-title": "iScience",
"author": [
{
"family": "Tomás-Sitjes",
"given": "Alba"
},
{
"family": "Arauz-Garofalo",
"given": "Gianluca"
},
{
"family": "Gay",
"given": "Marina"
},
{
"family": "Jarió",
"given": "Sònia"
},
{
"family": "Vilaseca",
"given": "Marta"
},
{
"family": "Schastlivaia",
"given": "Valentina"
},
{
"family": "Kessen",
"given": "Maaike"
},
{
"family": "Manicardi",
"given": "Nicola"
},
{
"family": "Battaglia",
"given": "Giuseppe"
},
{
"family": "Gonzalez-Carter",
"given": "Daniel"
}
],
"container-title-short": "iScience",
"volume": "29",
"issue": "6",
"page": "116231",
"DOI": "10.1016/j.isci.2026.116231",
"PMID": "42291236",
"PMCID": "PMC13264249",
"ISSN": "2589-0042",
"publisher": "Elsevier",
"URL": "https://doi.org/10.1016/j.isci.2026.116231",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
5
]
]
}
}

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.1038/s41467-026-71418-8 [code]
Deep visual proteomics uncovers nociceptor diversity and pain targets.
Journal: Nature communications
In common: scikit-learn, pandas, SciPy, 2 other tools, genetics / omics, cellular / molecular, 2 references
[2] doi:10.1016/j.mcpro.2026.101604 [code]
Optimizing NGN2 Dosage Enhances the Neuronal Enrichment of iPSC-Derived Neuronal Cultures.
Journal: Molecular & cellular proteomics : MCP
In common: seaborn, scikit-learn, pandas, 3 other tools, genetics / omics, cellular / molecular, 1 reference
[3] doi:10.1186/s12974-026-03890-4 [code]
Neuronal toll-like receptor-4 regulation of matrix metalloproteinase-9 activity mediates dentate circuit dysfunction after traumatic brain injury.
Journal: Journal of neuroinflammation
In common: seaborn, scikit-learn, pandas, 3 other tools, rat, cellular / molecular
[4] doi:10.1007/s12021-026-09814-0 [code]
Application of Machine Learning Models to Identify Differences in Neural Electrophysiological Properties Across Estrous Cycle Phases.
Journal: Neuroinformatics
In common: seaborn, scikit-learn, pandas, 3 other tools, rat
[5] doi:10.1038/s41467-026-76939-w [code]
HIPPIE: a generative model for electrophysiological analysis across species, technologies, and modalities.
Journal: Nature communications
In common: seaborn, scikit-learn, pandas, 3 other tools, rat
[6] doi:10.3389/fnins.2026.1873417 [code]
Functional brain network alterations in a rat model of dental malocclusion.
Journal: Frontiers in neuroscience
In common: seaborn, scikit-learn, pandas, 3 other tools, rat
[7] doi:10.1016/j.isci.2026.116119 [code]
Distinctly structured social behavior across three rodent strains is associated with different neural activity patterns.
Journal: iScience
In common: seaborn, scikit-learn, pandas, 3 other tools, rat
[8] doi:10.1371/journal.pcbi.1013488 [code]
Evaluating place cell detection methods in Rats and Humans: Implications for cross-species spatial coding.
Journal: PLoS computational biology
In common: seaborn, scikit-learn, pandas, 3 other tools, rat
[9] doi:10.1038/s41467-026-71887-x [code]
Magnetic resonance identification tags for ultra-flexible electrodes.
Journal: Nature communications
In common: seaborn, scikit-learn, pandas, 3 other tools, rat
[10] doi:10.1038/s41467-026-73796-5 [code]
Cross-species transcriptomic analysis of rodent model fidelity to human mesial temporal lobe epilepsy.
Journal: Nature communications
In common: seaborn, pandas, SciPy, 2 other tools, rat, genetics / omics, cellular / molecular

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.