Score Metabolic Pathways

Related to Figure 3.

Load Seurat objects

ren1c_obj <- readRDS("ren1c_obj.rds")
captopril_obj <- readRDS("captopril_obj.rds")
DefaultAssay(captopril_obj) <- "RNA"

ren1c_obj$cell_type <- ren1c_obj$reconciled_celltype
captopril_obj$cell_type <- captopril_obj$reconciled_celltype

ren1c_obj[["umap"]] <- ren1c_obj[["umap_harmony"]]

num_available_cores <- parallelly::availableCores()
register(MulticoreParam(workers = num_available_cores[[1]] - 4), default = TRUE)

Score metabolic pathways

calcMetabolicScores adds UCell-based pathway scores to @meta.data. UCell uses per-cell gene rankings so scores are robust to sequencing depth variation.

ren1c_obj     <- calcMetabolicScores(ren1c_obj)
captopril_obj <- calcMetabolicScores(captopril_obj)

Scores added: OXPHOS_Score, Glycolysis_Score, TCA_Score, FAO_Score, PPP_Score.

Statistical testing — Ren1c KO model

# OXPHOS
ren1_oxphos_stats <- calcStatistics(
  ren1c_obj,
  group_var = "genotype",
  group1 = "WT",
  group2 = "KO",
  metric = "OXPHOS_Score"
)

# Glycolysis
ren1_glyc_stats <- calcStatistics(
  ren1c_obj,
  group_var = "genotype",
  group1 = "WT",
  group2 = "KO",
  metric = "Glycolysis_Score"
)

Statistical testing — captopril model

capt_oxphos_stats <- calcStatistics(
  captopril_obj,
  group_var = "condition",
  group1 = "ctrl",
  group2 = "trt",
  metric = "OXPHOS_Score"
)

capt_glyc_stats <- calcStatistics(
  captopril_obj,
  group_var = "condition",
  group1 = "ctrl",
  group2 = "trt",
  metric = "Glycolysis_Score"
)

Cohen's d effect sizes — main signatures

To compare effect magnitudes across pathways (rather than relying on p-values alone), Cohen's d is computed using the pooled-SD formula. Because the objects are enriched for renin-lineage cells, whole-object Cohen's d values are attenuated by cell-type composition. Interpret relative magnitudes across signatures, not against absolute benchmarks.

cohensD <- function(x, y) {
  nx <- length(x); ny <- length(y)
  pooled_sd <- sqrt(((nx - 1) * var(x) + (ny - 1) * var(y)) / (nx + ny - 2))
  (mean(y) - mean(x)) / pooled_sd
}

main_scores <- c("OXPHOS_Score", "Glycolysis_Score",
                 "TCA_Score", "FAO_Score",
                 "PPP_Score")

calcMainEffectSizes <- function(seurat_obj, group_var, group1, group2, model_label) {
  meta <- seurat_obj@meta.data
  g1   <- meta[meta[[group_var]] == group1, ]
  g2   <- meta[meta[[group_var]] == group2, ]
  scores_present <- main_scores[main_scores %in% colnames(meta)]
  results <- lapply(scores_present, function(s) {
    d <- cohensD(g1[[s]], g2[[s]])
    data.frame(
      model = model_label, score = s,
      group1 = group1, group2 = group2,
      mean_group1 = mean(g1[[s]]), mean_group2 = mean(g2[[s]]),
      cohens_d = d,
      magnitude = dplyr::case_when(
        abs(d) >= 0.8 ~ "large",
        abs(d) >= 0.5 ~ "medium",
        abs(d) >= 0.2 ~ "small",
        TRUE          ~ "negligible"
      )
    )
  })
  do.call(rbind, results)
}

main_effect_capt  <- calcMainEffectSizes(captopril_obj, "condition", "ctrl", "trt", "captopril")
main_effect_ren1c <- calcMainEffectSizes(ren1c_obj,     "genotype",  "WT",   "KO",  "ren1c")
main_effect_all   <- rbind(main_effect_capt, main_effect_ren1c)

fwrite(main_effect_all,
       paste0(parent_dir, "main_metabolic_signatures_cohens_d.csv"),
       row.names = FALSE, sep = ",")

Captopril model summary (ctrl → trt, positive d = elevated in treated):

Pathway Cohen's d Magnitude
Glycolysis 0.619 medium
FAO 0.457 small
TCA 0.452 small
OXPHOS 0.372 small
PPP 0.357 small

Glycolysis shows the largest transcriptional shift, consistent with HIF-driven metabolic reprogramming.

K-means metabolic zone clustering

Produces manuscript Figures 3g and 3m (cells clustered by OXPHOS, glycolysis, and balance scores into k=4 zones ranked by mean glycolysis score; KO and captopril-treated cells are enriched in the highest glycolytic cluster).

calcMetabolicClustering and plotClustering are defined in metabolic_analysis_functions.R. Features used: OXPHOS_Score, Glycolysis_Score, Metabolic_Balance (OXPHOS − Glycolysis), and Metabolic_Ratio (OXPHOS / Glycolysis), scaled before clustering. Clusters are ranked 1–4 by mean glycolysis (rank 1 = highest). Enrichment of KO/treated cells toward higher-glycolysis clusters is tested with a Wilcoxon test on per-cell Glycolysis_Rank values; per-cluster Fisher's exact tests are BH-corrected.

source("metabolic_analysis_functions.R")

ren1_clustering <- calcMetabolicClustering(
    ren1c_obj,
    group_var    = "genotype",
    model_name   = "Ren1 KO",
    group_levels = c("WT", "KO"),
    method       = "kmeans",
    k            = 4
)

capt_clustering <- calcMetabolicClustering(
    captopril_obj,
    group_var    = "condition",
    model_name   = "Captopril",
    group_levels = c("ctrl", "trt"),
    method       = "kmeans",
    k            = 4
)

ren1_cluster_plots <- plotClustering(ren1c_obj,     ren1_clustering, "genotype",  "Ren1 KO")
capt_cluster_plots <- plotClustering(captopril_obj, capt_clustering, "condition", "Captopril")

for (plt_name in names(ren1_cluster_plots)) {
    ggsave(paste0(parent_dir, "ren1c_metabolic-clustering_", plt_name, "_", Sys.Date(), ".svg"),
           plot = ren1_cluster_plots[[plt_name]], units = "mm", dpi = 300)
    ggsave(paste0(parent_dir, "captopril_metabolic-clustering_", plt_name, "_", Sys.Date(), ".svg"),
           plot = capt_cluster_plots[[plt_name]], units = "mm", dpi = 300)
}