Getting Started
4 Phyloseq

Analisis Esensial dengan phyloseq — Script & Penjelasan

Dokumen ini memuat script R lengkap untuk analisis esensial menggunakan phyloseq dan penjelasan langsung di bawah tiap blok kode.

🧪

Skrip ini mengasumsikan Anda sudah menjalankan tahap DADA2 sehingga tersedia: ASV_table.csv, 99_taxonomy_table.csv, dan ASV_sequences.fasta di folder output/dada2_outputs/.


0) Setup

suppressPackageStartupMessages({
  library(phyloseq)
  library(Biostrings)
  library(ggplot2)
  library(vegan)      # PERMANOVA (adonis2), diversity helpers
  library(DECIPHER)   # optional: alignment for tree
  library(phangorn)   # optional: ML tree for UniFrac
})

Paket yang dipanggil:

  • phyloseq untuk integrasi data mikrobioma.
  • Biostrings untuk manipulasi sekuens DNA.
  • ggplot2 untuk visualisasi.
  • vegan untuk analisis keanekaragaman & PERMANOVA.
  • DECIPHER dan phangorn opsional bila ingin membuat pohon filogenetik untuk UniFrac.

Path Input & Output

projdir      <- "./../.."
in_dada2_dir <- file.path(projdir, "output/dada2_outputs")
outdir       <- file.path(projdir, "output/phloseq_outputs")
dir.create(outdir, showWarnings = FALSE, recursive = TRUE)
  • in_dada2_dir: folder tempat hasil DADA2 disimpan.
  • outdir: semua hasil analisis phyloseq akan disimpan di sini.
otu_csv      <- file.path(in_dada2_dir, "ASV_table.csv")
tax_csv      <- file.path(in_dada2_dir, "99_taxonomy_table.csv")
asv_fasta    <- file.path(in_dada2_dir, "ASV_sequences.fasta")
metadata_csv <- file.path(projdir, "data", "sample_metadata.csv")
stopifnot(file.exists(otu_csv), file.exists(tax_csv), file.exists(asv_fasta))

Input wajib: ASV table, taxonomy table, dan ASV fasta. Metadata CSV opsional.


1) Load Data & Buat Objek phyloseq

otu_df <- read.csv(otu_csv, row.names = 1, check.names = FALSE, stringsAsFactors = FALSE)
rownames(otu_df) <- trimws(rownames(otu_df))
colnames(otu_df) <- trimws(colnames(otu_df))
otu_df[] <- lapply(otu_df, function(x) as.numeric(as.character(x)))

Membaca tabel ASV (baris = sampel, kolom = ASV) dan memastikan semua nilai berupa numerik.

tax_df <- read.csv(tax_csv, check.names = FALSE)
rownames(tax_df) <- tax_df$ASV
tax_df$ASV <- NULL

Membaca tabel taksonomi; setiap baris adalah ASV dengan rank (Phylum, Genus, dll.).

common_asvs <- intersect(colnames(otu_df), rownames(tax_df))
otu_df <- otu_df[, common_asvs, drop=FALSE]
tax_df <- tax_df[common_asvs, , drop=FALSE]

Menyamakan ASV yang muncul di kedua tabel agar konsisten.

asv_seqs <- readDNAStringSet(asv_fasta)
asv_seqs <- asv_seqs[names(asv_seqs) %in% common_asvs]
asv_seqs <- asv_seqs[match(common_asvs, names(asv_seqs))]

Mengambil sekuens DNA untuk setiap ASV (opsional, diperlukan untuk pohon filogenetik).

if (file.exists(metadata_csv)) {
  meta_df <- read.csv(metadata_csv, check.names = FALSE)
  rownames(meta_df) <- meta_df$SampleID
} else {
  meta_df <- data.frame(SampleID = rownames(otu_df), Group = "GroupA", row.names = rownames(otu_df))
}

Membaca metadata sampel. Jika tidak ada, skrip membuat dummy metadata dengan semua sampel = GroupA.

common_samples <- intersect(rownames(otu_df), rownames(meta_df))
otu_df  <- otu_df[common_samples, , drop=FALSE]
meta_df <- meta_df[common_samples, , drop=FALSE]
 
OTU  <- otu_table(as.matrix(otu_df), taxa_are_rows = FALSE)
TAX  <- tax_table(as.matrix(tax_df))
SAMP <- sample_data(meta_df)
ps   <- phyloseq(OTU, TAX, SAMP)
saveRDS(ps, file.path(outdir, "01_phyloseq_input.rds"))

Membangun objek phyloseq (ps) yang menggabungkan data ASV, taksonomi, dan metadata.


2) Eksplorasi Awal (mia/miaViz)

tse <- mia::convertFromPhyloseq(ps)
tse <- mia::transformAssay(tse, method = "relabundance")

Mengubah phyloseq ke TreeSummarizedExperiment (TSE) dan menghitung relative abundance.

p_genus <- miaViz::plotAbundance(tse, abund_values = "relabundance", rank = "Genus") +
  theme_minimal(11) +
  labs(title = "Genus composition (relative)", x = "Sample", y = "Relative abundance") +
  scale_y_continuous(labels = scales::percent_format(1), limits = c(0,1))
ggsave(file.path(outdir, "02_abundance_genus.png"), p_genus, dpi = 300)

Membuat barplot komposisi genus dan menyimpan ke PNG. Sama untuk level Phylum.

Genus composition

Genus composition

Phylum composition

Phylum composition


3) Alpha Diversity

alpha_df <- data.frame(
  SampleID = sample_names(ps),
  Observed = phyloseq::estimate_richness(ps, measures = "Observed")[,1],
  Shannon  = phyloseq::estimate_richness(ps, measures = "Shannon")[,1],
  Simpson  = phyloseq::estimate_richness(ps, measures = "Simpson")[,1],
  Group    = sample_data(ps)$Group
)
write.csv(alpha_df, file.path(outdir, "02_alpha_diversity.csv"), row.names = FALSE)

Menghitung 3 metrik keanekaragaman alfa: Observed, Shannon, dan Simpson.
Disimpan ke CSV.

p_alpha <- function(metric) {
  ggplot(alpha_df, aes(x = Group, y = .data[[metric]])) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter(width = 0.15, alpha = 0.6) +
    labs(x = "Group", y = metric, title = paste(metric, "diversity")) +
    theme_bw(base_size = 12)
}
ggsave(file.path(outdir, "02a_alpha_observed.png"), p_alpha("Observed"))

Membuat plot boxplot + jitter untuk setiap metrik alpha diversity.


4) Pohon Filogenetik (Opsional, untuk UniFrac)

do_tree <- TRUE
if (do_tree) {
  aln   <- DECIPHER::AlignSeqs(asv_seqs, processors = 0)
  phdat <- phangorn::phyDat(as(aln, "matrix"), type="DNA")
  dm    <- phangorn::dist.ml(phdat)
  tree0 <- phangorn::NJ(dm)
  fit   <- phangorn::pml(tree0, data = phdat)
  fit   <- phangorn::optim.pml(fit, model="GTR", optInv=TRUE, optGamma=TRUE, rearrangement="stochastic")
  tree  <- fit$tree
  ps    <- merge_phyloseq(ps, phy_tree(tree))
  saveRDS(ps, file.path(outdir, "03_phyloseq_with_tree.rds"))
}

Jika do_tree = TRUE, skrip akan:

  1. Align sekuens ASV.
  2. Hitung jarak evolusi (dist.ml).
  3. Buat pohon Neighbor-Joining, optimasi Maximum Likelihood (model GTR).
  4. Simpan ps baru dengan pohon.

5) Beta Diversity + PERMANOVA

ps_rel <- transform_sample_counts(ps, function(x) x / sum(x))
dist_bray <- phyloseq::distance(ps_rel, method = "bray")
ord_bray  <- ordinate(ps_rel, method = "PCoA", distance = dist_bray)
  • Bray–Curtis: jarak berbasis kelimpahan relatif antar sampel.
  • PCoA: ordination untuk visualisasi jarak.
p_bray <- plot_ordination(ps_rel, ord_bray, color="Group") +
  geom_point(size=3, alpha=0.85) +
  theme_bw(base_size = 12) +
  labs(title = "PCoA (Bray-Curtis)")
ggsave(file.path(outdir, "04a_pcoa_bray.png"), p_bray, width=6.5, height=5, dpi=300)

Menyimpan gambar PCoA Bray-Curtis.

meta_for_adonis <- as(sample_data(ps_rel), "data.frame")
adon_bray <- adonis2(as.matrix(dist_bray) ~ Group, data = meta_for_adonis, permutations = 999)
sink(file.path(outdir, "04b_permanova_bray.txt")); print(adon_bray); sink()

Melakukan PERMANOVA (adonis2) untuk menguji apakah komposisi komunitas berbeda signifikan antar grup.


Ringkasan Output

  • 02_abundance_genus.png & 02_abundance_phylum.png: barplot komposisi taksonomi.
  • 02a_alpha_observed.png, 02b_alpha_shannon.png, 02c_alpha_simpson.png: plot alpha diversity.
  • 03_phyloseq_with_tree.rds: phyloseq dengan pohon filogenetik.
  • 04a_pcoa_bray.png: plot PCoA Bray-Curtis.
  • 04b_permanova_bray.txt: hasil PERMANOVA.
📊

Output ini bisa langsung dipakai untuk laporan, publikasi, atau workshop sebagai analisis mikrobioma standar.