Single-Cell RNA-seq Metabolic Flux Analysis
Zaoqu Liu
2026-01-23
Source:vignettes/singlecell_analysis.Rmd
singlecell_analysis.RmdOverview
This vignette demonstrates metabolic flux analysis for single-cell RNA-seq data using METAFLUX’s community modeling approach.
Biological Context
Tumor Microenvironment Metabolism
Single-cell metabolic analysis reveals:
- Metabolic heterogeneity within cell populations
- Metabolic cooperation between cell types
- Competition for shared nutrients
- Metabolic crosstalk via secreted metabolites
Community Modeling Concept
┌─────────────────────────────────────────────────────────────────┐
│ Tumor Microenvironment │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Tumor │ ←→ │ T cell │ ←→ │ Macro- │ │
│ │ Cells │ │ │ │ phage │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ┌────┴────┐ │
│ │ Shared │ │
│ │ Medium │ │
│ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
Data Preparation
Step 1: Bootstrap Aggregation
Single-cell data is sparse. Bootstrap aggregation reduces noise while preserving biological variation.
# Calculate bootstrap-averaged expression
avg_expr <- calculate_avg_exp(
myseurat = sc_test_example,
myident = "Cell_type", # Column with cell type labels
n_bootstrap = 100, # Number of bootstrap iterations
seed = 42 # For reproducibility
)
# Check output dimensions
dim(avg_expr)
# Rows: genes
# Columns: cell_type_1, cell_type_2, ..., cell_type_1, ... (repeated n_bootstrap times)Step 2: Calculate MRAS
# Calculate reaction activity scores
mras <- calculate_reaction_score(avg_expr)
# Verify dimensions
dim(mras) # 13082 × (n_celltypes × n_bootstrap)Step 4: Community Flux Calculation
# Number of cell types
num_cell <- length(unique(sc_test_example$Cell_type))
# Compute community metabolic fluxes
flux <- compute_sc_flux(
num_cell = num_cell,
fraction = fractions,
fluxscore = mras,
medium = human_blood,
parallel = TRUE, # Enable parallel computing
n_cores = 4, # Number of CPU cores
use_cpp = TRUE # Use C++ acceleration
)
# Check output
dim(flux)
head(rownames(flux), 20)Step 5: Analyze Results
Extract Cell Type-Specific Fluxes
# Get reaction names
reaction_names <- rownames(flux)
# Extract fluxes for specific cell type
get_celltype_flux <- function(flux_matrix, celltype_num) {
pattern <- paste0("^celltype ", celltype_num, " ")
idx <- grep(pattern, rownames(flux_matrix))
result <- flux_matrix[idx, , drop = FALSE]
rownames(result) <- gsub(pattern, "", rownames(result))
return(result)
}
# Extract for each cell type
tumor_flux <- get_celltype_flux(flux, 1)
tcell_flux <- get_celltype_flux(flux, 2)External Medium Exchange
# Extract external exchange reactions
external_idx <- grep("^external_medium", rownames(flux))
external_flux <- flux[external_idx, , drop = FALSE]
# Net nutrient consumption/production
nutrient_balance <- rowMeans(external_flux)
head(sort(nutrient_balance), 10) # Top uptakes
tail(sort(nutrient_balance), 10) # Top secretionsAdvanced Analysis
Metabolic Cooperation
Identify metabolites exchanged between cell types:
# One cell type produces, another consumes
producer <- which(lactate_by_celltype > 0)
consumer <- which(lactate_by_celltype < 0)
if (length(producer) > 0 && length(consumer) > 0) {
cat(sprintf("%s produces lactate\n", names(lactate_by_celltype)[producer]))
cat(sprintf("%s consumes lactate\n", names(lactate_by_celltype)[consumer]))
}Performance Tips
Parallel Computing
# Check available cores
parallel::detectCores()
# Recommended: use physical cores - 1
n_cores <- max(1, parallel::detectCores(logical = FALSE) - 1)
# Limit to 8 to prevent memory issues
n_cores <- min(n_cores, 8)Memory Management
# For large datasets, reduce bootstrap iterations
avg_expr <- calculate_avg_exp(
myseurat = sc_test_example,
myident = "Cell_type",
n_bootstrap = 50, # Reduced from 100
seed = 42
)
# Or subsample cells first
sc_subset <- subset(sc_test_example, downsample = 5000)Biological Interpretation
Warburg Effect
# High glycolysis, low oxidative phosphorylation
glycolysis_rxns <- c("HMR_4363", "HMR_4365", "HMR_4367") # Example
oxphos_rxns <- c("HMR_6916", "HMR_6921") # Example
tumor_flux <- get_celltype_flux(flux, 1)
glycolysis_mean <- mean(abs(tumor_flux[glycolysis_rxns, ]))
oxphos_mean <- mean(abs(tumor_flux[oxphos_rxns, ]))
warburg_ratio <- glycolysis_mean / oxphos_mean
cat(sprintf("Warburg ratio: %.2f\n", warburg_ratio))Immunometabolism
# T cell activation markers
glutamine_rxn <- "HMR_9063" # Glutamine uptake
fa_synthesis <- grep("fatty acid synthesis", rownames(tumor_flux), ignore.case = TRUE)
tcell_flux <- get_celltype_flux(flux, 2)
tcell_glutamine <- mean(abs(tcell_flux[glutamine_rxn, ]))
tcell_fa <- mean(abs(tcell_flux[fa_synthesis, ]))
cat(sprintf("T cell glutamine uptake: %.4f\n", tcell_glutamine))
cat(sprintf("T cell fatty acid synthesis: %.4f\n", tcell_fa))Next Steps
- Visualization: See Visualization Guide
- Pathway analysis: Aggregate fluxes by metabolic pathway
- Statistical testing: Compare conditions
- Integration: Combine with other omics data
Author
Zaoqu Liu - Package maintainer - GitHub: Zaoqu-Liu - ORCID: 0000-0002-0452-742X