16S-rDNA-V3-V4 repository: https://github.com/ycl6/16S-rDNA-V3-V4
export2graphlan: GitHub, Documentation
GraPhlAn: GitHub, Documentation, Paper
Demo Dataset: PRJEB27564 from Gut Microbiota in Parkinson’s Disease: Temporal Stability and Relations to Disease Progression. EBioMedicine. 2019;44:691-707
License: GPL-3.0
Note:
export2graphlan
andGraPhlAn
can only run in Python 2.7.
R
cd /ngs/16S-Demo/PRJEB27564
R
library("data.table")
library("phyloseq")
library("ggplot2")
library("grid")
library("tidyverse")
Sys.setlocale("LC_COLLATE", "C")
## [1] "C"
Set the full-path to additional scripts
source("/path-to-script/lefse.R", local = TRUE)
load("2_phyloseq_tutorial.RData")
Create a folder lefse
if(!dir.exists("lefse")) { dir.create("lefse") }
# Patient vs. control at baseline
prune_samples(sample_names(ps1)[grep("B$", sample_names(ps1))], ps1)
ps1a = prune_taxa(taxa_sums(ps1a) > 0, ps1a)
ps1a =
# Patient followup vs. patient baseline
prune_samples(sample_names(ps1)[grep("^P", sample_names(ps1))], ps1)
ps1b = prune_taxa(taxa_sums(ps1b) > 0, ps1b) ps1b =
We are now using new version of LEfSe. Since we are interested in testing the biomarker using the main class labels (control vs. patient), hence the subject line is removed when creating the LEfSe input table.
# Add 'subject = TRUE' to include subject in the data.frame
lefse_1name_obj(ps1a, sample_data(ps1a)$Group)
tax1 = lefse_obj(ps1a)
lefse1 = rbind(tax1, lefse1)
lefse1 =
lefse_1name_obj(ps1b, sample_data(ps1b)$Time)
tax2 = lefse_obj(ps1b)
lefse2 = rbind(tax2, lefse2)
lefse2 =
# Replace unsupported chars with underscore
$name = gsub(" ","_",lefse1$name)
lefse1$name = gsub("-","_",lefse1$name)
lefse1$name = gsub("/","_",lefse1$name)
lefse1
$name = gsub(" ","_",lefse2$name)
lefse2$name = gsub("-","_",lefse2$name)
lefse2$name = gsub("/","_",lefse2$name) lefse2
For Silva v132 users, apply below to fix identifical phylum & class names (Actinobacteria and Deferribacteres)
fix_taxa_silva132(lefse1)
lefse1 = fix_taxa_silva132(lefse2) lefse2 =
expr1
: Patient vs. control at baselineexpr2
: Patient at baseline vs. patient at followupwrite.table(lefse1, file = "lefse/expr1.lefse_table.txt", sep = "\t", quote = F,
row.names = F, col.names = F)
write.table(lefse2, file = "lefse/expr2.lefse_table.txt", sep = "\t", quote = F,
row.names = F, col.names = F)
We use linear discriminant analysis (LDA) effect size (LEfSe) to determines the features (in this case the clades at each taxonomic rank) most likely to explain the differences between Parkinson’s patients and control subjects
Set the full-paths to LEfSe
’s python scripts if they are not in PATH
-format_input = "/path-to-lefse-format_input.py" # e.g. /home/ngs/lefse/lefse-format_input.py
lefse "/path-to-run_lefse.py" # e.g. /home/ngs/lefse/run_lefse.py run_lefse =
/path-to-lefse-format_input.py lefse/expr1.lefse_table.txt lefse/expr1.lefse_table.in -c 1 -o 1000000
/path-to-lefse-format_input.py lefse/expr2.lefse_table.txt lefse/expr2.lefse_table.in -c 1 -o 1000000
/path-to-run_lefse.py lefse/expr1.lefse_table.in lefse/expr1.lefse_table.res -b 100 -a 1 -l 1
/path-to-run_lefse.py lefse/expr2.lefse_table.in lefse/expr2.lefse_table.res -b 100 -a 1 -l 1
system2(lefse_format_input,
args = c("lefse/expr1.lefse_table.txt", "lefse/expr1.lefse_table.in",
"-c 1", "-o 1000000"))
system2(lefse_format_input,
args = c("lefse/expr2.lefse_table.txt", "lefse/expr2.lefse_table.in",
"-c 1", "-o 1000000"))
# set Kruskal-Wallis alpha (-a) to 1 to allow returning of all P-value to perform adjustment later
system2(run_lefse,
args = c("lefse/expr1.lefse_table.in", "lefse/expr1.lefse_table.res",
"-b 100", "-a 1", "-l 1"), stdout = TRUE)
## [1] "Number of significantly discriminative features: 36 ( 269 ) before internal wilcoxon"
## [2] "Number of discriminative features with abs LDA score > 1.0 : 36"
system2(run_lefse,
args = c("lefse/expr2.lefse_table.in", "lefse/expr2.lefse_table.res",
"-b 100", "-a 1", "-l 1"), stdout = TRUE)
## [1] "Number of significantly discriminative features: 11 ( 267 ) before internal wilcoxon"
## [2] "Number of discriminative features with abs LDA score > 1.0 : 9"
Perform multiple testing correction on reported P-values
# set fdr threshold at 0.1
0.1
q =
data.frame(fread("lefse/expr1.lefse_table.res"))
expr1 = pcorrection(expr1, q)
expr1 =
data.frame(fread("lefse/expr2.lefse_table.res"))
expr2 = pcorrection(expr2, q)
expr2 =
# You can use table() to check number of taxa pass the threshold
table(expr1$V3 != "")
##
## FALSE TRUE
## 234 36
table(expr2$V3 != "")
##
## FALSE TRUE
## 261 9
# Write new result file with the P-value column replaced by the FDR
write.table(expr1[,c(1:4,6)], file = "lefse/expr1.lefse_table.res.padj", sep = "\t", quote = F,
row.names = F, col.names = F)
write.table(expr2[,c(1:4,6)], file = "lefse/expr2.lefse_table.res.padj", sep = "\t", quote = F,
row.names = F, col.names = F)
Note:
export2graphlan
andGraPhlAn
can only run in Python 2.7. They do not support Python 3.
Note: Update the coloring
lefse/expr1.colors
andlefse/expr2.colors
if necessary. The colors should be defined in HSV (hue, saturation, value) scale.
Regarding the color file format:
A 150., 100., 53.
B 217., 100., 91.
C 4., 85., 84.
D 39., 100., 100.
If you have used conda
to create a Python 2.7-specific environment for export2graphlan
and GraPhlAn
, for example an environment called graphlan
, you can activate it now to run both programs.
Note: Use
conda deactivate
to deactivate from a currently active conda environment if required.
conda activate graphlan
export2graphlan
and GraPhlAn
in terminal/consoleNote: Remember to change the PATHs to each script accordingly.
Patient vs. control at baseline (expr1)
# Run export2graphlan
/path-to-export2graphlan.py -i lefse/expr1.lefse_table.txt -o lefse/expr1.lefse_table.res.padj \
-t lefse/expr1.graphlan_tree.txt -a lefse/expr1.graphlan_annot.txt --external_annotations 2,3,4,5,6 \
--fname_row 0 --biomarkers2colors lefse/expr1.colors
# Run graphlan
/path-to-graphlan_annotate.py --annot lefse/expr1.graphlan_annot.txt lefse/expr1.graphlan_tree.txt lefse/expr1.graphlan_outtree.txt
# Convert 'lsqb' and 'rsqb' back to square bracket symbols
sed 's/lsqb/[/' lefse/expr1.graphlan_outtree.txt | sed 's/rsqb/]/' > lefse/expr1.graphlan_outtree_sqb.txt
sed 's/lsqb/[/' lefse/expr1.lefse_table.res.padj | sed 's/rsqb/]/' > lefse/expr1.lefse_table.res_sqb.padj
# Create cladogram
/path-to-graphlan.py --dpi 150 lefse/expr1.graphlan_outtree_sqb.txt lefse/expr1.graphlan.png --external_legends --size 8 --pad 0.2
# Convert to readble output
perl /path-to-lefse.pl lefse/expr1.lefse_table.res_sqb.padj lefse/expr1.graphlan_outtree_sqb.txt lefse/expr1.out
Patient at baseline vs. patient at followup (expr2)
# Run export2graphlan
/path-to-export2graphlan.py -i lefse/expr2.lefse_table.txt -o lefse/expr2.lefse_table.res.padj \
-t lefse/expr2.graphlan_tree.txt -a lefse/expr2.graphlan_annot.txt --external_annotations 2,3,4,5,6 \
--fname_row 0 --biomarkers2colors lefse/expr2.colors
# Run graphlan
/path-to-graphlan_annotate.py --annot lefse/expr2.graphlan_annot.txt lefse/expr2.graphlan_tree.txt lefse/expr2.graphlan_outtree.txt
# Convert 'lsqb' and 'rsqb' back to square bracket symbols
sed 's/lsqb/[/' lefse/expr2.graphlan_outtree.txt | sed 's/rsqb/]/' > lefse/expr2.graphlan_outtree_sqb.txt
sed 's/lsqb/[/' lefse/expr2.lefse_table.res.padj | sed 's/rsqb/]/' > lefse/expr2.lefse_table.res_sqb.padj
# Create cladogram
/path-to-graphlan.py --dpi 150 lefse/expr2.graphlan_outtree_sqb.txt lefse/expr2.graphlan.png --external_legends --size 8 --pad 0.2
# Convert to readble output
perl /path-to-lefse.pl lefse/expr2.lefse_table.res_sqb.padj lefse/expr2.graphlan_outtree_sqb.txt lefse/expr2.out
Note: Use
conda deactivate
to deactivate thegraphlan
environment if required.
Patient vs. control at baseline (expr1)
data.frame(fread("lefse/expr1.out"))
res1 = res1[order(res1$order),]
res1 =names(res1)[c(5:7)] = c("Group","LDA","FDR")
$taxon = paste0(res1$taxon, "(",res1$rank, ";", " ",res1$order, ")")
res1$taxon = as.factor(res1$taxon)
res1$taxon = factor(res1$taxon, levels = unique(res1$taxon[order(res1$order, decreasing = T)]))
res1$Group = as.factor(res1$Group)
res1levels(res1$taxon) = gsub("Escherichia_Shigella","Escherichia/Shigella",levels(res1$taxon))
levels(res1$taxon) = gsub("_UCG_","_UCG-",levels(res1$taxon))
Patient at baseline vs. patient at followup (expr2)
data.frame(fread("lefse/expr2.out"))
res2 = res2[order(res2$order),]
res2 =names(res2)[c(5:7)] = c("Group","LDA","FDR")
$taxon = paste0(res2$taxon, "(",res2$rank, ";", " ",res2$order, ")")
res2$taxon = as.factor(res2$taxon)
res2$taxon = factor(res2$taxon, levels = unique(res2$taxon[order(res2$order, decreasing = T)]))
res2$Group = as.factor(res2$Group)
res2levels(res2$taxon) = gsub("Escherichia_Shigella","Escherichia/Shigella",levels(res2$taxon))
levels(res2$taxon) = gsub("_UCG_","_UCG-",levels(res2$taxon))
Patient vs. control at baseline (expr1)
png("lefse/expr1.lefse_table.png", width = 6, height = 5, units = "in", res = 300)
ggplot(res1, aes(taxon, LDA, fill = Group)) + geom_bar(stat = "identity", width = 0.7, size = 0.5) +
coord_flip() + theme_bw() + facet_grid(rows = vars(Group), scales = "free_y", space = "free_y") +
scale_fill_manual(values = c("control" = "blue", "patient" = "red")) +
theme(legend.position = "none",
axis.text.y = element_text(face = "bold", size = 8),
strip.placement = "outside",
strip.text.y = element_text(face = "bold", angle = 0)) +
labs(title = "LEfSe Analysis (Baseline)", x = "Taxon", y = "LDA")
invisible(dev.off())
Patient at baseline vs. patient at followup (expr2)
png("lefse/expr2.lefse_table.png", width = 6, height = 3, units = "in", res = 300)
ggplot(res2, aes(taxon, LDA, fill = Group)) + geom_bar(stat = "identity", width = 0.7, size = 0.5) +
coord_flip() + theme_bw() + facet_grid(rows = vars(Group), scales = "free_y", space = "free_y") +
scale_fill_manual(values = c("baseline" = "blue", "followup" = "red")) +
theme(legend.position = "none",
axis.text.y = element_text(face = "bold", size = 8),
strip.placement = "outside",
strip.text.y = element_text(face = "bold", angle = 0)) +
labs(title = "LEfSe Analysis (followup)", x = "Taxon", y = "LDA")
invisible(dev.off())
save.image(file = "3_lefse_tutorial.RData")
sessionInfo()
## R version 4.1.0 (2021-05-18)
## Platform: x86_64-conda-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.5 LTS
##
## Matrix products: default
## BLAS/LAPACK: /home/ihsuan/miniconda3_4.10.0/envs/r4-16S/lib/libopenblasp-r0.3.15.so
##
## locale:
## [1] LC_CTYPE=en_GB.UTF-8 LC_NUMERIC=C LC_TIME=en_GB.UTF-8
## [4] LC_COLLATE=C LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8
## [7] LC_PAPER=en_GB.UTF-8 LC_NAME=C LC_ADDRESS=C
## [10] LC_TELEPHONE=C LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] grid stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] forcats_0.5.1 stringr_1.4.0 dplyr_1.0.7 purrr_0.3.4
## [5] readr_1.4.0 tidyr_1.1.3 tibble_3.1.2 tidyverse_1.3.1
## [9] ggplot2_3.3.4 phyloseq_1.36.0 data.table_1.14.0 knitr_1.33
##
## loaded via a namespace (and not attached):
## [1] colorspace_2.0-2 hwriter_1.3.2 ellipsis_0.3.2
## [4] XVector_0.32.0 GenomicRanges_1.44.0 fs_1.5.0
## [7] rstudioapi_0.13 bit64_4.0.5 AnnotationDbi_1.54.0
## [10] fansi_0.4.2 lubridate_1.7.10 xml2_1.3.2
## [13] codetools_0.2-18 splines_4.1.0 cachem_1.0.5
## [16] geneplotter_1.70.0 dada2_1.20.0 ade4_1.7-17
## [19] jsonlite_1.7.2 Rsamtools_2.8.0 annotate_1.70.0
## [22] broom_0.7.8 cluster_2.1.2 dbplyr_2.1.1
## [25] png_0.1-7 compiler_4.1.0 httr_1.4.2
## [28] backports_1.2.1 fastmap_1.1.0 assertthat_0.2.1
## [31] Matrix_1.3-4 cli_2.5.0 htmltools_0.5.1.1
## [34] tools_4.1.0 igraph_1.2.6 gtable_0.3.0
## [37] glue_1.4.2 GenomeInfoDbData_1.2.6 reshape2_1.4.4
## [40] ShortRead_1.50.0 Rcpp_1.0.6 Biobase_2.52.0
## [43] cellranger_1.1.0 vctrs_0.3.8 Biostrings_2.60.0
## [46] rhdf5filters_1.4.0 multtest_2.48.0 ape_5.5
## [49] nlme_3.1-152 iterators_1.0.13 xfun_0.24
## [52] ps_1.6.0 rvest_1.0.0 lifecycle_1.0.0
## [55] XML_3.99-0.6 zlibbioc_1.38.0 MASS_7.3-54
## [58] scales_1.1.1 hms_1.1.0 MatrixGenerics_1.4.0
## [61] parallel_4.1.0 SummarizedExperiment_1.22.0 biomformat_1.20.0
## [64] rhdf5_2.36.0 RColorBrewer_1.1-2 yaml_2.2.1
## [67] memoise_2.0.0 RSQLite_2.2.5 latticeExtra_0.6-29
## [70] stringi_1.6.2 highr_0.9 genefilter_1.74.0
## [73] S4Vectors_0.30.0 foreach_1.5.1 permute_0.9-5
## [76] BiocGenerics_0.38.0 BiocParallel_1.26.0 GenomeInfoDb_1.28.0
## [79] rlang_0.4.11 pkgconfig_2.0.3 bitops_1.0-7
## [82] matrixStats_0.59.0 evaluate_0.14 lattice_0.20-44
## [85] Rhdf5lib_1.14.0 GenomicAlignments_1.28.0 bit_4.0.4
## [88] tidyselect_1.1.1 DESeq2_1.32.0 plyr_1.8.6
## [91] magrittr_2.0.1 R6_2.5.0 IRanges_2.26.0
## [94] generics_0.1.0 DelayedArray_0.18.0 DBI_1.1.1
## [97] pillar_1.6.1 haven_2.4.1 withr_2.4.2
## [100] mgcv_1.8-36 KEGGREST_1.32.0 survival_3.2-11
## [103] RCurl_1.98-1.3 modelr_0.1.8 crayon_1.4.1
## [106] utf8_1.2.1 rmarkdown_2.9 jpeg_0.1-8.1
## [109] locfit_1.5-9.4 readxl_1.3.1 blob_1.2.1
## [112] vegan_2.5-7 reprex_2.0.0 digest_0.6.27
## [115] xtable_1.8-4 RcppParallel_5.1.4 stats4_4.1.0
## [118] munsell_0.5.0