
Bio Workflows Multi Omics Pipeline
- 3 installs
- 1.1k repo stars
- Updated July 25, 2026
- gptomics/bioskills
Run an end-to-end multi-omics integration workflow across transcriptomics, proteomics, and metabolomics with MOFA2 and mixOmics.
About
Orchestrates data harmonization, MOFA/mixOmics integration, factor interpretation, and downstream analysis across omics modalities. A developer uses it to integrate multiple omics datasets and interpret shared latent factors.
- MOFA2 and mixOmics multi-modality integration
- Data harmonization, factor interpretation, similarity networks
Bio Workflows Multi Omics Pipeline by the numbers
- 3 all-time installs (skills.sh)
- Ranked #1,661 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/gptomics/bioskills --skill bio-workflows-multi-omics-pipelineAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3 |
|---|---|
| repo stars | ★ 1.1k |
| Last updated | July 25, 2026 |
| Repository | gptomics/bioskills ↗ |
What it does
Run an end-to-end multi-omics integration workflow across transcriptomics, proteomics, and metabolomics with MOFA2 and mixOmics.
Files
Version Compatibility
Reference examples tested with: clusterProfiler 4.10+, ggplot2 3.5+, scanpy 1.10+
Before using code patterns, verify installed versions match. If versions differ:
- R:
packageVersion('<pkg>')then?function_nameto verify parameters
If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.
Multi-omics Integration Pipeline
"Integrate my multi-omics datasets" -> Orchestrate data harmonization, MOFA+ factor analysis, mixOmics multivariate integration, similarity network fusion, and joint pathway interpretation across transcriptomics, proteomics, metabolomics, or other modalities.
Pipeline Overview
RNA-seq Data ─────┐
│
Proteomics Data ──┼──> Data Harmonization ──> Integration ──> Factors/Components
│ │
Metabolomics ─────┘ ▼
┌─────────────────────────────────────────────────────┐
│ multi-omics-pipeline │
├─────────────────────────────────────────────────────┤
│ 1. Data Preprocessing per Modality │
│ 2. Sample Harmonization (matching samples) │
│ 3. Feature Selection/Filtering │
│ 4. Integration (MOFA2 / mixOmics / SNF) │
│ 5. Factor/Component Interpretation │
│ 6. Downstream Analysis │
└─────────────────────────────────────────────────────┘
│
▼
Integrated Factors + Biomarker SignaturesComplete MOFA2 Workflow
library(MOFA2)
library(MOFAdata)
library(ggplot2)
library(tidyverse)
# === 1. LOAD AND HARMONIZE DATA ===
# RNA-seq data (samples x genes)
rna <- read.csv('rnaseq_normalized.csv', row.names = 1)
cat('RNA:', nrow(rna), 'samples,', ncol(rna), 'genes\n')
# Proteomics data (samples x proteins)
protein <- read.csv('proteomics_normalized.csv', row.names = 1)
cat('Protein:', nrow(protein), 'samples,', ncol(protein), 'proteins\n')
# Metabolomics data (samples x metabolites)
metab <- read.csv('metabolomics_normalized.csv', row.names = 1)
cat('Metabolites:', nrow(metab), 'samples,', ncol(metab), 'metabolites\n')
# Find common samples
common_samples <- Reduce(intersect, list(rownames(rna), rownames(protein), rownames(metab)))
cat('Common samples:', length(common_samples), '\n')
# Subset to common samples
rna <- rna[common_samples, ]
protein <- protein[common_samples, ]
metab <- metab[common_samples, ]
# === 2. FEATURE SELECTION ===
# Select most variable features per modality
select_variable <- function(data, n = 2000) {
vars <- apply(data, 2, var, na.rm = TRUE)
top_features <- names(sort(vars, decreasing = TRUE))[1:min(n, ncol(data))]
data[, top_features]
}
rna_var <- select_variable(rna, n = 2000)
protein_var <- select_variable(protein, n = 1000)
metab_var <- select_variable(metab, n = 500)
# === 3. CREATE MOFA OBJECT ===
# Prepare data as list of matrices (features x samples)
data_list <- list(
RNA = t(as.matrix(rna_var)),
Protein = t(as.matrix(protein_var)),
Metabolome = t(as.matrix(metab_var))
)
# Create MOFA object
mofa <- create_mofa(data_list)
# Add sample metadata
sample_metadata <- read.csv('sample_metadata.csv')
rownames(sample_metadata) <- sample_metadata$sample_id
samples_metadata(mofa) <- sample_metadata[common_samples, ]
# === 4. CONFIGURE AND TRAIN MODEL ===
# Data options
data_opts <- get_default_data_options(mofa)
data_opts$scale_views <- TRUE # Scale each view
# Model options
model_opts <- get_default_model_options(mofa)
model_opts$num_factors <- 15 # Number of factors to learn
# Training options
train_opts <- get_default_training_options(mofa)
train_opts$maxiter <- 1000
train_opts$convergence_mode <- 'slow'
train_opts$seed <- 42
# Prepare and train
mofa <- prepare_mofa(mofa, data_options = data_opts,
model_options = model_opts,
training_options = train_opts)
cat('Training MOFA model...\n')
mofa <- run_mofa(mofa, outfile = 'mofa_model.hdf5', use_basilisk = TRUE)
# === 5. ANALYZE FACTORS ===
# Variance explained per factor per view
plot_variance_explained(mofa, max_r2 = 15)
ggsave('variance_explained.png', width = 10, height = 6)
# Factor values
factor_values <- get_factors(mofa)[[1]]
# Correlate factors with phenotypes
plot_factor_cor(mofa, color_by = 'condition')
ggsave('factor_phenotype_correlation.png', width = 8, height = 6)
# Factor plots
plot_factor(mofa, factors = 1:4, color_by = 'condition', dot_size = 3)
ggsave('factor_scatter.png', width = 12, height = 10)
# === 6. INTERPRET FACTORS ===
# Get top weights per factor per view
for (f in 1:5) {
cat('\nFactor', f, ':\n')
weights <- get_weights(mofa, factors = f, as.data.frame = TRUE)
for (view in unique(weights$view)) {
view_weights <- weights[weights$view == view, ]
view_weights <- view_weights[order(abs(view_weights$value), decreasing = TRUE), ]
cat(' ', view, ':', paste(head(view_weights$feature, 5), collapse = ', '), '\n')
}
}
# Heatmap of top features per factor
plot_top_weights(mofa, view = 'RNA', factors = 1:5, nfeatures = 10)
ggsave('top_weights_rna.png', width = 10, height = 8)
# === 7. ENRICHMENT ANALYSIS ===
library(clusterProfiler)
library(org.Hs.eg.db)
# Get RNA weights for factor 1
rna_weights <- get_weights(mofa, views = 'RNA', factors = 1)[[1]][, 1]
top_genes <- names(sort(abs(rna_weights), decreasing = TRUE))[1:200]
# GO enrichment -- use all RNA features as background (not the full genome)
all_rna_genes <- names(rna_weights)
ego <- enrichGO(gene = top_genes,
universe = all_rna_genes,
OrgDb = org.Hs.eg.db,
keyType = 'SYMBOL',
ont = 'BP',
pvalueCutoff = 0.05)
ego <- simplify(ego, cutoff = 0.7, by = 'p.adjust')
dotplot(ego, showCategory = 15)
ggsave('factor1_enrichment.png', width = 8, height = 10)
# === 8. DOWNSTREAM: SURVIVAL ANALYSIS ===
library(survival)
library(survminer)
# Add factor values to metadata
surv_data <- data.frame(
sample = rownames(factor_values),
factor1 = factor_values[, 1],
time = sample_metadata[rownames(factor_values), 'survival_time'],
status = sample_metadata[rownames(factor_values), 'survival_status']
)
# Median split
surv_data$factor1_group <- ifelse(surv_data$factor1 > median(surv_data$factor1), 'High', 'Low')
# Kaplan-Meier
fit <- survfit(Surv(time, status) ~ factor1_group, data = surv_data)
ggsurvplot(fit, data = surv_data, pval = TRUE, risk.table = TRUE)
ggsave('survival_factor1.png', width = 8, height = 8)
# === 9. EXPORT RESULTS ===
# Factor values
write.csv(factor_values, 'mofa_factor_values.csv')
# Weights
all_weights <- get_weights(mofa, as.data.frame = TRUE)
write.csv(all_weights, 'mofa_weights.csv', row.names = FALSE)
cat('\nMOFA analysis complete!\n')mixOmics DIABLO Workflow
library(mixOmics)
# === 1. PREPARE DATA ===
# Same preprocessing as above
X <- list(
RNA = as.matrix(rna_var),
Protein = as.matrix(protein_var),
Metabolome = as.matrix(metab_var)
)
# Outcome variable
Y <- factor(sample_metadata[common_samples, 'condition'])
# === 2. DESIGN MATRIX ===
# Define connections between blocks
design <- matrix(0.1, ncol = length(X), nrow = length(X),
dimnames = list(names(X), names(X)))
diag(design) <- 0
# === 3. TUNE MODEL ===
# Tune number of components
perf.diablo <- perf(block.splsda(X, Y, ncomp = 5, design = design),
validation = 'Mfold', folds = 5, nrepeat = 10)
ncomp <- perf.diablo$choice.ncomp$WeightedVote['Overall.BER', 'max.dist']
cat('Optimal components:', ncomp, '\n')
# Tune number of variables per component
test.keepX <- list(
RNA = c(10, 25, 50, 100),
Protein = c(5, 10, 25, 50),
Metabolome = c(5, 10, 25)
)
tune.diablo <- tune.block.splsda(X, Y, ncomp = ncomp, test.keepX = test.keepX,
design = design, validation = 'Mfold', folds = 5)
optimal.keepX <- tune.diablo$choice.keepX
# === 4. FINAL MODEL ===
diablo.model <- block.splsda(X, Y, ncomp = ncomp,
keepX = optimal.keepX, design = design)
# === 5. VISUALIZATION ===
# Sample plot
plotIndiv(diablo.model, ind.names = FALSE, legend = TRUE, title = 'DIABLO Sample Plot')
# Variable plot
plotVar(diablo.model, var.names = FALSE, style = 'graphics', legend = TRUE)
# Circos plot
circosPlot(diablo.model, cutoff = 0.7, line = TRUE,
color.blocks = c('darkorchid', 'brown1', 'lightgreen'))
# Heatmap
cimDiablo(diablo.model, color.blocks = c('darkorchid', 'brown1', 'lightgreen'),
margins = c(10, 5))
# === 6. PERFORMANCE ===
perf.final <- perf(diablo.model, validation = 'Mfold', folds = 5, nrepeat = 10)
cat('Classification error rate:', perf.final$WeightedVote.error.rate, '\n')
# ROC curves
auc.diablo <- auroc(diablo.model, roc.block = 'RNA', roc.comp = 1)Similarity Network Fusion (SNF)
library(SNFtool)
# === 1. CREATE SIMILARITY MATRICES ===
# Distance matrices per modality
dist_rna <- dist2(as.matrix(rna_var), as.matrix(rna_var))
dist_protein <- dist2(as.matrix(protein_var), as.matrix(protein_var))
dist_metab <- dist2(as.matrix(metab_var), as.matrix(metab_var))
# Affinity matrices
K <- 20 # Number of neighbors
alpha <- 0.5 # Hyperparameter
aff_rna <- affinityMatrix(dist_rna, K = K, sigma = alpha)
aff_protein <- affinityMatrix(dist_protein, K = K, sigma = alpha)
aff_metab <- affinityMatrix(dist_metab, K = K, sigma = alpha)
# === 2. FUSE NETWORKS ===
W <- SNF(list(aff_rna, aff_protein, aff_metab), K = K, t = 20)
# === 3. CLUSTER ON FUSED NETWORK ===
clusters <- spectralClustering(W, K = 3) # K = number of clusters
cat('Cluster distribution:', table(clusters), '\n')
# === 4. VISUALIZATION ===
# Plot fused network
displayClustersWithHeatmap(W, clusters)QC Checkpoints
| Stage | Check | Action if Failed |
|---|---|---|
| Sample matching | >80% samples shared | Check sample IDs |
| Missing values | <20% per modality | Impute or remove |
| Feature variance | Features vary | Filter low variance |
| Model convergence | ELBO plateau | Increase iterations |
| Factor variance | >5% per factor | Keep fewer factors |
Workflow Variants
With Missing Samples
# MOFA2 handles missing views gracefully
# Use create_mofa_from_df for unbalanced data
data_long <- rbind(
data.frame(sample = rownames(rna), view = 'RNA',
feature = colnames(rna), value = unlist(rna)),
data.frame(sample = rownames(protein), view = 'Protein',
feature = colnames(protein), value = unlist(protein))
)
mofa <- create_mofa_from_df(data_long)Single-cell Multi-omics
# MOFA+ for single-cell
library(MOFA2)
mofa <- create_mofa_from_Seurat(seurat_obj, groups = 'cell_type',
assays = c('RNA', 'ATAC'))Related Skills
- multi-omics-integration/mofa-integration - MOFA2 details
- multi-omics-integration/mixomics-analysis - mixOmics methods
- multi-omics-integration/similarity-network - SNF method
- multi-omics-integration/data-harmonization - Preprocessing
- pathway-analysis/go-enrichment - Factor interpretation
- differential-expression/batch-correction - Batch effects
# Reference: clusterProfiler 4.10+, ggplot2 3.5+, scanpy 1.10+ | Verify API if version differs
library(MOFA2)
library(ggplot2)
# === CONFIGURATION ===
output_dir <- 'results/'
dir.create(output_dir, showWarnings = FALSE)
# === 1. LOAD DATA ===
cat('Loading data...\n')
rna <- read.csv('rnaseq_normalized.csv', row.names = 1)
protein <- read.csv('proteomics_normalized.csv', row.names = 1)
metab <- read.csv('metabolomics_normalized.csv', row.names = 1)
# Find common samples
common_samples <- Reduce(intersect, list(rownames(rna), rownames(protein), rownames(metab)))
cat('Common samples:', length(common_samples), '\n')
rna <- rna[common_samples, ]
protein <- protein[common_samples, ]
metab <- metab[common_samples, ]
# === 2. FEATURE SELECTION ===
cat('Selecting variable features...\n')
select_top_var <- function(data, n) {
vars <- apply(data, 2, var, na.rm = TRUE)
data[, names(sort(vars, decreasing = TRUE))[1:min(n, ncol(data))]]
}
rna_var <- select_top_var(rna, 2000)
protein_var <- select_top_var(protein, 1000)
metab_var <- select_top_var(metab, 500)
# === 3. CREATE MOFA OBJECT ===
data_list <- list(
RNA = t(as.matrix(rna_var)),
Protein = t(as.matrix(protein_var)),
Metabolome = t(as.matrix(metab_var))
)
mofa <- create_mofa(data_list)
# === 4. CONFIGURE MODEL ===
data_opts <- get_default_data_options(mofa)
data_opts$scale_views <- TRUE
model_opts <- get_default_model_options(mofa)
model_opts$num_factors <- 10
train_opts <- get_default_training_options(mofa)
train_opts$maxiter <- 1000
train_opts$seed <- 42
mofa <- prepare_mofa(mofa, data_options = data_opts,
model_options = model_opts, training_options = train_opts)
# === 5. TRAIN MODEL ===
cat('Training MOFA model...\n')
mofa <- run_mofa(mofa, outfile = file.path(output_dir, 'mofa_model.hdf5'), use_basilisk = TRUE)
# === 6. ANALYZE RESULTS ===
cat('Analyzing results...\n')
# Variance explained
plot_variance_explained(mofa, max_r2 = 15)
ggsave(file.path(output_dir, 'variance_explained.png'), width = 10, height = 6)
# Factor values
factors <- get_factors(mofa)[[1]]
# Top weights
plot_top_weights(mofa, view = 'RNA', factors = 1:3, nfeatures = 10)
ggsave(file.path(output_dir, 'top_weights_rna.png'), width = 10, height = 8)
plot_top_weights(mofa, view = 'Protein', factors = 1:3, nfeatures = 10)
ggsave(file.path(output_dir, 'top_weights_protein.png'), width = 10, height = 8)
# === 7. EXPORT ===
write.csv(factors, file.path(output_dir, 'factor_values.csv'))
weights <- get_weights(mofa, as.data.frame = TRUE)
write.csv(weights, file.path(output_dir, 'all_weights.csv'), row.names = FALSE)
cat('Analysis complete! Results in', output_dir, '\n')
Multi-omics Integration Pipeline Usage Guide
Overview
This workflow integrates multiple molecular data types (transcriptomics, proteomics, metabolomics, etc.) to discover shared biological signals and cross-modal biomarkers.
Prerequisites
BiocManager::install(c('MOFA2', 'mixOmics'))
install.packages(c('SNFtool', 'pheatmap'))Quick Start
Tell your AI agent what you want to do:
- "Integrate my transcriptomics and proteomics data"
- "Run MOFA2 on my multi-omics dataset"
- "Find shared factors across my omics modalities"
Example Prompts
Basic Integration
"I have RNA-seq and proteomics from the same samples, integrate them with MOFA2"
"Find shared biological signals across my multi-omics data"
Supervised Analysis
"Use DIABLO to find multi-omics biomarkers that predict treatment response"
"Run supervised multi-omics analysis with patient outcomes"
Patient Stratification
"Cluster patients using multi-omics data with SNF"
"Find patient subtypes from my integrated omics data"
When to Use This Pipeline
- Studies with multiple omics measurements
- Multi-platform biomarker discovery
- Patient stratification across modalities
- Understanding disease mechanisms
- Drug response prediction
Required Inputs
1. Normalized data matrices - One per modality (samples × features) 2. Sample metadata - Conditions, outcomes, covariates 3. Feature annotations - Gene names, protein IDs, metabolite names
Data Requirements
Samples
- Common samples across modalities (or at least significant overlap)
- Minimum 20-30 samples for MOFA, more for mixOmics
- Biological replicates preferred
Features
- Pre-normalized data (log2, z-score, etc.)
- Similar scales across modalities
- Feature IDs that can be mapped (genes, proteins, metabolites)
Integration Methods
MOFA2 (Recommended)
Best for: Unsupervised exploration, factor discovery
- Handles missing views/samples
- Identifies shared vs. unique variation
- Easy interpretation via factor weights
- GPU acceleration available
mixOmics DIABLO
Best for: Supervised classification, biomarker selection
- Requires outcome variable
- Feature selection built-in
- Cross-validation for variable tuning
- Sparse solutions
SNF (Similarity Network Fusion)
Best for: Patient clustering, network-based integration
- Creates fused similarity network
- Good for patient stratification
- No feature selection
- Works with any data type
Pipeline Steps
1. Data Preprocessing
- Normalize each modality separately
- Log transform if needed
- Handle missing values
2. Sample Harmonization
- Match samples across modalities
- Verify sample IDs are consistent
- Remove samples missing from all modalities
3. Feature Selection
- Select most variable features
- Optional: pre-filter by relevance
- Balance features across modalities
4. Integration
- Run MOFA/DIABLO/SNF
- Tune parameters (components, neighbors)
- Assess convergence
5. Interpretation
- Analyze factors/components
- Identify top features per factor
- Pathway enrichment on feature sets
Parameter Guidelines
MOFA2
| Parameter | Recommended | Notes |
|---|---|---|
| num_factors | 10-15 | Start high, prune later |
| scale_views | TRUE | Equalizes modality contributions |
| maxiter | 1000 | Increase if not converged |
mixOmics DIABLO
| Parameter | Recommended | Notes |
|---|---|---|
| ncomp | 2-5 | Tune via CV |
| keepX | 10-100 | Tune per modality |
| design | 0.1 | Low correlation between blocks |
SNF
| Parameter | Recommended | Notes |
|---|---|---|
| K (neighbors) | 10-30 | ~10-20% of samples |
| t (iterations) | 20 | Usually sufficient |
Common Issues
Few common samples
- Check sample ID formatting
- Consider imputation for missing views
- MOFA handles missing better than DIABLO
Factors dominated by one view
- Increase scale_views strength
- Balance feature numbers
- Check for outliers in dominant view
No meaningful factors
- Check data quality
- Try different feature selection
- Verify biological signal exists
DIABLO overfitting
- Reduce number of features
- Use more CV folds
- Check sample size vs features
Output Files
| File | Description |
|---|---|
| mofa_model.hdf5 | Trained MOFA model |
| mofa_factor_values.csv | Sample factor scores |
| mofa_weights.csv | Feature weights per factor |
| variance_explained.png | Factor variance decomposition |
| factor_scatter.png | Sample visualization |
| top_weights_*.png | Important features |
Interpretation Guide
Factor Variance Explained
- Factors explaining >5% variance are meaningful
- Shared factors: affect multiple modalities
- Unique factors: one modality only
Feature Weights
- High absolute weight = important feature
- Sign indicates direction of association
- Compare top features across modalities
Biological Interpretation
1. Extract top genes per factor 2. Run pathway enrichment 3. Connect to clinical variables 4. Validate key features
Tips
- Sample overlap: Ensure samples are matched across modalities (same patients/conditions)
- Normalization: Pre-normalize each modality separately before integration
- Missing views: MOFA2 handles missing views better than DIABLO
- Feature selection: Select top variable features per modality to reduce noise
- Interpretation: Run pathway enrichment on top-weighted features per factor; use all features in the view as background (not the full genome), and simplify() GO results to remove redundant terms
References
- MOFA2: doi:10.1186/s13059-020-02015-1
- mixOmics: doi:10.1371/journal.pcbi.1005752
- SNF: doi:10.1038/nmeth.2810