Source: TBA

Introduction

TMT Proteomics Analysis Workflow

# 1. Install packages (run once)
install.packages(c("tidyverse","readr","janitor","pheatmap","ggplot2"))
install.packages("BiocManager")
BiocManager::install(c("limma","clusterProfiler","org.Hs.eg.db"))

Load libraries

library("dplyr")
library("tidyverse")
library("readr")
library("janitor")
library("limma")
library("pheatmap")
library("clusterProfiler")
library("org.Hs.eg.db")
library("ggplot2")
library("kableExtra")
library("beeswarm")
library("mitch")
library("gplots")
## 
## ---------------------
## gplots 3.3.0 loaded:
##   * Use citation('gplots') for citation info.
##   * Homepage: https://talgalili.github.io/gplots/
##   * Report issues: https://github.com/talgalili/gplots/issues
##   * Ask questions: https://stackoverflow.com/questions/tagged/gplots
##   * Suppress this message with: suppressPackageStartupMessages(library(gplots))
## ---------------------
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:IRanges':
## 
##     space
## The following object is masked from 'package:S4Vectors':
## 
##     space
## The following object is masked from 'package:stats':
## 
##     lowess

Load FragPipe files

plexA <- read_tsv("abundance_protein_MD_plexA.tsv")
## Rows: 963 Columns: 27
## ── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr  (8): Index, Gene, Protein, Protein ID, Entry Name, Protein Description,...
## dbl (19): NumberPSM, MaxPepProb, ReferenceIntensity, _126, _127N, _127C, _12...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
plexB <- read_tsv("abundance_protein_MD_plexB.tsv")
## Rows: 962 Columns: 27
## ── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr  (8): Index, Gene, Protein, Protein ID, Entry Name, Protein Description,...
## dbl (19): NumberPSM, MaxPepProb, ReferenceIntensity, _126, _127N, _127C, _12...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
plexA <- janitor::clean_names(plexA)
plexB <- janitor::clean_names(plexB)

Clean data

Keep relevant columns

Rename TMT channels to sample IDs

Merge Plex A and B.

plexA <- dplyr::select(plexA, protein, gene,
                       x126, x127n, x127c, x128n, x128c,
                       x129n, x129c, x130n, x130c,
                       x131n, x131c, x132n)

plexB <- dplyr::select(plexB, protein, gene,
                       x126, x127n, x127c, x128n, x128c,
                       x129n, x129c, x130n, x130c,
                       x131n, x131c, x132n)

# Rename TMT channels to sample IDs
annotationA <- c(
  x126="19191", x127n="34629", x127c="34862",
  x128n="40431", x128c="40475", x129n="35038",
  x129c="34866", x130n="41436", x130c="41383",
  x131n="40316", x131c="3746", x132n="102953"
)

annotationB <- c(
  x126="40797", x127n="4177", x127c="103376",
  x128n="47542", x128c="47442", x129n="42977",
  x129c="43081", x130n="113835", x130c="113856",
  x131n="19584", x131c="118117", x132n="118008"
)

colnames(plexA)[match(names(annotationA), colnames(plexA))] <- annotationA
colnames(plexB)[match(names(annotationB), colnames(plexB))] <- annotationB

# Merge Plex A and B
merged <- full_join(plexA, plexB, by=c("protein","gene"))

head(merged) %>%
  kbl(caption="Proteomic data from fragpipe") %>%
  kable_paper("hover", full_width = F)
Proteomic data from fragpipe
protein gene 19191 34629 34862 40431 40475 35038 34866 41436 41383 40316 3746 102953 40797 4177 103376 47542 47442 42977 43081 113835 113856 19584 118117 118008
sp|A0A075B6H7|KV37_HUMAN IGKV3-7 25.20197 25.39573 25.43256 26.05771 25.05397 25.57650 25.65469 25.37295 25.65501 25.64185 25.43883 25.33301 30.46372 30.34873 30.21146 30.78558 30.36076 30.19026 30.28124 30.56661 29.76611 30.72821 30.20665 30.00076
sp|A0A075B6H9|LV469_HUMAN IGLV4-69 28.95035 29.82285 29.61003 29.53702 29.44966 28.84860 29.91425 29.41320 29.00432 28.83877 28.59919 29.14621 22.40007 21.18373 21.26245 21.90925 22.59531 21.24953 21.98843 21.22654 21.40015 22.00258 21.02142 21.46372
sp|A0A075B6I0|LV861_HUMAN IGLV8-61 27.53609 28.54878 26.58017 27.43782 27.43139 26.83964 27.26845 26.57449 28.21526 26.57432 26.75554 NA 25.58149 26.12823 26.52763 25.72071 26.59545 25.47399 26.13838 25.35584 25.89193 25.69072 25.72252 26.67365
sp|A0A075B6I1|LV460_HUMAN IGLV4-60 21.13980 NA 20.95866 21.90418 19.86279 21.18880 21.20105 20.12885 20.95064 21.09826 20.35881 NA 27.79615 26.93927 25.90896 26.48209 28.84106 26.96525 28.56674 27.15404 27.20759 27.49989 27.18150 27.81810
sp|A0A075B6J9|LV218_HUMAN IGLV2-18 22.38769 25.30212 25.12898 24.02298 23.89291 24.49498 24.70158 24.32961 24.30966 24.58185 23.43995 23.82350 27.34292 26.35223 24.59685 26.37291 25.30866 25.64357 26.10869 25.59368 27.73543 25.64763 26.16884 26.54800
sp|A0A075B6K0|LV316_HUMAN IGLV3-16 21.37483 22.29617 21.39598 21.69973 21.51293 23.78554 22.11370 22.61187 20.93010 22.14908 20.87886 20.41397 20.66449 22.03552 22.04962 21.69365 21.55941 21.37521 22.05910 22.66605 21.11006 20.78442 21.76661 21.22903
# Create expression matrix
expr <- as.data.frame(merged)
rownames(expr) <- paste(expr$gene,expr$protein)
expr$protein <- NULL
expr$gene <- NULL

Log transformation and normalisation

First log transform data and then filter protein, and do quantile normalisation.

# Log2 transform intensities
expr_log <- log2(expr + 1)

# Filter proteins (present in >=50% of samples)
keep <- rowSums(!is.na(expr_log)) >= ncol(expr_log)*0.5
expr_filtered <- expr_log[keep, ]

# Quantile normalization
expr_norm <- normalizeBetweenArrays(expr_filtered, method="quantile")

# QC: Missing value percentage
missing_percent <- colMeans(is.na(expr_norm))*100
print(missing_percent)
##    19191    34629    34862    40431    40475    35038    34866    41436 
## 10.28761 15.04425 12.38938 15.15487 15.04425 10.84071 10.95133 13.82743 
##    41383    40316     3746   102953    40797     4177   103376    47542 
## 12.50000 15.70796 11.83628 15.37611 15.26549 13.49558 21.01770 13.71681 
##    47442    42977    43081   113835   113856    19584   118117   118008 
## 19.13717 14.60177 14.15929 19.69027 15.04425 15.48673 19.57965 25.33186

QC analysis

Intensity distribution plot

expr_long <- as.data.frame(expr_norm) %>%
  pivot_longer(cols = everything(),
               names_to = "Sample",
               values_to = "Intensity") %>%
  filter(is.finite(Intensity))  # remove NA / Inf / -Inf

ggplot(expr_long, aes(x = Intensity)) +
  geom_density(fill = "steelblue", alpha = 0.4) +
  facet_wrap(~Sample) +
  theme_bw() +
  ggtitle("Intensity Distribution per Sample")

Combined intensity distribution plot

expr_long <- as.data.frame(expr_norm) %>%
  pivot_longer(cols = everything(),
               names_to = "Sample",
               values_to = "Intensity") %>%
  filter(is.finite(Intensity))  # remove NA/Inf/-Inf

ggplot(expr_long, aes(x = Intensity, color = Sample)) +
  geom_density(size = 1) +
  theme_bw() +
  ggtitle("Combined Intensity Distribution of All Samples") +
  xlab("Log2 Intensity") +
  ylab("Density")

QC: PCA plot

# Remove infinite values
expr_norm[is.infinite(expr_norm)] <- NA

# Impute missing values (median)
expr_pca <- expr_norm

for(i in 1:ncol(expr_pca)){
  expr_pca[is.na(expr_pca[,i]), i] <- median(expr_pca[,i], na.rm=TRUE)
}

# PCA
pca <- prcomp(t(expr_pca))

pca_df <- data.frame(
  PC1 = pca$x[,1],
  PC2 = pca$x[,2],
  Sample = colnames(expr_pca)
)

# Add group info
group <- factor(c(
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control"
))

pca_df$Group <- group

# Plot
library(ggplot2)

ggplot(pca_df, aes(PC1, PC2, color=Group, label=Sample)) +
  geom_point(size=3) +
  geom_text(vjust=1.5) +
  theme_bw() +
  ggtitle("PCA of Samples")

Sample correlation heatmap

cor_matrix <- cor(expr_norm, use="pairwise.complete.obs")
pheatmap(cor_matrix, main="Sample Correlation Heatmap")

Differential expression analysis

Set up the design matrix and then use limma to run the stat test.

group <- factor(c(
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control",
  "Case","Control","Case","Control"
))

design <- model.matrix(~group)
fit <- lmFit(expr_norm, design)
fit <- eBayes(fit)

results <- topTable(fit, coef=2, number=Inf)

head(results,20) %>%
  kbl(caption="Top 20 most significant differences") %>%
  kable_paper("hover", full_width = F)
Top 20 most significant differences
logFC AveExpr t P.Value adj.P.Val B
ENTPD5 sp|O75356|ENTP5_HUMAN -0.0824043 4.365370 -4.020203 0.0016686 0.5779301 -0.9514331
HSPD1 sp|P10809|CH60_HUMAN 0.1342293 4.276747 3.608039 0.0025558 0.5779301 -1.4393077
ITM2B sp|Q9Y287|ITM2B_HUMAN 0.0645200 4.304086 3.672916 0.0031434 0.5779301 -1.5269652
VPS29 sp|Q9UBQ0|VPS29_HUMAN 0.1115886 4.261511 3.661900 0.0032077 0.5779301 -1.5454004
CA3 sp|P07451|CAH3_HUMAN -0.1004160 4.445305 -3.516887 0.0041916 0.5779301 -1.7888697
ARRB1 sp|P49407|ARRB1_HUMAN -0.0981963 4.432147 -3.445170 0.0039019 0.5779301 -1.7967856
ITGA6 sp|P23229|ITA6_HUMAN 0.1266236 4.408744 3.419608 0.0050193 0.5779301 -1.9528870
PSMF1 sp|Q92530|PSMF1_HUMAN -0.1013330 4.080828 -3.409490 0.0051144 0.5779301 -1.9699710
INF2 sp|Q27J81|INF2_HUMAN 0.0964987 4.423766 3.100175 0.0068328 0.5854217 -2.3479025
TPM3 sp|P06753|TPM3_HUMAN 0.1232341 4.554235 3.088933 0.0092897 0.5854217 -2.5124136
DBN1 sp|Q16643|DREB_HUMAN 0.1015202 4.431206 3.081373 0.0094217 0.5854217 -2.5192803
PRCP sp|P42785|PCP_HUMAN -0.0731277 4.354974 -3.083102 0.0093913 0.5854217 -2.5222820
SFTPB sp|P07988|PSPB_HUMAN -0.0963832 4.417397 -3.057247 0.0098555 0.5854217 -2.5660301
CSF1R sp|P07333|CSF1R_HUMAN -0.0999052 4.385271 -2.938158 0.0123076 0.5854217 -2.7672585
DKK3 sp|Q9UBP4|DKK3_HUMAN 0.0734493 4.302518 2.932529 0.0124375 0.5854217 -2.7767533
PPM1F sp|P49593|PPM1F_HUMAN -0.1030720 4.160987 -2.927306 0.0125593 0.5854217 -2.7855632
IGKV2D-29 sp|A0A075B6S2|KVD29_HUMAN -0.0745215 4.784014 -2.923371 0.0126518 0.5854217 -2.7922006
IGF1 sp|P05019|IGF1_HUMAN -0.0548494 4.515201 -2.910803 0.0129518 0.5854217 -2.8133887
ARPC4 sp|P59998|ARPC4_HUMAN 0.1267741 4.507737 2.853209 0.0126876 0.5854217 -2.8552706
GM2A sp|P17900|SAP3_HUMAN -0.0676636 4.384216 -2.838208 0.0148284 0.6362363 -2.9355862
saveRDS(results,"DE_results.rds")
write.csv(results, "Differential_expression_results.csv")

Volcano plot

ggplot(results, aes(x=logFC, y=-log10(P.Value))) +
  geom_point(alpha=0.6) +
  theme_bw() +
  xlab("log2 Fold Change") +
  ylab("-log10 P-value") +
  ggtitle("Volcano Plot")

Top genes

gene <- rownames(results)[1]
pex <- expr_norm[which(rownames(expr_norm) == gene),]
pex_case <- pex[which(group=="Case")]
pex_ctrl <- pex[which(group=="Control")]
pl <- list("Ctrl"=pex_ctrl,"Case"=pex_case)
pl
## $Ctrl
##    34629    40431    35038    41436    40316   102953     4177    47542 
##       NA       NA       NA       NA       NA       NA 4.290280 4.317761 
##    42977   113835    19584   118008 
## 4.314943 4.373970 4.286314 4.361736 
## 
## $Case
##    19191    34862    40475    34866    41383     3746    40797   103376 
##       NA       NA       NA       NA       NA       NA 4.418528 4.408456 
##    47442    43081   113856   118117 
## 4.422823 4.344689 4.432390 4.412545
boxplot(pl,col="white",cex=0,ylab="normalised protein expression",main=gene)
beeswarm(pl,add=TRUE,cex=2,col="darkgray",pch=19)

null <- lapply(1:10,function(i) {
  gene <- rownames(results)[i]
  pex <- expr_norm[which(rownames(expr_norm) == gene),]
  pex_case <- pex[which(group=="Case")]
  pex_ctrl <- pex[which(group=="Control")]
  pl <- list("Ctrl"=pex_ctrl,"Case"=pex_case)
  pl
  boxplot(pl,col="white",cex=0,ylab="normalised protein expression",main=gene)
  beeswarm(pl,add=TRUE,cex=2,col="darkgray",pch=19)
})

Heatmap

topgenes <- rownames(head(results,30))
rowidx <- which(rownames(expr_norm) %in% topgenes)
topmx <- expr_norm[rowidx,]
topmx <- topmx+0.01
topmx[is.na(topmx)] <- 0
colnames(topmx) <- paste(group,colnames(topmx))
colfunc <- colorRampPalette(c("blue", "white", "red"))
heatmap.2(topmx, main="Top proteins", scale="row", col = colfunc(25), trace="none",margin=c(9,13),cexRow=0.7,cexCol=0.8)

Pathway enrichment analysis

reactome <- gmt_import("ReactomePathways_2026-04-02.gmt")
head(reactome)
## $`2-LTR circle formation`
##  [1] "BANF1"   "HMGA1"   "LIG4"    "PSIP1"   "XRCC4"   "XRCC5"   "XRCC6"  
##  [8] "gag"     "gag-pol" "rev"     "vif"     "vpr"     "vpu"    
## 
## $`3-Methylcrotonyl-CoA carboxylase deficiency`
## [1] "MCCC1" "MCCC2"
## 
## $`3-hydroxyisobutyryl-CoA hydrolase deficiency`
## [1] "HIBCH"
## 
## $`3-methylglutaconic aciduria`
## [1] "AUH"
## 
## $`5-Phosphoribose 1-diphosphate biosynthesis`
## [1] "PRPS1"   "PRPS1L1" "PRPS2"  
## 
## $`ABC transporter disorders`
##  [1] "ABCA1"  "ABCA12" "ABCA3"  "ABCB11" "ABCB4"  "ABCB6"  "ABCC2"  "ABCC6" 
##  [9] "ABCC8"  "ABCC9"  "ABCD1"  "ABCD4"  "ABCG5"  "ABCG8"  "ADRM1"  "APOA1" 
## [17] "CFTR"   "DERL1"  "DERL2"  "DERL3"  "ERLEC1" "ERLIN1" "ERLIN2" "KCNJ11"
## [25] "LMBRD1" "OS9"    "PSMA1"  "PSMA2"  "PSMA3"  "PSMA4"  "PSMA5"  "PSMA6" 
## [33] "PSMA7"  "PSMB1"  "PSMB2"  "PSMB3"  "PSMB4"  "PSMB5"  "PSMB6"  "PSMB7" 
## [41] "PSMC1"  "PSMC2"  "PSMC3"  "PSMC4"  "PSMC5"  "PSMC6"  "PSMD1"  "PSMD11"
## [49] "PSMD12" "PSMD13" "PSMD14" "PSMD2"  "PSMD3"  "PSMD6"  "PSMD7"  "PSMD8" 
## [57] "RNF185" "RNF5"   "RPS27A" "SEL1L"  "SEM1"   "UBA52"  "UBB"    "UBC"   
## [65] "VCP"
gt <- data.frame(rownames(results))
gt$genename <- sapply(strsplit(gt[,1]," "),"[[",1)

y <- mitch_import(x=results, DEtype="limma",geneTable=gt)
## The input is a single dataframe; one contrast only. Converting
##         it to a list for you.
## Note: Mean no. genes in input = 904
## Note: no. genes in output = 904
## Note: estimated proportion of input genes in output = 1
mres <- mitch_calc(x=y, genesets=reactome, priority="effect", minsetsize=5, cores=4)
## Note: Enrichments with large effect sizes may not be
##             statistically significant.
head(mres$enrichment_result,10) %>%
  kbl(caption="Top results by enrichment score") %>%
  kable_paper("hover", full_width = F)
Top results by enrichment score
set setSize pANOVA s.dist p.adjustANOVA
327 Mitochondrial protein degradation 6 0.0065206 0.6429102 0.3298240
501 Sensory processing of sound 5 0.0184966 0.6097887 0.4958357
155 Diseases of carbohydrate metabolism 6 0.0104326 -0.6054195 0.3925270
548 Syndecan interactions 10 0.0013242 0.5885906 0.2032772
151 Diseases associated with O-glycosylation of proteins 9 0.0026981 0.5796400 0.2455375
433 RUNX1 regulates genes involved in megakaryocyte differentiation and platelet function 5 0.0317934 0.5559511 0.5629302
230 Glutathione conjugation 5 0.0389872 0.5345940 0.6011561
194 Folding of actin by CCT/TriC 6 0.0255122 0.5282108 0.5389579
45 Association of TriC/CCT with target proteins during biosynthesis 6 0.0287906 0.5170750 0.5515299
378 Phospholipid metabolism 5 0.0496776 0.5083426 0.6565385
mres2 <- mitch_calc(x=y, genesets=reactome, priority="significance", minsetsize=5, cores=4)
## Note: When prioritising by significance (ie: small
##             p-values), large effect sizes might be missed.
head(mres2$enrichment_result,10) %>%
  kbl(caption="Top results by statistical significance") %>%
  kable_paper("hover", full_width = F)
Top results by statistical significance
set setSize pANOVA s.dist p.adjustANOVA
197 Formation of the cornified envelope 28 0.0007394 -0.3733692 0.2032772
282 Keratinization 28 0.0007394 -0.3733692 0.2032772
548 Syndecan interactions 10 0.0013242 0.5885906 0.2032772
317 Metabolism of lipids 30 0.0013841 0.3423341 0.2032772
354 Non-integrin membrane-ECM interactions 19 0.0016883 0.4198037 0.2032772
151 Diseases associated with O-glycosylation of proteins 9 0.0026981 0.5796400 0.2455375
374 Peptide hormone metabolism 15 0.0028551 -0.4479190 0.2455375
88 Cellular responses to stimuli 86 0.0045506 0.1855348 0.3298240
383 Platelet Adhesion to exposed collagen 10 0.0060991 0.5031320 0.3298240
168 EPH-Ephrin signaling 20 0.0061924 0.3571267 0.3298240

Session information

For reproducibility.

sessionInfo()
## R version 4.5.3 (2026-03-11)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.4 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
## 
## locale:
##  [1] LC_CTYPE=en_AU.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_AU.UTF-8        LC_COLLATE=en_AU.UTF-8    
##  [5] LC_MONETARY=en_AU.UTF-8    LC_MESSAGES=en_AU.UTF-8   
##  [7] LC_PAPER=en_AU.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_AU.UTF-8 LC_IDENTIFICATION=C       
## 
## time zone: Australia/Melbourne
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats4    stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] gplots_3.3.0           mitch_1.20.0           beeswarm_0.4.0        
##  [4] kableExtra_1.4.0       org.Hs.eg.db_3.21.0    AnnotationDbi_1.70.0  
##  [7] IRanges_2.42.0         S4Vectors_0.46.0       Biobase_2.68.0        
## [10] BiocGenerics_0.54.1    generics_0.1.4         clusterProfiler_4.16.0
## [13] pheatmap_1.0.13        limma_3.64.3           janitor_2.2.1         
## [16] lubridate_1.9.5        forcats_1.0.1          stringr_1.6.0         
## [19] purrr_1.2.1            readr_2.1.6            tidyr_1.3.2           
## [22] tibble_3.3.1           ggplot2_4.0.2          tidyverse_2.0.0       
## [25] dplyr_1.2.0           
## 
## loaded via a namespace (and not attached):
##   [1] RColorBrewer_1.1-3      rstudioapi_0.18.0       jsonlite_2.0.0         
##   [4] magrittr_2.0.4          ggtangle_0.1.1          farver_2.1.2           
##   [7] rmarkdown_2.30          fs_1.6.6                vctrs_0.7.1            
##  [10] memoise_2.0.1           ggtree_3.16.3           htmltools_0.5.9        
##  [13] gridGraphics_0.5-1      sass_0.4.10             KernSmooth_2.23-26     
##  [16] bslib_0.10.0            htmlwidgets_1.6.4       plyr_1.8.9             
##  [19] echarts4r_0.5.0         cachem_1.1.0            igraph_2.2.2           
##  [22] mime_0.13               lifecycle_1.0.5         pkgconfig_2.0.3        
##  [25] Matrix_1.7-4            R6_2.6.1                fastmap_1.2.0          
##  [28] gson_0.1.0              shiny_1.12.1            GenomeInfoDbData_1.2.14
##  [31] snakecase_0.11.1        digest_0.6.39           aplot_0.2.9            
##  [34] enrichplot_1.28.4       colorspace_2.1-2        GGally_2.4.0           
##  [37] patchwork_1.3.2         textshaping_1.0.4       RSQLite_2.4.6          
##  [40] labeling_0.4.3          timechange_0.4.0        httr_1.4.8             
##  [43] compiler_4.5.3          bit64_4.6.0-1           withr_3.0.2            
##  [46] S7_0.2.1                BiocParallel_1.42.2     DBI_1.2.3              
##  [49] ggstats_0.12.0          R.utils_2.13.0          MASS_7.3-65            
##  [52] rappdirs_0.3.4          caTools_1.18.3          gtools_3.9.5           
##  [55] tools_4.5.3             otel_0.2.0              ape_5.8-1              
##  [58] httpuv_1.6.16           R.oo_1.27.1             glue_1.8.0             
##  [61] promises_1.5.0          nlme_3.1-168            GOSemSim_2.34.0        
##  [64] grid_4.5.3              reshape2_1.4.5          fgsea_1.34.2           
##  [67] gtable_0.3.6            tzdb_0.5.0              R.methodsS3_1.8.2      
##  [70] data.table_1.18.2.1     hms_1.1.4               xml2_1.5.2             
##  [73] XVector_0.48.0          ggrepel_0.9.6           pillar_1.11.1          
##  [76] vroom_1.7.0             yulab.utils_0.2.4       later_1.4.6            
##  [79] splines_4.5.3           treeio_1.32.0           lattice_0.22-9         
##  [82] bit_4.6.0               tidyselect_1.2.1        GO.db_3.21.0           
##  [85] Biostrings_2.76.0       knitr_1.51              gridExtra_2.3          
##  [88] svglite_2.2.2           xfun_0.56               statmod_1.5.1          
##  [91] stringi_1.8.7           UCSC.utils_1.4.0        statnet.common_4.13.0  
##  [94] lazyeval_0.2.2          ggfun_0.2.0             yaml_2.3.12            
##  [97] evaluate_1.0.5          codetools_0.2-20        qvalue_2.40.0          
## [100] ggplotify_0.1.3         cli_3.6.5               xtable_1.8-4           
## [103] systemfonts_1.3.1       jquerylib_0.1.4         network_1.20.0         
## [106] dichromat_2.0-0.1       Rcpp_1.1.1              GenomeInfoDb_1.44.3    
## [109] coda_0.19-4.1           png_0.1-8               parallel_4.5.3         
## [112] blob_1.3.0              DOSE_4.2.0              bitops_1.0-9           
## [115] viridisLite_0.4.3       tidytree_0.4.7          scales_1.4.0           
## [118] crayon_1.5.3            rlang_1.1.7             cowplot_1.2.0          
## [121] fastmatch_1.1-8         KEGGREST_1.48.1