OSCR

FABP7 controls radial glial scaffold stability during human cortical development.

Code ↔ Paper

1 match 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 1 match
  1. [1] § Results › FABP7 Regulates Cortical Lineage Balance and Transcriptional Programs Underlying Scaffold and Stress Responses. ↔ R/Seurat-function.R, lines 540–581 · score 0.56 · Uniform Manifold Approximation, UMAP, signatures, cell

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

R · 1,857 lines · 83 KB · GPL-3.0 · 1 match

  1. #' Run NMF (non-negative matrix factorization)
  2. #'
  3. #' @param object An object. This can be a Seurat object, an Assay object, or a matrix-like object.
  4. #' @param assay A character string specifying the assay to be used for the analysis. Default is NULL.
  5. #' @param slot A character string specifying the slot name to be used for the analysis. Default is "data".
  6. #' @param features A character vector specifying the features to be used for the analysis. Default is NULL, which uses all variable features.
  7. #' @param nbes An integer specifying the number of basis vectors (components) to be computed. Default is 50.
  8. #' @param nmf.method A character string specifying the NMF algorithm to be used. Currently supported values are "RcppML" and "NMF". Default is "RcppML".
  9. #' @param tol A numeric value specifying the tolerance for convergence (only applicable when nmf.method is "RcppML"). Default is 1e-5.
  10. #' @param maxit An integer specifying the maximum number of iterations for convergence (only applicable when nmf.method is "RcppML"). Default is 100.
  11. #' @param rev.nmf A logical value indicating whether to perform reverse NMF (i.e., transpose the input matrix) before running the analysis. Default is FALSE.
  12. #' @param ndims.print An integer vector specifying the dimensions (number of basis vectors) to print in the output. Default is 1:5.
  13. #' @param nfeatures.print An integer specifying the number of features to print in the output. Default is 30.
  14. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "nmf".
  15. #' @param reduction.key A character string specifying the prefix for the column names of the basis vectors. Default is "BE_".
  16. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  17. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  18. #' @param ... Additional arguments passed to RcppML::\link[RcppML]{nmf} or NMF::\link[NMF]{nmf} function.
  19. #'
  20. #' @examples
  21. #' pancreas_sub <- RunNMF(object = pancreas_sub)
  22. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "nmf")
  23. #'
  24. #' @rdname RunNMF
  25. #' @export
  26. #'
  27. RunNMF <- function(object, ...) {
  28. UseMethod(generic = "RunNMF", object = object)
  29. }
  30. #' @rdname RunNMF
  31. #' @method RunNMF Seurat
  32. #' @importFrom Seurat LogSeuratCommand VariableFeatures DefaultAssay GetAssay
  33. #' @export
  34. RunNMF.Seurat <- function(object, assay = NULL, slot = "data", features = NULL, nbes = 50,
  35. nmf.method = "RcppML", tol = 1e-5, maxit = 100, rev.nmf = FALSE,
  36. ndims.print = 1:5, nfeatures.print = 30,
  37. reduction.name = "nmf", reduction.key = "BE_",
  38. verbose = TRUE, seed.use = 11, ...) {
  39. features <- features %||% VariableFeatures(object = object)
  40. assay <- assay %||% DefaultAssay(object = object)
  41. assay.data <- GetAssay(object = object, assay = assay)
  42. reduction.data <- RunNMF(
  43. object = assay.data,
  44. assay = assay,
  45. slot = slot,
  46. features = features,
  47. nbes = nbes,
  48. nmf.method = nmf.method,
  49. tol = tol,
  50. maxit = maxit,
  51. rev.nmf = rev.nmf,
  52. verbose = verbose,
  53. ndims.print = ndims.print,
  54. nfeatures.print = nfeatures.print,
  55. reduction.key = reduction.key,
  56. seed.use = seed.use,
  57. ...
  58. )
  59. object[[reduction.name]] <- reduction.data
  60. object <- LogSeuratCommand(object = object)
  61. return(object)
  62. }
  63. #' @rdname RunNMF
  64. #' @method RunNMF Assay
  65. #' @importFrom stats var
  66. #' @importFrom Seurat VariableFeatures GetAssayData
  67. #' @export
  68. RunNMF.Assay <- function(object, assay = NULL, slot = "data", features = NULL, nbes = 50,
  69. nmf.method = "RcppML", tol = 1e-5, maxit = 100, rev.nmf = FALSE,
  70. ndims.print = 1:5, nfeatures.print = 30,
  71. reduction.key = "BE_", verbose = TRUE, seed.use = 11,
  72. ...) {
  73. features <- features %||% VariableFeatures(object = object)
  74. data.use <- GetAssayData(object = object, slot = slot)
  75. features.var <- apply(
  76. X = data.use[features, ], MARGIN = 1,
  77. FUN = var
  78. )
  79. features.keep <- features[features.var > 0]
  80. data.use <- data.use[features.keep, ]
  81. reduction.data <- RunNMF(
  82. object = data.use,
  83. assay = assay,
  84. slot = slot,
  85. nbes = nbes,
  86. nmf.method = nmf.method,
  87. tol = tol,
  88. maxit = maxit,
  89. rev.nmf = rev.nmf,
  90. verbose = verbose,
  91. ndims.print = ndims.print,
  92. nfeatures.print = nfeatures.print,
  93. reduction.key = reduction.key,
  94. seed.use = seed.use,
  95. ...
  96. )
  97. return(reduction.data)
  98. }
  99. #' @rdname RunNMF
  100. #' @method RunNMF default
  101. #' @importFrom utils capture.output
  102. #' @importFrom Matrix t
  103. #' @importFrom Seurat CreateDimReducObject
  104. #' @export
  105. RunNMF.default <- function(object, assay = NULL, slot = "data", nbes = 50,
  106. nmf.method = "RcppML", tol = 1e-5, maxit = 100, rev.nmf = FALSE,
  107. ndims.print = 1:5, nfeatures.print = 30,
  108. reduction.key = "BE_", verbose = TRUE, seed.use = 11, ...) {
  109. if (!is.null(x = seed.use)) {
  110. set.seed(seed = seed.use)
  111. }
  112. if (rev.nmf) {
  113. object <- t(object)
  114. }
  115. nbes <- min(nbes, nrow(x = object) - 1)
  116. if (nmf.method == "RcppML") {
  117. check_R("zdebruine/RcppML")
  118. options("RcppML.verbose" = FALSE)
  119. options("RcppML.threads" = 0)
  120. if (!"package:Matrix" %in% search()) {
  121. attachNamespace("Matrix")
  122. }
  123. nmf.results <- RcppML::nmf(
  124. t(object),
  125. k = nbes, tol = tol, maxit = maxit,
  126. verbose = verbose, ...
  127. )
  128. cell.embeddings <- nmf.results$w
  129. feature.loadings <- t(nmf.results$h)
  130. }
  131. if (nmf.method == "NMF") {
  132. check_R("NMF")
  133. seed <- NMF::seed
  134. nmf.results <- NMF::nmf(x = as_matrix(t(object)), rank = nbes)
  135. cell.embeddings <- nmf.results@fit@W
  136. feature.loadings <- t(nmf.results@fit@H)
  137. }
  138. rownames(x = feature.loadings) <- rownames(x = object)
  139. colnames(x = feature.loadings) <- paste0(reduction.key, 1:nbes)
  140. rownames(x = cell.embeddings) <- colnames(x = object)
  141. colnames(x = cell.embeddings) <- colnames(x = feature.loadings)
  142. reduction.data <- CreateDimReducObject(
  143. embeddings = cell.embeddings,
  144. loadings = feature.loadings,
  145. assay = assay,
  146. key = reduction.key,
  147. misc = list(slot = slot, nmf.results = nmf.results)
  148. )
  149. if (verbose) {
  150. msg <- capture.output(print(
  151. x = reduction.data,
  152. dims = ndims.print,
  153. nfeatures = nfeatures.print
  154. ))
  155. message(paste(msg, collapse = "\n"))
  156. }
  157. return(reduction.data)
  158. }
  159. #' Run MDS (multi-dimensional scaling)
  160. #'
  161. #' @param object An object. This can be a Seurat object, an assay object, or a matrix-like object.
  162. #' @param assay A character string specifying the assay to be used for the analysis. Default is NULL.
  163. #' @param slot A character string specifying the slot name to be used for the analysis. Default is "data".
  164. #' @param features A character vector specifying the features to be used for the analysis. Default is NULL, which uses all variable features.
  165. #' @param nmds An integer specifying the number of dimensions to be computed. Default is 50.
  166. #' @param dist.method A character string specifying the distance metric to be used. Currently supported values are "euclidean", "chisquared","kullback", "jeffreys", "jensen", "manhattan", "maximum", "canberra", "minkowski", and "hamming". Default is "euclidean".
  167. #' @param mds.method A character string specifying the MDS algorithm to be used. Currently supported values are "cmdscale", "isoMDS", and "sammon". Default is "cmdscale".
  168. #' @param rev.mds A logical value indicating whether to perform reverse MDS (i.e., transpose the input matrix) before running the analysis. Default is FALSE.
  169. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "mds".
  170. #' @param reduction.key A character string specifying the prefix for the column names of the basis vectors. Default is "MDS_".
  171. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  172. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  173. #' @param ... Additional arguments to be passed to the stats::\link[stats]{cmdscale}, MASS::\link[MASS]{isoMDS} or MASS::\link[MASS]{sammon} function.
  174. #'
  175. #' @examples
  176. #' pancreas_sub <- RunMDS(object = pancreas_sub)
  177. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "mds")
  178. #'
  179. #' @rdname RunMDS
  180. #' @export
  181. #'
  182. RunMDS <- function(object, ...) {
  183. UseMethod(generic = "RunMDS", object = object)
  184. }
  185. #' @rdname RunMDS
  186. #' @method RunMDS Seurat
  187. #' @importFrom Seurat LogSeuratCommand VariableFeatures DefaultAssay GetAssay
  188. #' @export
  189. RunMDS.Seurat <- function(object, assay = NULL, slot = "data",
  190. features = NULL, nmds = 50, dist.method = "euclidean", mds.method = "cmdscale",
  191. rev.mds = FALSE,
  192. reduction.name = "mds", reduction.key = "MDS_",
  193. verbose = TRUE, seed.use = 11, ...) {
  194. features <- features %||% VariableFeatures(object = object)
  195. assay <- assay %||% DefaultAssay(object = object)
  196. assay.data <- GetAssay(object = object, assay = assay)
  197. reduction.data <- RunMDS(
  198. object = assay.data,
  199. assay = assay,
  200. slot = slot,
  201. features = features,
  202. nmds = nmds,
  203. dist.method = dist.method,
  204. mds.method = mds.method,
  205. rev.mds = rev.mds,
  206. verbose = verbose,
  207. reduction.key = reduction.key,
  208. seed.use = seed.use,
  209. ...
  210. )
  211. object[[reduction.name]] <- reduction.data
  212. object <- LogSeuratCommand(object = object)
  213. return(object)
  214. }
  215. #' @rdname RunMDS
  216. #' @method RunMDS Assay
  217. #' @importFrom stats var
  218. #' @importFrom Seurat VariableFeatures GetAssayData
  219. #' @export
  220. RunMDS.Assay <- function(object, assay = NULL, slot = "data",
  221. features = NULL, nmds = 50, dist.method = "euclidean", mds.method = "cmdscale",
  222. rev.mds = FALSE,
  223. reduction.key = "MDS_", verbose = TRUE, seed.use = 11, ...) {
  224. features <- features %||% VariableFeatures(object = object)
  225. data.use <- GetAssayData(object = object, slot = slot)
  226. features.var <- apply(
  227. X = data.use[features, ], MARGIN = 1,
  228. FUN = var
  229. )
  230. features.keep <- features[features.var > 0]
  231. data.use <- data.use[features.keep, ]
  232. reduction.data <- RunMDS(
  233. object = data.use,
  234. assay = assay,
  235. slot = slot,
  236. nmds = nmds,
  237. dist.method = dist.method,
  238. mds.method = mds.method,
  239. rev.mds = rev.mds,
  240. verbose = verbose,
  241. reduction.key = reduction.key,
  242. seed.use = seed.use,
  243. ...
  244. )
  245. return(reduction.data)
  246. }
  247. #' @rdname RunMDS
  248. #' @method RunMDS default
  249. #' @importFrom proxyC dist
  250. #' @importFrom utils capture.output
  251. #' @importFrom Matrix t
  252. #' @importFrom stats cmdscale as.dist
  253. #' @importFrom Seurat CreateDimReducObject
  254. #' @export
  255. RunMDS.default <- function(object, assay = NULL, slot = "data",
  256. nmds = 50, dist.method = "euclidean", mds.method = "cmdscale",
  257. rev.mds = FALSE,
  258. reduction.key = "MDS_", verbose = TRUE, seed.use = 11, ...) {
  259. if (!is.null(x = seed.use)) {
  260. set.seed(seed = seed.use)
  261. }
  262. if (rev.mds) {
  263. object <- t(object)
  264. }
  265. nmds <- min(nmds, nrow(x = object) - 1)
  266. x <- t(as_matrix(object))
  267. cell.dist <- as.dist(dist(x = x, method = dist.method))
  268. if (mds.method == "cmdscale") {
  269. mds.results <- cmdscale(cell.dist, k = nmds, eig = TRUE, ...)
  270. }
  271. if (mds.method == "isoMDS") {
  272. check_R("MASS")
  273. mds.results <- MASS::isoMDS(cell.dist, k = nmds, ...)
  274. }
  275. if (mds.method == "sammon") {
  276. check_R("MASS")
  277. mds.results <- MASS::sammon(cell.dist, k = nmds, ...)
  278. }
  279. cell.embeddings <- mds.results$points
  280. rownames(x = cell.embeddings) <- colnames(x = object)
  281. colnames(x = cell.embeddings) <- paste0(reduction.key, 1:nmds)
  282. reduction.data <- CreateDimReducObject(
  283. embeddings = cell.embeddings,
  284. assay = assay,
  285. key = reduction.key,
  286. misc = list(slot = slot, mds.results = mds.results)
  287. )
  288. return(reduction.data)
  289. }
  290. #' Run GLMPCA (generalized version of principal components analysis)
  291. #'
  292. #' @param object An object. This can be a Seurat object, an assay object, or a matrix-like object.
  293. #' @param assay A character string specifying the assay to be used for the analysis. Default is NULL.
  294. #' @param slot A character string specifying the slot name to be used for the analysis. Default is "counts".
  295. #' @param features A character vector specifying the features to be used for the analysis. Default is NULL, which uses all variable features.
  296. #' @param L An integer specifying the number of components to be computed. Default is 5.
  297. #' @param fam A character string specifying the family of the generalized linear model to be used. Currently supported values are "poi", "nb", "nb2", "binom", "mult", and "bern". Default is "poi".
  298. #' @param rev.gmlpca A logical value indicating whether to perform reverse GLMPCA (i.e., transpose the input matrix) before running the analysis. Default is FALSE.
  299. #' @param ndims.print An integer vector specifying the dimensions (number of components) to print in the output. Default is 1:5.
  300. #' @param nfeatures.print An integer specifying the number of features to print in the output. Default is 30.
  301. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "glmpca".
  302. #' @param reduction.key A character string specifying the prefix for the column names of the basis vectors. Default is "GLMPC_".
  303. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  304. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  305. #' @param ... Additional arguments to be passed to the \link[glmpca]{glmpca} function.
  306. #'
  307. #' @examples
  308. #' pancreas_sub <- RunGLMPCA(object = pancreas_sub)
  309. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "glmpca")
  310. #'
  311. #' @rdname RunGLMPCA
  312. #' @export
  313. RunGLMPCA <- function(object, ...) {
  314. UseMethod(generic = "RunGLMPCA", object = object)
  315. }
  316. #' @rdname RunGLMPCA
  317. #' @method RunGLMPCA Seurat
  318. #' @importFrom Seurat LogSeuratCommand DefaultAssay GetAssayData Embeddings
  319. #' @export
  320. RunGLMPCA.Seurat <- function(object, assay = NULL, slot = "counts",
  321. features = NULL, L = 5, fam = c("poi", "nb", "nb2", "binom", "mult", "bern"),
  322. rev.gmlpca = FALSE, ndims.print = 1:5, nfeatures.print = 30,
  323. reduction.name = "glmpca", reduction.key = "GLMPC_",
  324. verbose = TRUE, seed.use = 11, ...) {
  325. features <- features %||% VariableFeatures(object = object)
  326. assay <- assay %||% DefaultAssay(object = object)
  327. assay.data <- GetAssay(object = object, assay = assay)
  328. reduction.data <- RunGLMPCA(
  329. object = assay.data,
  330. assay = assay,
  331. slot = slot,
  332. L = L,
  333. fam = fam,
  334. rev.gmlpca = rev.gmlpca,
  335. ndims.print = ndims.print,
  336. nfeatures.print = nfeatures.print,
  337. reduction.key = reduction.key,
  338. verbose = verbose,
  339. ...
  340. )
  341. object[[reduction.name]] <- reduction.data
  342. object <- LogSeuratCommand(object = object)
  343. return(object)
  344. }
  345. #' @rdname RunGLMPCA
  346. #' @method RunGLMPCA Assay
  347. #' @importFrom stats var
  348. #' @importFrom Seurat VariableFeatures GetAssayData
  349. #' @export
  350. RunGLMPCA.Assay <- function(object, assay = NULL, slot = "counts",
  351. features = NULL, L = 5, fam = c("poi", "nb", "nb2", "binom", "mult", "bern"),
  352. rev.gmlpca = FALSE, ndims.print = 1:5, nfeatures.print = 30,
  353. reduction.key = "GLMPC_", verbose = TRUE, seed.use = 11, ...) {
  354. features <- features %||% VariableFeatures(object = object)
  355. data.use <- GetAssayData(object = object, slot = slot)
  356. features.var <- apply(
  357. X = data.use[features, ], MARGIN = 1,
  358. FUN = var
  359. )
  360. features.keep <- features[features.var > 0]
  361. data.use <- data.use[features.keep, ]
  362. reduction.data <- RunGLMPCA(
  363. object = data.use,
  364. assay = assay,
  365. slot = slot,
  366. L = L,
  367. fam = fam,
  368. rev.gmlpca = rev.gmlpca,
  369. ndims.print = ndims.print,
  370. nfeatures.print = nfeatures.print,
  371. reduction.key = reduction.key,
  372. verbose = verbose,
  373. ...
  374. )
  375. return(reduction.data)
  376. }
  377. #' @rdname RunGLMPCA
  378. #' @method RunGLMPCA default
  379. #' @importFrom Seurat DefaultAssay DefaultAssay<- CreateDimReducObject Tool<- LogSeuratCommand
  380. #' @export
  381. RunGLMPCA.default <- function(object, assay = NULL, slot = "counts",
  382. features = NULL, L = 5, fam = c("poi", "nb", "nb2", "binom", "mult", "bern"),
  383. rev.gmlpca = FALSE, ndims.print = 1:5, nfeatures.print = 30,
  384. reduction.key = "GLMPC_", verbose = TRUE, seed.use = 11, ...) {
  385. check_R("glmpca")
  386. if (inherits(object, "dgCMatrix")) {
  387. object <- as_matrix(object)
  388. }
  389. fam <- match.arg(fam)
  390. glmpca_results <- glmpca::glmpca(Y = object, L = L, fam = fam, ...)
  391. glmpca_dimnames <- paste0(reduction.key, seq_len(L))
  392. factors <- as_matrix(glmpca_results$factors)
  393. loadings <- as_matrix(glmpca_results$loadings)
  394. colnames(x = factors) <- glmpca_dimnames
  395. colnames(x = loadings) <- glmpca_dimnames
  396. factors_l2_norm <- sqrt(colSums(factors^2))
  397. class(glmpca_results) <- NULL
  398. glmpca_results$factors <- glmpca_results$loadings <- NULL
  399. reduction.data <- CreateDimReducObject(
  400. embeddings = factors,
  401. key = reduction.key,
  402. loadings = loadings,
  403. stdev = factors_l2_norm,
  404. assay = assay,
  405. global = TRUE,
  406. misc = list(slot = slot, glmpca.results = glmpca_results)
  407. )
  408. if (verbose) {
  409. msg <- capture.output(print(
  410. x = reduction.data,
  411. dims = ndims.print,
  412. nfeatures = nfeatures.print
  413. ))
  414. message(paste(msg, collapse = "\n"))
  415. }
  416. return(reduction.data)
  417. }
  418. #' Run DM (diffusion map)
  419. #'
  420. #' @param object An object. This can be a Seurat object or a matrix-like object.
  421. #' @param reduction A character string specifying the reduction to be used.
  422. #' @param dims An integer vector specifying the dimensions to be used. Default is 1:30.
  423. #' @param features A character vector specifying the features to be used. Default is NULL.
  424. #' @param assay A character string specifying the assay to be used. Default is NULL.
  425. #' @param slot A character string specifying the slot name to be used. Default is "data".
  426. #' @param ndcs An integer specifying the number of diffusion components (dimensions) to be computed. Default is 2.
  427. #' @param sigma A character string specifying the diffusion scale parameter of the Gaussian kernel. Currently supported values are "local" (default) and "global".
  428. #' @param k An integer specifying the number of nearest neighbors to be used for the construction of the graph. Default is 30.
  429. #' @param dist.method A character string specifying the distance metric to be used for the construction of the knn graph. Currently supported values are "euclidean" and "cosine". Default is "euclidean".
  430. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "dm".
  431. #' @param reduction.key A character string specifying the prefix for the column names of the basis vectors. Default is "DM_".
  432. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  433. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  434. #' @param ... Additional arguments to be passed to the \link[destiny]{DiffusionMap} function.
  435. #'
  436. #' @examples
  437. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  438. #' pancreas_sub <- RunDM(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  439. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "dm")
  440. #'
  441. #' @rdname RunDM
  442. #' @export
  443. #'
  444. RunDM <- function(object, ...) {
  445. UseMethod(generic = "RunDM", object = object)
  446. }
  447. #' @rdname RunDM
  448. #' @method RunDM Seurat
  449. #' @importFrom Seurat LogSeuratCommand DefaultAssay GetAssayData Embeddings
  450. #' @export
  451. RunDM.Seurat <- function(object,
  452. reduction = "pca", dims = 1:30,
  453. features = NULL, assay = NULL, slot = "data",
  454. ndcs = 2, sigma = "local", k = 30, dist.method = "euclidean",
  455. reduction.name = "dm", reduction.key = "DM_",
  456. verbose = TRUE, seed.use = 11, ...) {
  457. if (!is.null(x = features)) {
  458. assay <- assay %||% DefaultAssay(object = object)
  459. data.use <- as_matrix(t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
  460. if (ncol(x = data.use) < ndcs) {
  461. stop("Please provide as many or more features than ndcs: ",
  462. length(x = features), " features provided, ",
  463. ndcs, " Diffusion components requested",
  464. call. = FALSE
  465. )
  466. }
  467. } else if (!is.null(x = dims)) {
  468. data.use <- Embeddings(object[[reduction]])[, dims]
  469. assay <- DefaultAssay(object = object[[reduction]])
  470. if (length(x = dims) < ndcs) {
  471. stop("Please provide as many or more dims than ndcs: ",
  472. length(x = dims), " dims provided, ", ndcs,
  473. " DiffusionMap components requested",
  474. call. = FALSE
  475. )
  476. }
  477. } else {
  478. stop("Please specify one of dims, features")
  479. }
  480. reduction.data <- RunDM(
  481. object = data.use,
  482. assay = assay,
  483. slot = slot,
  484. ndcs = ndcs,
  485. sigma = sigma,
  486. k = k,
  487. dist.method = dist.method,
  488. reduction.key = reduction.key,
  489. seed.use = seed.use,
  490. verbose = verbose,
  491. ...
  492. )
  493. object[[reduction.name]] <- reduction.data
  494. object <- LogSeuratCommand(object = object)
  495. return(object)
  496. }
  497. #' @rdname RunDM
  498. #' @method RunDM default
  499. #' @importFrom utils capture.output
  500. #' @importFrom Seurat CreateDimReducObject
  501. #' @export
  502. RunDM.default <- function(object, assay = NULL, slot = "data",
  503. ndcs = 2, sigma = "local", k = 30, dist.method = "euclidean",
  504. reduction.key = "DM_", verbose = TRUE, seed.use = 11, ...) {
  505. check_R("destiny")
  506. if (!is.null(x = seed.use)) {
  507. set.seed(seed = seed.use)
  508. }
  509. dm.results <- destiny::DiffusionMap(data = as_matrix(object), n_eigs = ndcs, sigma = sigma, k = k, distance = dist.method, verbose = verbose, ...)
  510. cell.embeddings <- dm.results@eigenvectors
  511. rownames(x = cell.embeddings) <- rownames(object)
  512. colnames(x = cell.embeddings) <- paste0(reduction.key, 1:ndcs)
  513. reduction <- CreateDimReducObject(
  514. embeddings = cell.embeddings,
  515. assay = assay,
  516. key = reduction.key,
  517. misc = list(slot = slot, dm.results = dm.results)
  518. )
  519. return(reduction)
  520. }
  521. #' Run UMAP (Uniform Manifold Approximation and Projection)
  522. #'
  523. #' @param object An object. This can be a Seurat object, a matrix-like object, a Neighbor object, or a Graph object.
  524. #' @param reduction A character string specifying the reduction to be used. Default is "pca".
  525. #' @param dims An integer vector specifying the dimensions to be used. Default is NULL.
  526. #' @param features A character vector specifying the features to be used. Default is NULL.
  527. #' @param neighbor A character string specifying the name of the Neighbor object to be used. Default is NULL.
  528. #' @param graph A character string specifying the name of the Graph object to be used. Default is NULL.
  529. #' @param assay A character string specifying the assay to be used. Default is NULL.
  530. #' @param slot A character string specifying the slot name to be used. Default is "data".
  531. #' @param umap.method A character string specifying the UMAP method to be used. Options are "naive" and uwot". Default is "uwot".
  532. #' @param reduction.model A DimReduc object containing a pre-trained UMAP model. Default is NULL.
  533. #' @param return.model A logical value indicating whether to return the UMAP model. Default is FALSE.
  534. #' @param n.neighbors An integer specifying the number of nearest neighbors to be used. Default is 30.
  535. #' @param n.components An integer specifying the number of UMAP components. Default is 2.
  536. #' @param metric A character string specifying the metric or a function to be used for distance calculations. When using a string, available metrics are: euclidean, manhattan. Other available generalized metrics are: cosine, pearson, pearson2. Note the triangle inequality may not be satisfied by some generalized metrics, hence knn search may not be optimal. When using metric.function as a function, the signature must be function(matrix, origin, target) and should compute a distance between the origin column and the target columns. Default is "cosine".
  537. #' @param n.epochs An integer specifying the number of iterations performed during layout optimization for UMAP. Default is 200.
  538. #' @param spread A numeric value specifying the spread parameter for UMAP, used during automatic estimation of a/b parameters. Default is 1.
  539. #' @param min.dist A numeric value specifying the minimum distance between UMAP embeddings, determines how close points appear in the final layout. Default is 0.3.
  540. #' @param set.op.mix.ratio Interpolate between (fuzzy) union and intersection as the set operation used to combine local fuzzy simplicial sets to obtain a global fuzzy simplicial sets. Both fuzzy set operations use the product t-norm. The value of this parameter should be between 0.0 and 1.0; a value of 1.0 will use a pure fuzzy union, while 0.0 will use a pure fuzzy intersection.
  541. #' @param local.connectivity An integer specifying the local connectivity, used during construction of fuzzy simplicial set. Default is 1.
  542. #' @param negative.sample.rate An integer specifying the negative sample rate for UMAP optimization. Determines how many non-neighbor points are used per point and per iteration during layout optimization. Default is 5.
  543. #' @param a A numeric value specifying the parameter a for UMAP optimization. Contributes to gradient calculations during layout optimization. When left at NA, a suitable value will be estimated automatically. Default is NULL.
  544. #' @param b A numeric value specifying the parameter b for UMAP optimization. Contributes to gradient calculations during layout optimization. When left at NA, a suitable value will be estimated automatically. Default is NULL.
  545. #' @param learning.rate A numeric value specifying the initial value of "learning rate" of layout optimization. Default is 1.
  546. #' @param repulsion.strength A numeric value determines, together with alpha, the learning rate of layout optimization. Default is 1.
  547. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "umap".
  548. #' @param reduction.key A character string specifying the prefix for the column names of the UMAP embeddings. Default is "UMAP_".
  549. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  550. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  551. #' @param ... Unused argument.
  552. #'
  553. #' @examples
  554. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  555. #' pancreas_sub <- RunUMAP2(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  556. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "umap")
  557. #'
  558. #' @rdname RunUMAP2
  559. #' @export
  560. RunUMAP2 <- function(object, ...) {
  561. UseMethod(generic = "RunUMAP2", object = object)
  562. }
  563. #' @rdname RunUMAP2
  564. #' @method RunUMAP2 Seurat
  565. #' @importFrom Seurat LogSeuratCommand
  566. #' @export
  567. RunUMAP2.Seurat <- function(object,
  568. reduction = "pca", dims = NULL, features = NULL, neighbor = NULL, graph = NULL,
  569. assay = NULL, slot = "data",
  570. umap.method = "uwot", reduction.model = NULL, n_threads = NULL,
  571. return.model = FALSE, n.neighbors = 30L, n.components = 2L,
  572. metric = "cosine", n.epochs = 200L, spread = 1, min.dist = 0.3,
  573. set.op.mix.ratio = 1, local.connectivity = 1L, negative.sample.rate = 5L,
  574. a = NULL, b = NULL, learning.rate = 1, repulsion.strength = 1,
  575. reduction.name = "umap", reduction.key = "UMAP_",
  576. verbose = TRUE, seed.use = 11L, ...) {
  577. if (sum(c(is.null(x = dims), is.null(x = features), is.null(neighbor), is.null(x = graph))) == 4) {
  578. stop("Please specify only one of the following arguments: dims, features, neighbor or graph")
  579. }
  580. if (!is.null(x = features)) {
  581. assay <- assay %||% DefaultAssay(object = object)
  582. data.use <- as_matrix(t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
  583. if (ncol(x = data.use) < n.components) {
  584. stop(
  585. "Please provide as many or more features than n.components: ",
  586. length(x = features),
  587. " features provided, ",
  588. n.components,
  589. " UMAP components requested",
  590. call. = FALSE
  591. )
  592. }
  593. } else if (!is.null(x = dims)) {
  594. data.use <- as_matrix(Embeddings(object[[reduction]])[, dims])
  595. assay <- DefaultAssay(object = object[[reduction]])
  596. if (length(x = dims) < n.components) {
  597. stop(
  598. "Please provide as many or more dims than n.components: ",
  599. length(x = dims),
  600. " dims provided, ",
  601. n.components,
  602. " UMAP components requested",
  603. call. = FALSE
  604. )
  605. }
  606. } else if (!is.null(x = neighbor)) {
  607. if (!inherits(x = object[[neighbor]], what = "Neighbor")) {
  608. stop(
  609. "Please specify a Neighbor object name, ",
  610. "instead of the name of a ",
  611. class(object[[neighbor]]),
  612. " object",
  613. call. = FALSE
  614. )
  615. }
  616. data.use <- object[[neighbor]]
  617. } else if (!is.null(x = graph)) {
  618. if (!inherits(x = object[[graph]], what = "Graph")) {
  619. stop(
  620. "Please specify a Graph object name, ",
  621. "instead of the name of a ",
  622. class(object[[graph]]),
  623. " object",
  624. call. = FALSE
  625. )
  626. }
  627. data.use <- object[[graph]]
  628. } else {
  629. stop("Please specify one of dims, features, neighbor, or graph")
  630. }
  631. object[[reduction.name]] <- RunUMAP2(
  632. object = data.use, assay = assay,
  633. umap.method = umap.method, reduction.model = reduction.model,
  634. return.model = return.model, n.neighbors = n.neighbors, n.components = n.components,
  635. metric = metric, n.epochs = n.epochs, spread = spread, min.dist = min.dist,
  636. set.op.mix.ratio = set.op.mix.ratio, local.connectivity = local.connectivity, negative.sample.rate = negative.sample.rate,
  637. a = a, b = b, learning.rate = learning.rate, repulsion.strength = repulsion.strength,
  638. seed.use = seed.use, verbose = verbose, reduction.key = reduction.key
  639. )
  640. object <- LogSeuratCommand(object = object)
  641. return(object)
  642. }
  643. #' @rdname RunUMAP2
  644. #' @method RunUMAP2 default
  645. #' @importFrom SeuratObject Indices Distances as.sparse CreateDimReducObject Misc<- Misc
  646. #' @importFrom Matrix sparseMatrix
  647. #' @export
  648. RunUMAP2.default <- function(object, assay = NULL,
  649. umap.method = "uwot", reduction.model = NULL, n_threads = NULL,
  650. return.model = FALSE, n.neighbors = 30L, n.components = 2L,
  651. metric = "cosine", n.epochs = 200L, spread = 1, min.dist = 0.3,
  652. set.op.mix.ratio = 1, local.connectivity = 1L, negative.sample.rate = 5L,
  653. a = NULL, b = NULL, learning.rate = 1, repulsion.strength = 1,
  654. reduction.key = "UMAP_", verbose = TRUE, seed.use = 11L, ...) {
  655. if (!is.null(x = seed.use)) {
  656. set.seed(seed = seed.use)
  657. }
  658. if (return.model) {
  659. if (verbose) {
  660. message("UMAP will return its model")
  661. }
  662. }
  663. if (!is.null(x = reduction.model)) {
  664. if (verbose) {
  665. message("Running UMAP projection")
  666. }
  667. if (is.null(x = reduction.model) || !inherits(x = reduction.model, what = "DimReduc")) {
  668. stop("If running projection UMAP, please pass a DimReduc object with the model stored to reduction.model.",
  669. call. = FALSE
  670. )
  671. }
  672. model <- Misc(object = reduction.model, slot = "model")
  673. if (length(x = model) == 0) {
  674. stop("The provided reduction.model does not have a model stored.",
  675. call. = FALSE
  676. )
  677. }
  678. umap.method <- ifelse("layout" %in% names(model), "naive-predict", "uwot-predict")
  679. }
  680. n.epochs <- as.integer(n.epochs)
  681. n.neighbors <- as.integer(n.neighbors)
  682. n.components <- as.integer(n.components)
  683. local.connectivity <- as.integer(local.connectivity)
  684. negative.sample.rate <- as.integer(negative.sample.rate)
  685. if (inherits(x = object, what = "Neighbor")) {
  686. object <- list(idx = Indices(object), dist = Distances(object))
  687. }
  688. if (umap.method == "naive") {
  689. umap.config <- umap::umap.defaults
  690. umap.config$n_neighbors <- n.neighbors
  691. umap.config$n_components <- n.components
  692. umap.config$metric <- metric
  693. umap.config$n_epochs <- ifelse(is.null(n.epochs), 200, n.epochs)
  694. umap.config$spread <- spread
  695. umap.config$min_dist <- min.dist
  696. umap.config$set_op_mix_ratio <- set.op.mix.ratio
  697. umap.config$local_connectivity <- local.connectivity
  698. umap.config$a <- ifelse(is.null(a), NA, a)
  699. umap.config$b <- ifelse(is.null(b), NA, b)
  700. umap.config$gamma <- repulsion.strength
  701. umap.config$alpha <- learning.rate
  702. umap.config$negative_sample_rate <- negative.sample.rate
  703. umap.config$random_state <- seed.use
  704. umap.config$transform_state <- seed.use
  705. umap.config$verbose <- verbose
  706. if (is.na(umap.config$a) || is.na(umap.config$b)) {
  707. umap.config[c("a", "b")] <- umap:::find.ab.params(umap.config$spread, umap.config$min_dist)
  708. umap.config$min_dist <- umap::umap.defaults$min_dist
  709. }
  710. if (inherits(x = object, what = "dist")) {
  711. knn <- umap:::knn.from.dist(d = object, k = n.neighbors)
  712. out <- umap::umap(
  713. d = matrix(nrow = nrow(object)),
  714. config = umap.config, knn = knn
  715. )
  716. embeddings <- out$layout
  717. rownames(x = embeddings) <- attr(object, "Labels")
  718. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  719. reduction <- CreateDimReducObject(
  720. embeddings = embeddings,
  721. key = reduction.key,
  722. assay = assay,
  723. global = TRUE
  724. )
  725. if (return.model) {
  726. Misc(reduction, slot = "model") <- out
  727. }
  728. return(reduction)
  729. }
  730. if (inherits(x = object, what = "list")) {
  731. # object <- srt@neighbors$Seurat.nn
  732. # object <- list(idx = Indices(object), dist = Distances(object))
  733. # j <- as.numeric(t(object$idx))
  734. # i <- ((1:length(j)) - 1) %/% ncol(object$idx) + 1
  735. # graph <- as(object = sparseMatrix(
  736. # i = i, j = j, x = as.numeric(t(object$dist)),
  737. # dims = c(nrow(x = object$idx), nrow(x = object$idx))
  738. # ), Class = "Graph")
  739. # rownames(x = graph) <- rownames(object$idx)
  740. # colnames(x = graph) <- rownames(object$idx)
  741. # object <- graph
  742. knn <- umap::umap.knn(indexes = object[["idx"]], distances = object[["dist"]])
  743. out <- umap::umap(
  744. d = matrix(nrow = nrow(object[["idx"]])),
  745. config = umap.config, knn = knn
  746. )
  747. embeddings <- out$layout
  748. rownames(x = embeddings) <- rownames(object[["idx"]])
  749. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  750. reduction <- CreateDimReducObject(
  751. embeddings = embeddings,
  752. key = reduction.key,
  753. assay = assay,
  754. global = TRUE
  755. )
  756. if (return.model) {
  757. Misc(reduction, slot = "model") <- out
  758. }
  759. return(reduction)
  760. }
  761. if (inherits(x = object, what = "Graph")) {
  762. if (!inherits(object, "dgCMatrix")) {
  763. object <- as.sparse(object[1:nrow(object), ])
  764. }
  765. diag(object) <- 0
  766. if (ncol(object) > 10000) {
  767. obs_sample <- sample(1:ncol(object), size = 10000)
  768. } else {
  769. obs_sample <- 1:ncol(object)
  770. }
  771. if (!isSymmetric(as_matrix(object[obs_sample, obs_sample]))) {
  772. stop("Graph must be a symmetric matrix.")
  773. }
  774. coo <- matrix(ncol = 3, nrow = length(object@x))
  775. coo[, 1] <- rep(1:ncol(object), diff(object@p))
  776. coo[, 2] <- object@i + 1
  777. coo[, 3] <- object@x
  778. colnames(coo) <- c("from", "to", "value")
  779. coo <- coo[order(coo[, 1], coo[, 2]), ]
  780. graph <- list(coo = coo, names = rownames(object), n.elements = nrow(object))
  781. class(graph) <- "coo"
  782. # diag(object) <- 0
  783. # if (inherits(object, what = "dgCMatrix")) {
  784. # object <- as_matrix(object)
  785. # } else {
  786. # object <- as_matrix(object)
  787. # }
  788. # if (!isSymmetric(object)) {
  789. # stop("Graph must be a symmetric matrix.")
  790. # }
  791. # graph <- umap:::coo(object)
  792. # # coo <- function(x) {
  793. # # if (!is(x, "Matrix")) {
  794. # # stop("x must be a square matrix\n")
  795. # # }
  796. # # if (nrow(x) != ncol(x)) {
  797. # # stop("x must be a square matrix\n")
  798. # # }
  799. # # nx <- nrow(x)
  800. # # coo <- matrix(0, ncol = 3, nrow = nx * nx)
  801. # # coo[, 1] <- rep(seq_len(nx), nx)
  802. # # coo[, 2] <- rep(seq_len(nx), each = nx)
  803. # # coo[, 3] <- as.vector(x)
  804. # # colnames(coo) <- c("from", "to", "value")
  805. # # coo <- coo[order(coo[, 1], coo[, 2]), ]
  806. # # make.coo(coo, rownames(x), nrow(x))
  807. # # }
  808. # # make.coo <- function(x, names, n.elements) {
  809. # # x <- x[, 1:3, drop = FALSE]
  810. # # colnames(x) <- c("from", "to", "value")
  811. # # result <- list(coo = x, names = names, n.elements = n.elements)
  812. # # class(result) <- "coo"
  813. # # result
  814. # # }
  815. umap.config$init <- "spectral"
  816. initial <- umap:::make.initial.embedding(V = graph$n.elements, config = umap.config, g = graph)
  817. embeddings <- umap:::naive.simplicial.set.embedding(g = graph, embedding = initial, config = umap.config)
  818. embeddings <- umap:::center.embedding(embeddings)
  819. rownames(x = embeddings) <- rownames(x = object)
  820. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  821. reduction <- CreateDimReducObject(
  822. embeddings = embeddings,
  823. key = reduction.key,
  824. assay = assay,
  825. global = TRUE
  826. )
  827. if (return.model) {
  828. warning("return.model does not support 'Graph' input.", immediate. = TRUE)
  829. }
  830. return(reduction)
  831. }
  832. if (inherits(x = object, what = "matrix") || inherits(x = object, what = "Matrix")) {
  833. # object <- srt@reductions$[email hidden]
  834. out <- umap::umap(d = object, config = umap.config, method = "naive")
  835. embeddings <- out$layout
  836. rownames(x = embeddings) <- rownames(object)
  837. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  838. reduction <- CreateDimReducObject(
  839. embeddings = embeddings,
  840. key = reduction.key,
  841. assay = assay,
  842. global = TRUE
  843. )
  844. if (return.model) {
  845. Misc(reduction, slot = "model") <- out
  846. }
  847. return(reduction)
  848. }
  849. }
  850. if (umap.method == "uwot") {
  851. if (inherits(x = object, what = "dist")) {
  852. embeddings <- uwot::umap(
  853. X = object, n_neighbors = n.neighbors, n_threads = n_threads, n_components = n.components,
  854. metric = metric, n_epochs = n.epochs, learning_rate = learning.rate,
  855. min_dist = min.dist, spread = spread, set_op_mix_ratio = set.op.mix.ratio,
  856. local_connectivity = local.connectivity, repulsion_strength = repulsion.strength,
  857. negative_sample_rate = negative.sample.rate,
  858. a = a, b = b, verbose = verbose,
  859. ret_model = FALSE
  860. )
  861. rownames(x = embeddings) <- attr(object, "Labels")
  862. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  863. reduction <- CreateDimReducObject(
  864. embeddings = embeddings,
  865. key = reduction.key,
  866. assay = assay,
  867. global = TRUE
  868. )
  869. if (return.model) {
  870. warning("return.model does not support 'dist' input.", immediate. = TRUE)
  871. }
  872. return(reduction)
  873. }
  874. if (inherits(x = object, what = "list")) {
  875. # object <- srt@neighbors$Seurat.nn
  876. # object <- list(idx = Indices(object), dist = Distances(object))
  877. out <- uwot::umap(
  878. X = NULL, nn_method = object, n_threads = n_threads, n_components = n.components,
  879. metric = metric, n_epochs = n.epochs, learning_rate = learning.rate,
  880. min_dist = min.dist, spread = spread, set_op_mix_ratio = set.op.mix.ratio,
  881. local_connectivity = local.connectivity, repulsion_strength = repulsion.strength,
  882. negative_sample_rate = negative.sample.rate,
  883. a = a, b = b, verbose = verbose,
  884. ret_model = return.model
  885. )
  886. if (return.model) {
  887. embeddings <- out$embedding
  888. } else {
  889. embeddings <- out
  890. }
  891. rownames(x = embeddings) <- row.names(object[["idx"]])
  892. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  893. reduction <- CreateDimReducObject(
  894. embeddings = embeddings,
  895. key = reduction.key,
  896. assay = assay,
  897. global = TRUE
  898. )
  899. if (return.model) {
  900. out$nn_index <- NULL
  901. Misc(reduction, slot = "model") <- out
  902. }
  903. return(reduction)
  904. }
  905. if (inherits(x = object, what = "Graph")) {
  906. if (!inherits(object, "dgCMatrix")) {
  907. object <- as.sparse(object[1:nrow(object), ])
  908. }
  909. diag(object) <- 0
  910. if (ncol(object) > 10000) {
  911. obs_sample <- sample(1:ncol(object), size = 10000)
  912. } else {
  913. obs_sample <- 1:ncol(object)
  914. }
  915. if (!isSymmetric(as_matrix(object[obs_sample, obs_sample]))) {
  916. stop("Graph must be a symmetric matrix.")
  917. }
  918. val <- split(object@x, rep(1:ncol(object), diff(object@p)))
  919. pos <- split(object@i + 1, rep(1:ncol(object), diff(object@p)))
  920. idx <- t(mapply(function(x, y) {
  921. out <- y[head(order(x, decreasing = TRUE), n.neighbors)]
  922. length(out) <- n.neighbors
  923. return(out)
  924. }, x = val, y = pos))
  925. connectivity <- t(mapply(function(x, y) {
  926. out <- y[head(order(x, decreasing = TRUE), n.neighbors)]
  927. length(out) <- n.neighbors
  928. out[is.na(out)] <- 0
  929. return(out)
  930. }, x = val, y = val))
  931. idx[is.na(idx)] <- sample(1:nrow(object), size = sum(is.na(idx)), replace = TRUE)
  932. nn <- list(idx = idx, dist = max(connectivity) - connectivity + min(diff(range(connectivity)), 1) / 1e50)
  933. # idx <- t(as_matrix(apply(object, 2, function(x) order(x, decreasing = TRUE)[1:n.neighbors])))
  934. # connectivity <- t(as_matrix(apply(object, 2, function(x) x[order(x, decreasing = TRUE)[1:n.neighbors]])))
  935. out <- uwot::umap(
  936. X = NULL, nn_method = nn, n_threads = n_threads, n_components = n.components,
  937. metric = metric, n_epochs = n.epochs, learning_rate = learning.rate,
  938. min_dist = min.dist, spread = spread, set_op_mix_ratio = set.op.mix.ratio,
  939. local_connectivity = local.connectivity, repulsion_strength = repulsion.strength,
  940. negative_sample_rate = negative.sample.rate,
  941. a = a, b = b, verbose = verbose,
  942. ret_model = return.model
  943. )
  944. if (return.model) {
  945. embeddings <- out$embedding
  946. } else {
  947. embeddings <- out
  948. }
  949. # object <- srt@graphs$BBKNN
  950. # object@x <- max(object@x) - object@x + 1e-10
  951. # min_neighbors <- min(rowSums(object > 0))
  952. # embeddings <- uwot::umap(
  953. # X = object*100, n_neighbors = min(min_neighbors,n.neighbors), n_threads = 1, n_components = n.components,
  954. # metric = metric, n_epochs = n.epochs, learning_rate = learning.rate,
  955. # min_dist = min.dist, spread = spread, set_op_mix_ratio = set.op.mix.ratio,
  956. # local_connectivity = local.connectivity, repulsion_strength = repulsion.strength,
  957. # negative_sample_rate = negative.sample.rate,
  958. # a = a, b = b, verbose = verbose,
  959. # ret_model = FALSE
  960. # )
  961. rownames(x = embeddings) <- row.names(object)
  962. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  963. reduction <- CreateDimReducObject(
  964. embeddings = embeddings,
  965. key = reduction.key,
  966. assay = assay,
  967. global = TRUE
  968. )
  969. if (return.model) {
  970. out$nn_index <- NULL
  971. Misc(reduction, slot = "model") <- out
  972. }
  973. return(reduction)
  974. }
  975. if (inherits(x = object, what = "matrix") || inherits(x = object, what = "Matrix")) {
  976. # object <- srt@reductions$[email hidden]
  977. out <- uwot::umap(
  978. X = object, n_neighbors = n.neighbors, n_threads = n_threads, n_components = n.components,
  979. metric = metric, n_epochs = n.epochs, learning_rate = learning.rate,
  980. min_dist = min.dist, spread = spread, set_op_mix_ratio = set.op.mix.ratio,
  981. local_connectivity = local.connectivity, repulsion_strength = repulsion.strength,
  982. negative_sample_rate = negative.sample.rate,
  983. a = a, b = b, verbose = verbose,
  984. ret_model = return.model
  985. )
  986. if (return.model) {
  987. embeddings <- out$embedding
  988. } else {
  989. embeddings <- out
  990. }
  991. rownames(x = embeddings) <- row.names(object)
  992. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  993. reduction <- CreateDimReducObject(
  994. embeddings = embeddings,
  995. key = reduction.key,
  996. assay = assay,
  997. global = TRUE
  998. )
  999. if (return.model) {
  1000. out$nn_index <- NULL
  1001. Misc(reduction, slot = "model") <- out
  1002. }
  1003. return(reduction)
  1004. }
  1005. }
  1006. if (umap.method == "naive-predict") {
  1007. if (inherits(x = object, what = "matrix") || inherits(x = object, what = "Matrix")) {
  1008. class(model) <- "umap"
  1009. if (any(!colnames(model$data) %in% colnames(object))) {
  1010. stop("query data must contain the same features with the model:\n", paste(head(colnames(model$data), 10), collapse = ","), " ......")
  1011. }
  1012. embeddings <- predict(model, object[, colnames(model$data)])
  1013. rownames(x = embeddings) <- row.names(object)
  1014. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  1015. reduction <- CreateDimReducObject(
  1016. embeddings = embeddings,
  1017. key = reduction.key,
  1018. assay = assay,
  1019. global = TRUE
  1020. )
  1021. return(reduction)
  1022. } else {
  1023. stop("naive umap model only support 'matrix' input.")
  1024. }
  1025. }
  1026. if (umap.method == "uwot-predict") {
  1027. if (inherits(x = object, what = "list")) {
  1028. if (ncol(object[["idx"]]) != model$n_neighbors) {
  1029. warning(
  1030. "Number of neighbors between query and reference is not equal to the number of neighbros within reference"
  1031. )
  1032. model$n_neighbors <- ncol(object[["idx"]])
  1033. }
  1034. if (is.null(model$num_precomputed_nns) || model$num_precomputed_nns == 0) {
  1035. model$num_precomputed_nns <- 1
  1036. }
  1037. embeddings <- uwot::umap_transform(
  1038. X = NULL, nn_method = object, model = model, n_epochs = n.epochs,
  1039. n_threads = n_threads, verbose = verbose
  1040. )
  1041. rownames(x = embeddings) <- row.names(object[["idx"]])
  1042. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  1043. reduction <- CreateDimReducObject(
  1044. embeddings = embeddings,
  1045. key = reduction.key,
  1046. assay = assay,
  1047. global = TRUE
  1048. )
  1049. return(reduction)
  1050. }
  1051. if (inherits(x = object, what = "Graph")) {
  1052. match_k <- t(as_matrix(apply(object, 2, function(x) order(x, decreasing = TRUE)[1:n.neighbors])))
  1053. match_k_connectivity <- t(as_matrix(apply(object, 2, function(x) x[order(x, decreasing = TRUE)[1:n.neighbors]])))
  1054. object <- list(idx = match_k, dist = max(match_k_connectivity) - match_k_connectivity)
  1055. if (is.null(model$num_precomputed_nns) || model$num_precomputed_nns == 0) {
  1056. model$num_precomputed_nns <- 1
  1057. }
  1058. embeddings <- uwot::umap_transform(
  1059. X = NULL, nn_method = object, model = model, n_epochs = n.epochs,
  1060. n_threads = n_threads, verbose = verbose
  1061. )
  1062. rownames(x = embeddings) <- row.names(object[["idx"]])
  1063. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  1064. reduction <- CreateDimReducObject(
  1065. embeddings = embeddings,
  1066. key = reduction.key,
  1067. assay = assay,
  1068. global = TRUE
  1069. )
  1070. return(reduction)
  1071. }
  1072. if (inherits(x = object, what = "matrix") || inherits(x = object, what = "Matrix")) {
  1073. embeddings <- uwot::umap_transform(
  1074. X = object, model = model, n_epochs = n.epochs,
  1075. n_threads = n_threads, verbose = verbose
  1076. )
  1077. rownames(x = embeddings) <- row.names(object)
  1078. colnames(x = embeddings) <- paste0(reduction.key, 1:n.components)
  1079. reduction <- CreateDimReducObject(
  1080. embeddings = embeddings,
  1081. key = reduction.key,
  1082. assay = assay,
  1083. global = TRUE
  1084. )
  1085. return(reduction)
  1086. }
  1087. }
  1088. }
  1089. #' Run PaCMAP (Pairwise Controlled Manifold Approximation)
  1090. #'
  1091. #' @param object An object. This can be a Seurat object or a matrix-like object.
  1092. #' @param reduction A character string specifying the reduction to be used. Default is "pca".
  1093. #' @param dims An integer vector specifying the dimensions to be used. Default is NULL.
  1094. #' @param features A character vector specifying the features to be used. Default is NULL.
  1095. #' @param assay A character string specifying the assay to be used. Default is NULL.
  1096. #' @param slot A character string specifying the slot name to be used. Default is "data".
  1097. #' @param n_components An integer specifying the number of PaCMAP components. Default is 2.
  1098. #' @param n.neighbors An integer specifying the number of neighbors considered in the k-Nearest Neighbor graph. Default to 10 for dataset whose sample size is smaller than 10000. For large dataset whose sample size (n) is larger than 10000, the default value is: 10 + 15 * (log10(n) - 4).
  1099. #' @param MN_ratio A numeric value specifying the ratio of the ratio of the number of mid-near pairs to the number of neighbors. Default is 0.5.
  1100. #' @param FP_ratio A numeric value specifying the ratio of the ratio of the number of further pairs to the number of neighbors. Default is 2.
  1101. #' @param distance_method A character string specifying the distance metric to be used. Default is "euclidean".
  1102. #' @param lr A numeric value specifying the learning rate of the AdaGrad optimizer. Default is 1.
  1103. #' @param num_iters An integer specifying the number of iterations for PaCMAP optimization. Default is 450.
  1104. #' @param apply_pca A logical value indicating whether pacmap should apply PCA to the data before constructing the k-Nearest Neighbor graph. Using PCA to preprocess the data can largely accelerate the DR process without losing too much accuracy. Notice that this option does not affect the initialization of the optimization process. Default is TRUE.
  1105. #' @param init A character string specifying the initialization of the lower dimensional embedding. One of "pca" or "random". Default is "random".
  1106. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "pacmap".
  1107. #' @param reduction.key A character string specifying the prefix for the column names of the PaCMAP embeddings. Default is "PaCMAP_".
  1108. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  1109. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  1110. #' @param ... Additional arguments to be passed to the pacmap.PaCMAP function.
  1111. #'
  1112. #' @examples
  1113. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  1114. #' pancreas_sub <- RunPaCMAP(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  1115. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "pacmap")
  1116. #'
  1117. #' @rdname RunPaCMAP
  1118. #' @export
  1119. RunPaCMAP <- function(object, ...) {
  1120. UseMethod(generic = "RunPaCMAP", object = object)
  1121. }
  1122. #' @rdname RunPaCMAP
  1123. #' @method RunPaCMAP Seurat
  1124. #' @importFrom Seurat LogSeuratCommand
  1125. #' @export
  1126. RunPaCMAP.Seurat <- function(object, reduction = "pca", dims = NULL, features = NULL,
  1127. assay = NULL, slot = "data",
  1128. n_components = 2, n.neighbors = NULL, MN_ratio = 0.5, FP_ratio = 2,
  1129. distance_method = "euclidean",
  1130. lr = 1, num_iters = 450L, apply_pca = TRUE, init = "random",
  1131. reduction.name = "pacmap", reduction.key = "PaCMAP_",
  1132. verbose = TRUE, seed.use = 11L, ...) {
  1133. if (sum(c(is.null(x = dims), is.null(x = features))) < 1) {
  1134. stop("Please specify only one of the following arguments: dims, features, or graph")
  1135. }
  1136. if (!is.null(x = features)) {
  1137. assay <- assay %||% DefaultAssay(object = object)
  1138. data.use <- as_matrix(t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
  1139. if (ncol(x = data.use) < n_components) {
  1140. stop(
  1141. "Please provide as many or more features than n_components: ",
  1142. length(x = features),
  1143. " features provided, ",
  1144. n_components,
  1145. " PaCMAP components requested",
  1146. call. = FALSE
  1147. )
  1148. }
  1149. } else if (!is.null(x = dims)) {
  1150. data.use <- Embeddings(object[[reduction]])[, dims]
  1151. assay <- DefaultAssay(object = object[[reduction]])
  1152. if (length(x = dims) < n_components) {
  1153. stop(
  1154. "Please provide as many or more dims than n_components: ",
  1155. length(x = dims),
  1156. " dims provided, ",
  1157. n_components,
  1158. " PaCMAP components requested",
  1159. call. = FALSE
  1160. )
  1161. }
  1162. } else {
  1163. stop("Please specify one of dims or features")
  1164. }
  1165. object[[reduction.name]] <- RunPaCMAP(
  1166. object = data.use, assay = assay,
  1167. n_components = n_components, n.neighbors = n.neighbors, MN_ratio = MN_ratio, FP_ratio = FP_ratio,
  1168. distance_method = distance_method,
  1169. lr = lr, num_iters = num_iters, apply_pca = apply_pca, init = init,
  1170. reduction.key = reduction.key, verbose = verbose, seed.use = seed.use
  1171. )
  1172. object <- LogSeuratCommand(object = object)
  1173. return(object)
  1174. }
  1175. #' @rdname RunPaCMAP
  1176. #' @method RunPaCMAP default
  1177. #' @importFrom Seurat CreateDimReducObject
  1178. #' @importFrom reticulate import
  1179. #' @export
  1180. RunPaCMAP.default <- function(object, assay = NULL,
  1181. n_components = 2, n.neighbors = NULL, MN_ratio = 0.5, FP_ratio = 2,
  1182. distance_method = "euclidean",
  1183. lr = 1, num_iters = 450L, apply_pca = TRUE, init = "random",
  1184. reduction.key = "PaCMAP_", verbose = TRUE, seed.use = 11L, ...) {
  1185. if (!is.null(x = seed.use)) {
  1186. set.seed(seed = seed.use)
  1187. }
  1188. check_Python("pacmap")
  1189. pacmap <- import("pacmap")
  1190. operator <- pacmap$PaCMAP(
  1191. n_components = as.integer(n_components), n_neighbors = n.neighbors, MN_ratio = MN_ratio, FP_ratio = FP_ratio,
  1192. distance = distance_method,
  1193. lr = lr, num_iters = num_iters, apply_pca = apply_pca,
  1194. verbose = verbose, random_state = as.integer(seed.use)
  1195. )
  1196. embedding <- operator$fit_transform(object, init = init)
  1197. colnames(x = embedding) <- paste0(reduction.key, seq_len(ncol(x = embedding)))
  1198. rownames(x = embedding) <- rownames(object)
  1199. reduction <- CreateDimReducObject(
  1200. embeddings = embedding,
  1201. key = reduction.key,
  1202. assay = assay,
  1203. global = TRUE
  1204. )
  1205. return(reduction)
  1206. }
  1207. #' Run PHATE (Potential of Heat-diffusion for Affinity-based Trajectory Embedding)
  1208. #'
  1209. #' @param object An object. This can be a Seurat object or a matrix-like object.
  1210. #' @param reduction A character string specifying the reduction to be used. Default is "pca".
  1211. #' @param dims An integer vector specifying the dimensions to be used. Default is NULL.
  1212. #' @param features A character vector specifying the features to be used. Default is NULL.
  1213. #' @param assay A character string specifying the assay to be used. Default is NULL.
  1214. #' @param slot A character string specifying the slot name to be used. Default is "data".
  1215. #' @param n_components An integer specifying the number of PHATE components. Default is 2.
  1216. #' @param knn An integer specifying the number of nearest neighbors on which to build kernel. Default is 5.
  1217. #' @param decay An integer specifying the sets decay rate of kernel tails. Default is 40.
  1218. #' @param n_landmark An integer specifying the number of landmarks to use in fast PHATE. Default is 2000.
  1219. #' @param t A character string specifying the power to which the diffusion operator is powered. This sets the level of diffusion. If ‘auto’, t is selected according to the knee point in the Von Neumann Entropy of the diffusion operator. Default is "auto".
  1220. #' @param gamma A numeric value specifying the informational distance constant between -1 and 1. gamma=1 gives the PHATE log potential, gamma=0 gives a square root potential. Default is 1.
  1221. #' @param n_pca An integer specifying the number of principal components to use for calculating neighborhoods. For extremely large datasets, using n_pca < 20 allows neighborhoods to be calculated in roughly log(n_samples) time. Default is 100.
  1222. #' @param knn_dist A character string specifying the distance metric for k-nearest neighbors. Recommended values: "euclidean, "cosine, "precomputed". Default is "euclidean".
  1223. #' @param knn_max An integer specifying the maximum number of neighbors for which alpha decaying kernel is computed for each point. For very large datasets, setting knn_max to a small multiple of knn can speed up computation significantly. Default is NULL.
  1224. #' @param t_max An integer specifying the maximum \code{t} to test. Default is 100.
  1225. #' @param do_cluster A logical value indicating whether to perform clustering on the PHATE embeddings. Default is FALSE.
  1226. #' @param n_clusters An integer specifying the number of clusters to be identified. Default is "auto".
  1227. #' @param max_clusters An integer specifying the maximum number of clusters to test. Default is 100.
  1228. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "phate".
  1229. #' @param reduction.key A character string specifying the prefix for the column names of the PHATE embeddings. Default is "PHATE_".
  1230. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  1231. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  1232. #' @param ... Additional arguments to be passed to the phate.PHATE function.
  1233. #'
  1234. #' @examples
  1235. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  1236. #' pancreas_sub <- RunPHATE(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  1237. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "phate")
  1238. #'
  1239. #' @rdname RunPHATE
  1240. #' @export
  1241. RunPHATE <- function(object, ...) {
  1242. UseMethod(generic = "RunPHATE", object = object)
  1243. }
  1244. #' @rdname RunPHATE
  1245. #' @method RunPHATE Seurat
  1246. #' @importFrom Seurat LogSeuratCommand
  1247. #' @export
  1248. RunPHATE.Seurat <- function(object, reduction = "pca", dims = NULL, features = NULL,
  1249. assay = NULL, slot = "data",
  1250. n_components = 2, knn = 5, decay = 40, n_landmark = 2000, t = "auto", gamma = 1,
  1251. n_pca = 100, knn_dist = "euclidean", knn_max = NULL, t_max = 100,
  1252. do_cluster = FALSE, n_clusters = "auto", max_clusters = 100,
  1253. reduction.name = "phate", reduction.key = "PHATE_",
  1254. verbose = TRUE, seed.use = 11L, ...) {
  1255. if (sum(c(is.null(x = dims), is.null(x = features))) == 2) {
  1256. stop("Please specify only one of the following arguments: dims, features")
  1257. }
  1258. if (!is.null(x = features)) {
  1259. assay <- assay %||% DefaultAssay(object = object)
  1260. data.use <- as_matrix(t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
  1261. if (ncol(x = data.use) < n_components) {
  1262. stop(
  1263. "Please provide as many or more features than n_components: ",
  1264. length(x = features),
  1265. " features provided, ",
  1266. n_components,
  1267. " PHATE components requested",
  1268. call. = FALSE
  1269. )
  1270. }
  1271. } else if (!is.null(x = dims)) {
  1272. data.use <- Embeddings(object[[reduction]])[, dims]
  1273. assay <- DefaultAssay(object = object[[reduction]])
  1274. if (length(x = dims) < n_components) {
  1275. stop(
  1276. "Please provide as many or more dims than n_components: ",
  1277. length(x = dims),
  1278. " dims provided, ",
  1279. n_components,
  1280. " PHATE components requested",
  1281. call. = FALSE
  1282. )
  1283. }
  1284. } else {
  1285. stop("Please specify one of dims or features")
  1286. }
  1287. object[[reduction.name]] <- RunPHATE(
  1288. object = data.use, assay = assay,
  1289. n_components = n_components, knn = knn, decay = decay, n_landmark = n_landmark, t = t, gamma = gamma,
  1290. n_pca = n_pca, knn_dist = knn_dist, knn_max = knn_max, t_max = t_max,
  1291. do_cluster = do_cluster, n_clusters = n_clusters, max_clusters = max_clusters,
  1292. reduction.key = reduction.key, verbose = verbose, seed.use = seed.use
  1293. )
  1294. object <- LogSeuratCommand(object = object)
  1295. return(object)
  1296. }
  1297. #' @rdname RunPHATE
  1298. #' @method RunPHATE default
  1299. #' @importFrom reticulate import
  1300. #' @importFrom Seurat CreateDimReducObject Misc<- Misc
  1301. #' @export
  1302. RunPHATE.default <- function(object, assay = NULL,
  1303. n_components = 2, knn = 5, decay = 40, n_landmark = 2000, t = "auto", gamma = 1,
  1304. n_pca = 100, knn_dist = "euclidean", knn_max = NULL, t_max = 100,
  1305. do_cluster = FALSE, n_clusters = "auto", max_clusters = 100,
  1306. reduction.key = "PHATE_", verbose = TRUE, seed.use = 11L, ...) {
  1307. if (!is.null(x = seed.use)) {
  1308. set.seed(seed = seed.use)
  1309. }
  1310. check_Python("phate")
  1311. phate <- import("phate")
  1312. if (is.numeric(knn_max) && length(knn_max) > 0) {
  1313. knn_max <- as.integer(knn_max)
  1314. } else {
  1315. knn_max <- NULL
  1316. }
  1317. operator <- phate$PHATE(
  1318. n_components = as.integer(n_components),
  1319. knn = as.integer(knn),
  1320. decay = as.integer(decay),
  1321. n_landmark = as.integer(n_landmark),
  1322. t = as.character(t),
  1323. gamma = as.numeric(gamma),
  1324. n_pca = as.integer(n_pca),
  1325. knn_dist = as.character(knn_dist),
  1326. knn_max = knn_max,
  1327. random_state = as.integer(seed.use),
  1328. verbose = as.integer(verbose),
  1329. ...
  1330. )
  1331. embedding <- operator$fit_transform(object, t_max = as.integer(t_max))
  1332. colnames(x = embedding) <- paste0(reduction.key, seq_len(ncol(x = embedding)))
  1333. rownames(x = embedding) <- rownames(object)
  1334. reduction <- CreateDimReducObject(
  1335. embeddings = embedding,
  1336. key = reduction.key,
  1337. assay = assay,
  1338. global = TRUE
  1339. )
  1340. if (isTRUE(do_cluster)) {
  1341. if (is.numeric(n_clusters)) {
  1342. n_clusters <- as.integer(n_clusters)
  1343. }
  1344. if (is.numeric(max_clusters)) {
  1345. max_clusters <- as.integer(max_clusters)
  1346. }
  1347. clusters <- phate$cluster$kmeans(operator, n_clusters = n_clusters, max_clusters = max_clusters, random_state = as.integer(seed.use))
  1348. clusters <- clusters + 1
  1349. clusters <- factor(clusters, levels = sort(unique(clusters)))
  1350. names(clusters) <- rownames(embedding)
  1351. Misc(reduction, slot = "clusters") <- clusters
  1352. }
  1353. return(reduction)
  1354. }
  1355. #' Run TriMap (Large-scale Dimensionality Reduction Using Triplets)
  1356. #'
  1357. #' @param object An object. This can be a Seurat object or a matrix-like object.
  1358. #' @param reduction A character string specifying the reduction to be used. Default is "pca".
  1359. #' @param dims An integer vector specifying the dimensions to be used. Default is NULL.
  1360. #' @param features A character vector specifying the features to be used. Default is NULL.
  1361. #' @param assay A character string specifying the assay to be used. Default is NULL.
  1362. #' @param slot A character string specifying the slot name to be used. Default is "data".
  1363. #' @param n_components An integer specifying the number of TriMap components. Default is 2.
  1364. #' @param n_inliers An integer specifying the number of nearest neighbors for forming the nearest neighbor triplets. Default is 12.
  1365. #' @param n_outliers An integer specifying the number of outliers for forming the nearest neighbor triplets. Default is 4.
  1366. #' @param n_random An integer specifying the number of random triplets per point. Default is 3.
  1367. #' @param distance_method A character string specifying the distance metric for TriMap. Options are: "euclidean", "manhattan", "angular", "cosine", "hamming". Default is "euclidean".
  1368. #' @param lr A numeric value specifying the learning rate for TriMap. Default is 0.1.
  1369. #' @param n_iters An integer specifying the number of iterations for TriMap. Default is 400.
  1370. #' @param apply_pca A logical value indicating whether to apply PCA before the nearest-neighbor calculation. Default is TRUE.
  1371. #' @param opt_method A character string specifying the optimization method for TriMap. Options are: "dbd", "sd", "momentum". Default is "dbd".
  1372. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "trimap".
  1373. #' @param reduction.key A character string specifying the prefix for the column names of the TriMap embeddings. Default is "TriMap_".
  1374. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  1375. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  1376. #' @param ... Additional arguments to be passed to the trimap.TRIMAP function.
  1377. #'
  1378. #' @examples
  1379. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  1380. #' pancreas_sub <- RunTriMap(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  1381. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "trimap")
  1382. #'
  1383. #' @rdname RunTriMap
  1384. #' @export
  1385. RunTriMap <- function(object, ...) {
  1386. UseMethod(generic = "RunTriMap", object = object)
  1387. }
  1388. #' @rdname RunTriMap
  1389. #' @method RunTriMap Seurat
  1390. #' @importFrom Seurat LogSeuratCommand
  1391. #' @export
  1392. RunTriMap.Seurat <- function(object, reduction = "pca", dims = NULL, features = NULL,
  1393. assay = NULL, slot = "data",
  1394. n_components = 2, n_inliers = 12, n_outliers = 4, n_random = 3, distance_method = "euclidean",
  1395. lr = 0.1, n_iters = 400,
  1396. apply_pca = TRUE, opt_method = "dbd",
  1397. reduction.name = "trimap", reduction.key = "TriMap_",
  1398. verbose = TRUE, seed.use = 11L, ...) {
  1399. if (sum(c(is.null(x = dims), is.null(x = features))) == 2) {
  1400. stop("Please specify only one of the following arguments: dims, features")
  1401. }
  1402. if (!is.null(x = features)) {
  1403. assay <- assay %||% DefaultAssay(object = object)
  1404. data.use <- as_matrix(t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
  1405. if (ncol(x = data.use) < n_components) {
  1406. stop(
  1407. "Please provide as many or more features than n_components: ",
  1408. length(x = features),
  1409. " features provided, ",
  1410. n_components,
  1411. " TriMap components requested",
  1412. call. = FALSE
  1413. )
  1414. }
  1415. } else if (!is.null(x = dims)) {
  1416. data.use <- Embeddings(object[[reduction]])[, dims]
  1417. assay <- DefaultAssay(object = object[[reduction]])
  1418. if (length(x = dims) < n_components) {
  1419. stop(
  1420. "Please provide as many or more dims than n_components: ",
  1421. length(x = dims),
  1422. " dims provided, ",
  1423. n_components,
  1424. " TriMap components requested",
  1425. call. = FALSE
  1426. )
  1427. }
  1428. } else {
  1429. stop("Please specify one of dims, features")
  1430. }
  1431. object[[reduction.name]] <- RunTriMap(
  1432. object = data.use, assay = assay,
  1433. n_components = n_components, n_inliers = n_inliers, n_outliers = n_outliers, n_random = n_random, distance_method = distance_method,
  1434. lr = lr, n_iters = n_iters,
  1435. apply_pca = apply_pca, opt_method = opt_method,
  1436. reduction.key = reduction.key, verbose = verbose, seed.use = seed.use
  1437. )
  1438. object <- LogSeuratCommand(object = object)
  1439. return(object)
  1440. }
  1441. #' @rdname RunTriMap
  1442. #' @method RunTriMap default
  1443. #' @importFrom reticulate import
  1444. #' @importFrom Seurat CreateDimReducObject Misc<- Misc
  1445. #' @export
  1446. RunTriMap.default <- function(object, assay = NULL,
  1447. n_components = 2, n_inliers = 12, n_outliers = 4, n_random = 3, distance_method = "euclidean",
  1448. lr = 0.1, n_iters = 400,
  1449. apply_pca = TRUE, opt_method = "dbd",
  1450. reduction.key = "TriMap_", verbose = TRUE, seed.use = 11L, ...) {
  1451. if (!is.null(x = seed.use)) {
  1452. set.seed(seed = seed.use)
  1453. }
  1454. check_Python("trimap")
  1455. trimap <- import("trimap")
  1456. operator <- trimap$TRIMAP(
  1457. n_dims = as.integer(n_components), n_inliers = as.integer(n_inliers), n_outliers = as.integer(n_outliers), n_random = as.integer(n_random), distance = distance_method,
  1458. lr = lr, n_iters = as.integer(n_iters),
  1459. apply_pca = apply_pca, opt_method = opt_method, verbose = verbose, ...
  1460. )
  1461. embedding <- operator$fit_transform(object)
  1462. colnames(x = embedding) <- paste0(reduction.key, seq_len(ncol(x = embedding)))
  1463. if (inherits(x = object, what = "dist")) {
  1464. rownames(x = embedding) <- attr(object, "Labels")
  1465. } else {
  1466. rownames(x = embedding) <- rownames(object)
  1467. }
  1468. reduction <- CreateDimReducObject(
  1469. embeddings = embedding,
  1470. key = reduction.key, assay = assay, global = TRUE
  1471. )
  1472. return(reduction)
  1473. }
  1474. #' Run LargeVis (Dimensionality Reduction with a LargeVis-like method)
  1475. #'
  1476. #' @inheritParams uwot::lvish
  1477. #' @param object An object. This can be a Seurat object or a matrix-like object.
  1478. #' @param reduction A character string specifying the reduction to be used. Default is "pca".
  1479. #' @param dims An integer vector specifying the dimensions to be used. Default is NULL.
  1480. #' @param features A character vector specifying the features to be used. Default is NULL.
  1481. #' @param assay A character string specifying the assay to be used. Default is NULL.
  1482. #' @param slot A character string specifying the slot name to be used. Default is "data".
  1483. #' @param n_components An integer specifying the number of LargeVis components. Default is 2.
  1484. #' @param pca_method Method to carry out any PCA dimensionality reduction when the pca parameter is specified. Allowed values are: "irlba", "rsvd", "bigstatsr", "svd", "auto"(the default. Uses "irlba", unless more than 50 case "svd" is used.)
  1485. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "largevis".
  1486. #' @param reduction.key A character string specifying the prefix for the column names of the LargeVis embeddings. Default is "LargeVis_".
  1487. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  1488. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  1489. #' @param ... Additional arguments to be passed to the \link[uwot]{lvish} function.
  1490. #'
  1491. #' @examples
  1492. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  1493. #' pancreas_sub <- RunLargeVis(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  1494. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "largevis")
  1495. #'
  1496. #' @rdname RunLargeVis
  1497. #' @export
  1498. #'
  1499. RunLargeVis <- function(object, ...) {
  1500. UseMethod(generic = "RunLargeVis", object = object)
  1501. }
  1502. #' @rdname RunLargeVis
  1503. #' @method RunLargeVis Seurat
  1504. #' @importFrom Seurat LogSeuratCommand
  1505. #' @export
  1506. RunLargeVis.Seurat <- function(object, reduction = "pca", dims = NULL, features = NULL,
  1507. assay = NULL, slot = "data",
  1508. perplexity = 50, n_neighbors = perplexity * 3, n_components = 2, metric = "euclidean",
  1509. n_epochs = -1, learning_rate = 1, scale = "maxabs", init = "lvrandom", init_sdev = NULL,
  1510. repulsion_strength = 7, negative_sample_rate = 5, nn_method = NULL, n_trees = 50,
  1511. search_k = 2 * n_neighbors * n_trees, n_threads = NULL, n_sgd_threads = 0, grain_size = 1,
  1512. kernel = "gauss", pca = NULL, pca_center = TRUE, pcg_rand = TRUE, fast_sgd = FALSE,
  1513. batch = FALSE, opt_args = NULL, epoch_callback = NULL, pca_method = NULL,
  1514. reduction.name = "largevis", reduction.key = "LargeVis_",
  1515. verbose = TRUE, seed.use = 11L, ...) {
  1516. if (sum(c(is.null(x = dims), is.null(x = features))) == 3) {
  1517. stop("Please specify only one of the following arguments: dims, features")
  1518. }
  1519. if (!is.null(x = features)) {
  1520. assay <- assay %||% DefaultAssay(object = object)
  1521. data.use <- as_matrix(t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
  1522. if (ncol(x = data.use) < n_components) {
  1523. stop(
  1524. "Please provide as many or more features than n_components: ",
  1525. length(x = features),
  1526. " features provided, ",
  1527. n_components,
  1528. " LargeVis components requested",
  1529. call. = FALSE
  1530. )
  1531. }
  1532. } else if (!is.null(x = dims)) {
  1533. data.use <- Embeddings(object[[reduction]])[, dims]
  1534. assay <- DefaultAssay(object = object[[reduction]])
  1535. if (length(x = dims) < n_components) {
  1536. stop(
  1537. "Please provide as many or more dims than n_components: ",
  1538. length(x = dims),
  1539. " dims provided, ",
  1540. n_components,
  1541. " LargeVis components requested",
  1542. call. = FALSE
  1543. )
  1544. }
  1545. } else {
  1546. stop("Please specify one of dims, features")
  1547. }
  1548. object[[reduction.name]] <- RunLargeVis(
  1549. object = data.use, assay = assay,
  1550. perplexity = perplexity, n_neighbors = n_neighbors, n_components = n_components, metric = metric,
  1551. n_epochs = n_epochs, learning_rate = learning_rate, scale = scale, init = init, init_sdev = init_sdev,
  1552. repulsion_strength = repulsion_strength, negative_sample_rate = negative_sample_rate, nn_method = nn_method, n_trees = n_trees,
  1553. search_k = search_k, n_threads = n_threads, n_sgd_threads = n_sgd_threads, grain_size = grain_size,
  1554. kernel = kernel, pca = pca, pca_center = pca_center, pcg_rand = pcg_rand, fast_sgd = fast_sgd,
  1555. batch = batch, opt_args = opt_args, epoch_callback = epoch_callback, pca_method = pca_method,
  1556. reduction.key = reduction.key, verbose = verbose, seed.use = seed.use
  1557. )
  1558. object <- LogSeuratCommand(object = object)
  1559. return(object)
  1560. }
  1561. #' @rdname RunLargeVis
  1562. #' @method RunLargeVis default
  1563. #' @importFrom Seurat CreateDimReducObject
  1564. #' @export
  1565. RunLargeVis.default <- function(object, assay = NULL,
  1566. perplexity = 50, n_neighbors = perplexity * 3, n_components = 2, metric = "euclidean",
  1567. n_epochs = -1, learning_rate = 1, scale = "maxabs", init = "lvrandom", init_sdev = NULL,
  1568. repulsion_strength = 7, negative_sample_rate = 5, nn_method = NULL, n_trees = 50,
  1569. search_k = 2 * n_neighbors * n_trees, n_threads = NULL, n_sgd_threads = 0, grain_size = 1,
  1570. kernel = "gauss", pca = NULL, pca_center = TRUE, pcg_rand = TRUE, fast_sgd = FALSE,
  1571. batch = FALSE, opt_args = NULL, epoch_callback = NULL, pca_method = NULL,
  1572. reduction.key = "LargeVis_", verbose = TRUE, seed.use = 11L, ...) {
  1573. if (!is.null(x = seed.use)) {
  1574. set.seed(seed = seed.use)
  1575. }
  1576. embedding <- uwot::lvish(
  1577. X = object, perplexity = perplexity, n_neighbors = n_neighbors, n_components = n_components, metric = metric,
  1578. n_epochs = n_epochs, learning_rate = learning_rate, scale = scale, init = init, init_sdev = init_sdev,
  1579. repulsion_strength = repulsion_strength, negative_sample_rate = negative_sample_rate, nn_method = nn_method, n_trees = n_trees,
  1580. search_k = search_k, n_threads = n_threads, n_sgd_threads = n_sgd_threads, grain_size = grain_size,
  1581. kernel = kernel, pca = pca, pca_center = pca_center, pcg_rand = pcg_rand, fast_sgd = fast_sgd,
  1582. verbose = verbose, batch = batch, opt_args = opt_args, epoch_callback = epoch_callback, pca_method = pca_method,
  1583. ...
  1584. )
  1585. colnames(x = embedding) <- paste0(reduction.key, seq_len(ncol(x = embedding)))
  1586. if (inherits(x = object, what = "dist")) {
  1587. rownames(x = embedding) <- attr(object, "Labels")
  1588. } else {
  1589. rownames(x = embedding) <- rownames(object)
  1590. }
  1591. reduction <- CreateDimReducObject(
  1592. embeddings = embedding,
  1593. key = reduction.key, assay = assay, global = TRUE
  1594. )
  1595. return(reduction)
  1596. }
  1597. #' Run Force-Directed Layout (Fruchterman-Reingold algorithm)
  1598. #'
  1599. #' @param object An object. This can be a Seurat object, a Neighbor object, or a Graph object.
  1600. #' @param reduction A character string specifying the reduction to be used. Default is NULL.
  1601. #' @param dims An integer vector specifying the dimensions to be used. Default is NULL.
  1602. #' @param features A character vector specifying the features to be used. Default is NULL.
  1603. #' @param assay A character string specifying the assay to be used. Default is NULL.
  1604. #' @param slot A character string specifying the slot name to be used. Default is "data".
  1605. #' @param graph A character string specifying the name of the Graph object to be used. Default is NULL.
  1606. #' @param neighbor A character string specifying the name of the Neighbor object to be used. Default is NULL.
  1607. #' @param k.param An integer specifying the number of nearest neighbors to consider. Default is 20.
  1608. #' @param ndim An integer specifying the number of dimensions for the force-directed layout. Default is 2.
  1609. #' @param niter An integer specifying the number of iterations for the force-directed layout. Default is 500.
  1610. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "fr".
  1611. #' @param reduction.key A character string specifying the prefix for the column names of the force-directed layout embeddings. Default is "FR_".
  1612. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  1613. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  1614. #' @param ... Additional arguments to be passed to the \link[igraph]{layout_with_fr} function.
  1615. #'
  1616. #' @examples
  1617. #' pancreas_sub <- Seurat::FindVariableFeatures(pancreas_sub)
  1618. #' pancreas_sub <- RunFR(object = pancreas_sub, features = Seurat::VariableFeatures(pancreas_sub))
  1619. #' CellDimPlot(pancreas_sub, group.by = "CellType", reduction = "fr")
  1620. #'
  1621. #' @rdname RunFR
  1622. #' @export
  1623. RunFR <- function(object, ...) {
  1624. UseMethod(generic = "RunFR", object = object)
  1625. }
  1626. #' @rdname RunFR
  1627. #' @method RunFR Seurat
  1628. #' @importFrom Seurat LogSeuratCommand DefaultAssay
  1629. #' @export
  1630. RunFR.Seurat <- function(object, reduction = NULL, dims = NULL, features = NULL,
  1631. assay = NULL, slot = "data",
  1632. graph = NULL, neighbor = NULL,
  1633. k.param = 20, ndim = 2, niter = 500,
  1634. reduction.name = "FR", reduction.key = "FR_",
  1635. verbose = TRUE, seed.use = 11L, ...) {
  1636. if (sum(c(is.null(x = dims), is.null(x = features), is.null(neighbor), is.null(x = graph))) == 4) {
  1637. stop("Please specify only one of the following arguments: dims, features, neighbor or graph")
  1638. }
  1639. if (!is.null(x = graph)) {
  1640. if (!inherits(x = object[[graph]], what = "Graph")) {
  1641. stop(
  1642. "Please specify a Graph object name, ",
  1643. "instead of the name of a ",
  1644. class(object[[graph]]),
  1645. " object",
  1646. call. = FALSE
  1647. )
  1648. }
  1649. data.use <- object[[graph]]
  1650. } else if (!is.null(x = neighbor)) {
  1651. if (!inherits(x = object[[neighbor]], what = "Neighbor")) {
  1652. stop(
  1653. "Please specify a Neighbor object name, ",
  1654. "instead of the name of a ",
  1655. class(object[[neighbor]]),
  1656. " object",
  1657. call. = FALSE
  1658. )
  1659. }
  1660. data.use <- object[[neighbor]]
  1661. } else if (!is.null(x = features)) {
  1662. assay <- assay %||% DefaultAssay(object = object)
  1663. data.use <- t(GetAssayData(object = object, slot = slot, assay = assay)[features, ])
  1664. data.use <- FindNeighbors(data.use, k.param = k.param)[["snn"]]
  1665. } else if (!is.null(x = dims)) {
  1666. data.use <- Embeddings(object = object[[reduction]])
  1667. if (max(dims) > ncol(x = data.use)) {
  1668. stop("More dimensions specified in dims than have been computed")
  1669. }
  1670. data.use <- data.use[, dims]
  1671. data.use <- FindNeighbors(data.use, k.param = k.param)[["snn"]]
  1672. } else {
  1673. stop("Please specify one of dims, features, neighbor, or graph")
  1674. }
  1675. object[[reduction.name]] <- RunFR(
  1676. object = data.use, ndim = ndim, niter = niter,
  1677. seed.use = seed.use, verbose = verbose, reduction.key = reduction.key,
  1678. ...
  1679. )
  1680. object <- LogSeuratCommand(object = object)
  1681. return(object)
  1682. }
  1683. #' @rdname RunFR
  1684. #' @method RunFR default
  1685. #' @importFrom Seurat CreateDimReducObject as.Graph
  1686. #' @importFrom igraph graph_from_adjacency_matrix layout_with_fr
  1687. #' @export
  1688. RunFR.default <- function(object, ndim = 2, niter = 500,
  1689. reduction.key = "FR_", verbose = TRUE, seed.use = 11L, ...) {
  1690. if (!is.null(x = seed.use)) {
  1691. set.seed(seed = seed.use)
  1692. }
  1693. if (inherits(object, "Neighbor")) {
  1694. object <- as.Graph(object)
  1695. }
  1696. g <- graph_from_adjacency_matrix(object, weighted = TRUE)
  1697. embedding <- layout_with_fr(graph = g, dim = ndim, niter = niter, ...)
  1698. colnames(x = embedding) <- paste0(reduction.key, seq_len(ncol(x = embedding)))
  1699. rownames(x = embedding) <- rownames(object)
  1700. reduction <- CreateDimReducObject(
  1701. embeddings = embedding,
  1702. key = reduction.key, assay = [email hidden], global = TRUE
  1703. )
  1704. return(reduction)
  1705. }
  1706. #' Run Harmony algorithm
  1707. #'
  1708. #' This is a modified version of harmony::RunHarmony specifically designed for compatibility with RunSymphonyMap.
  1709. #'
  1710. #' @param object A Seurat object.
  1711. #' @param group.by.vars A character vector specifying the batch variable name.
  1712. #' @param reduction A character string specifying the reduction to be used. Default is "pca".
  1713. #' @param dims.use An integer vector specifying the dimensions to be used. Default is 1:30.
  1714. #' @param reduction.name A character string specifying the name of the reduction to be stored in the Seurat object. Default is "Harmony".
  1715. #' @param reduction.key A character string specifying the prefix for the column names of the Harmony embeddings. Default is "Harmony_".
  1716. #' @param project.dim A logical value indicating whether to project dimension reduction loadings. Default is TRUE.
  1717. #' @param verbose A logical value indicating whether to print verbose output. Default is TRUE.
  1718. #' @param seed.use An integer specifying the random seed to be used. Default is 11.
  1719. #' @param ... Additional arguments to be passed to the \link[harmony]{RunHarmony} function.
  1720. #'
  1721. #' @examples
  1722. #' panc8_sub <- Standard_SCP(panc8_sub)
  1723. #' panc8_sub <- RunHarmony2(panc8_sub, group.by.vars = "tech", reduction = "Standardpca")
  1724. #' CellDimPlot(panc8_sub, group.by = c("tech", "celltype"), reduction = "Standardpca")
  1725. #' CellDimPlot(panc8_sub, group.by = c("tech", "celltype"), reduction = "Harmony")
  1726. #'
  1727. #' @rdname RunHarmony2
  1728. #' @export
  1729. RunHarmony2 <- function(object, ...) {
  1730. UseMethod(generic = "RunHarmony2", object = object)
  1731. }
  1732. #' @rdname RunHarmony2
  1733. #' @method RunHarmony2 Seurat
  1734. #' @importFrom Seurat Embeddings RunPCA FetchData CreateDimReducObject ProjectDim LogSeuratCommand
  1735. #' @importFrom methods slot
  1736. #' @importFrom stats sd
  1737. #' @export
  1738. RunHarmony2.Seurat <- function(object, group.by.vars,
  1739. reduction = "pca", dims.use = 1:30,
  1740. project.dim = TRUE,
  1741. reduction.name = "Harmony", reduction.key = "Harmony_",
  1742. verbose = TRUE, seed.use = 11L, ...) {
  1743. check_R("harmony@1.1.0")
  1744. if (!is.null(x = seed.use)) {
  1745. set.seed(seed = seed.use)
  1746. }
  1747. if (length(dims.use) == 1) {
  1748. stop("only specified one dimension in dims.use")
  1749. }
  1750. data.use <- Embeddings(object[[reduction]])
  1751. if (max(dims.use) > ncol(data.use)) {
  1752. stop("trying to use more dimensions than computed")
  1753. }
  1754. assay <- DefaultAssay(object = object[[reduction]])
  1755. metavars_df <- FetchData(object, group.by.vars, cells = rownames(data.use))
  1756. harmonyObject <- harmony::RunHarmony(
  1757. data_mat = data.use[, dims.use, drop = FALSE],
  1758. meta_data = metavars_df,
  1759. vars_use = group.by.vars,
  1760. verbose = verbose,
  1761. return_object = TRUE,
  1762. ...
  1763. )
  1764. harmonyEmbed <- t(as_matrix(harmonyObject$Z_corr))
  1765. rownames(harmonyEmbed) <- row.names(data.use)
  1766. colnames(harmonyEmbed) <- paste0(reduction.name, "_", seq_len(ncol(harmonyEmbed)))
  1767. harmonyClusters <- t(harmonyObject$R)
  1768. rownames(harmonyClusters) <- row.names(data.use)
  1769. colnames(harmonyClusters) <- paste0("R", seq_len(ncol(harmonyClusters)))
  1770. object[[reduction.name]] <- CreateDimReducObject(
  1771. embeddings = harmonyEmbed,
  1772. stdev = as.numeric(apply(harmonyEmbed, 2, sd)),
  1773. assay = assay,
  1774. key = reduction.key,
  1775. misc = list(
  1776. R = harmonyClusters,
  1777. reduction_use = reduction,
  1778. reduction_dims = dims.use
  1779. )
  1780. )
  1781. if (project.dim) {
  1782. object <- ProjectDim(
  1783. object,
  1784. reduction = reduction.name,
  1785. overwrite = TRUE,
  1786. verbose = FALSE
  1787. )
  1788. }
  1789. object <- LogSeuratCommand(object = object)
  1790. return(object)
  1791. }

Seurat-function.R at commit b9b0eb7, under GPL-3.0 · at the source

Overview

Authors: Yuanhao Wang1,2, Xu Zhang1,2, Ru Ba3, Yimin Zhu1, Hanwen Yu1, Da Wang1, Chu Chu1, Xinyue Zhang1,2, Yuan Hong1,4, Shanshan Wu1, Wanying Zhu1, Min Xu1, Qing Cheng5, Chunjie Zhao3,6, Xiao Han1,2,4, Yan Liu1,2,4
  1. Institute of Stem Cell and Neural Regeneration, School of Pharmacy, Nanjing Medical University, Nanjing 211166, China
  2. Interdisciplinary InnoCenter for Organoids, State Key Laboratory of Reproductive Medicine and Offspring Health, Nanjing Medical University, Nanjing 211166, China
  3. Department of histology and embryology, School of Medicine, Southeast University, Nanjing 210009, China
  4. State Key Laboratory of Reproductive Medicine (Suzhou Centre), The Affiliated Suzhou Hospital of Nanjing Medical University, Suzhou Municipal Hospital, Gusu School, Innovation Center of Suzhou, Nanjing Medical University, Suzhou 215000, China
  5. Department of Obstetrics and Gynecology, Women’s Hospital of Nanjing Medical University, Nanjing Women and Children’s Healthcare Hospital, Nanjing Medical University, Nanjing 210004, China
  6. Department of Anesthesiology, Surgery and Pain Management and Key Laboratory of Clinical Science and Research, Zhongda Hospital, Southeast University, Nanjing 210009, China
Dates: received 21 August 2025; accepted 6 March 2026; published online 15 April 2026; in print 21 April 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1073/pnas.2523130123 · PMID 41984827 · PMCID PMC13099611 · OpenAlex W7154483619
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: human (organism), mouse (organism), autism (population)
Keywords: FABP7, radial glial scaffold, brain organoids, mevalonate pathway, autism
MeSH: Cerebral Cortex*, Ependymoglial Cells*, Fatty Acid-Binding Protein 7*, Nerve Tissue Proteins*, Animals, Autistic Disorder, Humans, Mice, Neurodevelopment, Neurons, Tumor Suppressor Proteins (* major topic)
Topic: Neurogenesis and neuroplasticity mechanisms (Developmental Neuroscience, Neuroscience), according to OpenAlex
Funding: MOST | National Key Research and Development Program of China (NKPs) (2022YFA1104800, 2023YFF1203600, 2021YFA1101800); Joint Project of the Yangtze River Delta Science and Technology Innovation Community (2024CSJZN0600); | Natural Science Research of Jiangsu Higher Education Institutions of China (Natural Sciences Fund for Colleges and Universities in Jiangsu Province) (23KJB180019); MOST | National Natural Science Foundation of China (32470872, 22274079, 82401794, 82530038, (82325015 82171528); JST | Jiangsu Natural Science Foundation | Basic Research Program of Jiangsu Province (BK20251255); JST | Natural Science Foundation of Jiangsu Province (BK20240131); 江苏省教育厅 | Natural Science Research of Jiangsu Higher Education Institutions of China (23KJB180019)
Citations: cited by 3 papers (Europe PMC); 52 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

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

chuiqin/irGSEA

License: other
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: f83affd9ca1556328e5158a2cb740167527793c1, 15 January 2026
Languages: R (17), JavaScript (3), Python (3)
Size: 103 files, 23 scripts
Software Heritage: not archived
Found in: “Data, Materials, and Software Availability”
Holds: README, license file, environment (DESCRIPTION), documentation, 1 notebook
Not found: CITATION.cff, tests, continuous integration
Tools: tidyverse (14 files), Seurat (10 files), ggplot2 (7 files), ComplexHeatmap (4 files), NumPy (3 files), pandas (3 files), Scanpy (3 files), SciPy (3 files), reticulate (2 files), circlize (1 file), clusterProfiler (1 file), cowplot (1 file), edgeR (1 file), reshape2 (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
26 files

zhanghao-njmu/SCP

License: GPL-3.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: b9b0eb7a7bf2c2c4b2262e73e09d7ebd515c7da0, 21 November 2023
Languages: R (17), Python (2), C++ (2)
Size: 233 files, 21 scripts
Software Heritage: not archived
Found in: the references
Holds: README, license file, environment (DESCRIPTION), continuous integration, documentation, 1 notebook
Not found: CITATION.cff, tests
Tools: Seurat (8 files), reticulate (5 files), ggplot2 (4 files), tidyverse (4 files), igraph (2 files), NumPy (2 files), pandas (2 files), reshape2 (2 files), clusterProfiler (1 file), cowplot (1 file), data.table (1 file), ggpubr (1 file), Harmony (1 file), limma (1 file), Matplotlib (1 file), patchwork (1 file), Plotly (1 file), Scanpy (1 file), SciPy (1 file), scVelo (1 file), UMAP (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
23 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;
  • 44 scripts, each with its path and the digest of its content;
  • 1 match 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

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1073/pnas.2523130123.

Versions

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

Version 1, 29 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 16 authors, 5 keywords, 11 MeSH terms, 7 funders, 45 references.

Cite

This paper

Wang, Y., Zhang, X., Ba, R., Zhu, Y., Yu, H., Wang, D., Chu, C., Zhang, X., Hong, Y., Wu, S., Zhu, W., Xu, M., Cheng, Q., Zhao, C., Han, X., & Liu, Y. (2026). FABP7 controls radial glial scaffold stability during human cortical development. Proceedings of the National Academy of Sciences of the United States of America, 123(16), e2523130123. https://doi.org/10.1073/pnas.2523130123

BibTeX

@article{wang2026fabp7,
author = {Wang, Yuanhao and Zhang, Xu and Ba, Ru and Zhu, Yimin and Yu, Hanwen and Wang, Da and Chu, Chu and Zhang, Xinyue and Hong, Yuan and Wu, Shanshan and Zhu, Wanying and Xu, Min and Cheng, Qing and Zhao, Chunjie and Han, Xiao and Liu, Yan},
title = {{FABP7 controls radial glial scaffold stability during human cortical development}},
journal = {Proceedings of the National Academy of Sciences of the United States of America},
year = {2026},
month = apr,
volume = {123},
number = {16},
pages = {e2523130123},
publisher = {National Academy of Sciences},
issn = {0027-8424},
doi = {10.1073/pnas.2523130123},
url = {https://doi.org/10.1073/pnas.2523130123},
pmid = {41984827},
pmcid = {PMC13099611}
}

RIS

TY - JOUR
AU - Wang, Yuanhao
AU - Zhang, Xu
AU - Ba, Ru
AU - Zhu, Yimin
AU - Yu, Hanwen
AU - Wang, Da
AU - Chu, Chu
AU - Zhang, Xinyue
AU - Hong, Yuan
AU - Wu, Shanshan
AU - Zhu, Wanying
AU - Xu, Min
AU - Cheng, Qing
AU - Zhao, Chunjie
AU - Han, Xiao
AU - Liu, Yan
TI - FABP7 controls radial glial scaffold stability during human cortical development
T2 - Proceedings of the National Academy of Sciences of the United States of America
J2 - Proc Natl Acad Sci U S A
PY - 2026
DA - 2026/04/15
VL - 123
IS - 16
SP - e2523130123
SN - 0027-8424
PB - National Academy of Sciences
DO - 10.1073/pnas.2523130123
UR - https://doi.org/10.1073/pnas.2523130123
LA - en
ER -

CSL-JSON

{
"id": "10.1073/pnas.2523130123",
"type": "article-journal",
"title": "FABP7 controls radial glial scaffold stability during human cortical development",
"container-title": "Proceedings of the National Academy of Sciences of the United States of America",
"author": [
{
"family": "Wang",
"given": "Yuanhao"
},
{
"family": "Zhang",
"given": "Xu"
},
{
"family": "Ba",
"given": "Ru"
},
{
"family": "Zhu",
"given": "Yimin"
},
{
"family": "Yu",
"given": "Hanwen"
},
{
"family": "Wang",
"given": "Da"
},
{
"family": "Chu",
"given": "Chu"
},
{
"family": "Zhang",
"given": "Xinyue"
},
{
"family": "Hong",
"given": "Yuan"
},
{
"family": "Wu",
"given": "Shanshan"
},
{
"family": "Zhu",
"given": "Wanying"
},
{
"family": "Xu",
"given": "Min"
},
{
"family": "Cheng",
"given": "Qing"
},
{
"family": "Zhao",
"given": "Chunjie"
},
{
"family": "Han",
"given": "Xiao"
},
{
"family": "Liu",
"given": "Yan"
}
],
"container-title-short": "Proc Natl Acad Sci U S A",
"volume": "123",
"issue": "16",
"page": "e2523130123",
"DOI": "10.1073/pnas.2523130123",
"PMID": "41984827",
"PMCID": "PMC13099611",
"ISSN": "0027-8424",
"publisher": "National Academy of Sciences",
"URL": "https://doi.org/10.1073/pnas.2523130123",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
15
]
]
}
}

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

Similar papers

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

[1] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: scVelo, Harmony, edgeR, 20 other tools
[2] doi:10.1002/imt2.70163 [code]
Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.
Journal: iMeta
In common: Harmony, edgeR, limma, 18 other tools, mouse
[3] doi:10.1038/s41586-026-10214-2 [code]
Multidimensional profiling of heterogeneity in supratentorial ependymomas.
Journal: Nature
In common: Harmony, edgeR, reticulate, 17 other tools, mouse
[4] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: edgeR, reticulate, limma, 17 other tools, mouse
[5] doi:10.1016/j.cpblue.2026.100007 [code]
An integrated single-cell and spatial proteotranscriptomics atlas of fibroblast-driven immunoregulation within the human adult oral cavity.
Journal: Cell press blue
In common: edgeR, reticulate, limma, 17 other tools
[6] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: edgeR, reticulate, limma, 17 other tools
[7] doi:10.1038/s41586-026-10629-x [code]
Whole-genome duplication shaped cell-type evolution in the vertebrate brain.
Journal: Nature
In common: scVelo, Harmony, reticulate, 16 other tools, mouse
[8] doi:10.1016/j.xcrm.2026.102651 [code]
Integrative CSF profiling identifies disease-specific immune responses in leptomeningeal disease.
Journal: Cell reports. Medicine
In common: Harmony, reticulate, UMAP, 17 other tools
[9] doi:10.3390/ijms27104466 [code]
Uncovering the Key Circuit FOSL2/FOS/EGR3/EGR1, Contributing to the Hyperexcitability of Excitatory Neurons in the Epileptic Temporal Cortex and Hippocampus.
Journal: International journal of molecular sciences
In common: reticulate, limma, UMAP, 15 other tools
[10] doi:10.1038/s41593-026-02367-0 [code]
A reproducible three-dimensional model of human brain tissue to investigate physiological and disease-associated microglia phenotypes.
Journal: Nature neuroscience
In common: Harmony, edgeR, reticulate, 13 other tools, 1 reference

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.