The dada2 ITS Pipeline for Pair_ended Reads - Yanmei-Zhang/DADA2_SchillingLab GitHub Wiki
Welcome to the dada2_SchillingLab wiki! This page will give you an example of step-by-step illustration of dada2 ITS2 pipeline run in RStudio through the interactive HPC resource. This is helpful if you are new to this pipeline and want to have a graphic view of each step. It assumes that you have set up the work environment as shown in the README.md. You can log into the interactive HPC resource such as NICE session and then open the terminal there. You can also run it in your own computer once you have all the software and packages set up in your own device. But it will run slowly if you have large dataset.
The example shown here was sequenced by Miseq 2x300 run at the University of Minnesota Genomic Center (UMGC) by their dual index protocol. The full length of variable ITS2 fragments can be assembled by merging forward and reverse reads.
Part 1: Load the software from the HPC server
# Load the primer trimming tool that will remove the primers
module load cutadapt
# Check the cutadapt path
which cutadpat
## /panfs/roc/msisoft/cutadapt/1.18/bin/cutadapt
# Load RStudio and start it
module load rstudio/2022.02.3 # use the latest version of rstudio and in this version R/4.1.0 is loaded
rstudio
If you are running it on your own computer, you need install cutadapt.
- cutadapt can be installed from here.
Part 2: dada2 ITS2 workflow processed by R/4.1.0
Now you are in Rstudio graphic view. You can navigate to the working folder in Rstudio by clicking on the files tab (In this example: "~/dada2_tutorial"). Then click dada2_pipeline_its2.R to open the R script.
0. Get ready
# Load dada2 and other required packages
library(dada2)
packageVersion("dada2")
## [1] ‘1.20.0’
library(ShortRead)
packageVersion("ShortRead")
## [1] ‘1.50.0’
library(Biostrings)
packageVersion("Biostrings")
## [1] ‘2.60.2’
library(ggplot2)
The example data is located in the tutorial folder you downloaded in the set up step. You can also download here.
# Define data path
data.path <- "~/dada2_tutorial/example/ITS2" # Change it to YOUR data folder
list.files(data.path)
## [1] "Q23_ITS_S185_R1_001.fastq.gz" "Q23_ITS_S185_R2_001.fastq.gz"
## [3] "Q24_ITS_S197_R1_001.fastq.gz" "Q24_ITS_S197_R2_001.fastq.gz"
## [5] "Q25_ITS_S209_R1_001.fastq.gz" "Q25_ITS_S209_R2_001.fastq.gz"
## [7] "Q26_ITS_S221_R1_001.fastq.gz" "Q26_ITS_S221_R2_001.fastq.gz"
## [9] "Q27_ITS_S233_R1_001.fastq.gz" "Q27_ITS_S233_R2_001.fastq.gz"
## [11] "Q28_ITS_S245_R1_001.fastq.gz" "Q28_ITS_S245_R2_001.fastq.gz"
# Generate matched lists of the forward and reverse read files, as well as parsing out the sample name.
fnFs <- sort(list.files(data.path, pattern = "_R1_001.fastq.gz", full.names = TRUE))
fnRs <- sort(list.files(data.path, pattern = "_R2_001.fastq.gz", full.names = TRUE))
# Set up work path in YOUR directory where you want data; you can also use the same path as the data is in, but it was nice to keep the data folder as original and store the processed data in another folder.
work.path <- "~/dada2_tutorial/dada2_ITS2" # Change it to YOUR work path
# Set up names of sub directories to stay organized
preprocess.fp <- file.path(work.path, "01_preprocess")
filtN.fp <- file.path(preprocess.fp, "filtN")
cut.fp <- file.path(preprocess.fp, "cutadapt")
filter.fp <- file.path(work.path, "02_filter")
table.fp <- file.path(work.path, "03_tabletax")
1. Pre-processing data for dada2 - remove sequences with Ns, remove primers with cutadapt
1.1 Remove Sequences with Ns
The presence of ambiguous bases (Ns) in the sequencing reads makes accurate mapping of short primer sequences difficult. To solve this problem, the sequences with ambiguous bases (Ns) will be removed.
# “Pre-filter” the sequences just to remove those with Ns, but perform no other filtering.
fnFs.filtN <- file.path(preprocess.fp, "filtN", basename(fnFs)) # Put N-filterd files in filtN/ subdirectory
fnRs.filtN <- file.path(preprocess.fp, "filtN", basename(fnRs))
trimN <- filterAndTrim(fnFs, fnFs.filtN, fnRs, fnRs.filtN, maxN = 0, multithread = TRUE)
head(trimN)
## reads.in reads.out
## Q23_ITS_S185_R1_001.fastq.gz 45666 45666
## Q24_ITS_S197_R1_001.fastq.gz 41782 41781
## Q25_ITS_S209_R1_001.fastq.gz 56977 56974
## Q26_ITS_S221_R1_001.fastq.gz 51472 51467
## Q27_ITS_S233_R1_001.fastq.gz 69681 69679
## Q28_ITS_S245_R1_001.fastq.gz 58241 58238
1.2 Remove Primers
The the primers sequences are removed by running cutadapt. First, assign the primers you used to "FWD" and "REV" below. Change it your primers if different.
# Identify primers
FWD <- "TCGATGAAGAACGCAGCG" #5.8SR # Change it to YOUR sequencing primer
REV <- "TCCTCCGCTTATTGATATGC" #ITS4 # Change it to YOUR sequencing primer
# A function to create a list of all orientations of primers
allOrients <- function(primer) {
# Create all orientations of the input sequence
require(Biostrings)
dna <- DNAString(primer) # The Biostrings works w/ DNAString objects rather than character vectors
orients <- c(Forward = dna, Complement = complement(dna), Reverse = reverse(dna),
RevComp = reverseComplement(dna))
return(sapply(orients, toString)) # Convert back to character vector
}
# Save the primers orientations to pass along to cutadapt
FWD.orients <- allOrients(FWD)
REV.orients <- allOrients(REV)
FWD.orients
## Forward Complement Reverse
## "TCGATGAAGAACGCAGCG" "AGCTACTTCTTGCGTCGC" "GCGACGCAAGAAGTAGCT"
## RevComp
## "CGCTGCGTTCTTCATCGA"
REV.orients
## Forward Complement Reverse
## "TCCTCCGCTTATTGATATGC" "AGGAGGCGAATAACTATACG" "CGTATAGTTATTCGCCTCCT"
## RevComp
## "GCATATCAATAAGCGGAGGA"
# A function to count the number of times the primers appear in the forward and reverse read, while considering all possible primer orientations.
primerHits <- function(primer, fn) {
# Counts number of reads in which the primer is found
nhits <- vcountPattern(primer, sread(readFastq(fn)), fixed = FALSE)
return(sum(nhits > 0))
}
# Check the primers for the first sample before running the cutadapt.
rbind(FWD.ForwardReads = sapply(FWD.orients, primerHits, fn = fnFs.filtN[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)),
FWD.ReverseReads = sapply(FWD.orients, primerHits, fn = fnRs.filtN[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)),
REV.ForwardReads = sapply(REV.orients, primerHits, fn = fnFs.filtN[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)),
REV.ReverseReads = sapply(REV.orients, primerHits, fn = fnRs.filtN[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)))
## Forward Complement Reverse RevComp
## FWD.ForwardReads 40740 0 0 0
## FWD.ReverseReads 2 0 0 25
## REV.ForwardReads 2 0 0 40
## REV.ReverseReads 43881 0 0 0
As expected, the FWD primer is found in the forward reads in its forward orientation, and in some of the reverse reads in its reverse-complement orientation (due to read-through when the ITS region is short). Similarly the REV primer is found with its expected orientations.
Next, we remove Primers by running cutadapt
# Remove Primers
cutadapt <- "/panfs/roc/msisoft/cutadapt/1.18/bin/cutadapt"# CHANGE ME to the cutadapt path on your machine
system2(cutadapt, args = "--version") # Run shell commands from R
## 2.10
if(!dir.exists(cut.fp)) dir.create(cut.fp)
fnFs.cut <- file.path(cut.fp, basename(fnFs))
fnRs.cut <- file.path(cut.fp, basename(fnRs))
FWD.RC <- dada2:::rc(FWD)
REV.RC <- dada2:::rc(REV)
# Trim FWD and the reverse-complement of REV off of R1 (forward reads)
R1.flags <- paste("-g", FWD, "-a", REV.RC)
# Trim REV and the reverse-complement of FWD off of R2 (reverse reads)
R2.flags <- paste("-G", REV, "-A", FWD.RC)
# Run Cutadapt
for(i in seq_along(fnFs)) {
system2(cutadapt, args = c(R1.flags, R2.flags, "-n", 2, # -n 2 required to remove FWD and REV from reads
"-o", fnFs.cut[i], "-p", fnRs.cut[i], # output files
"-m", 1, # specify the minimum length as some downstream tools such as PlotQualityProfile
# may have problems with zero-length sequences
fnFs.filtN[i], fnRs.filtN[i])) # input files
}
# Count the presence of primers in the first cutadapt-ed sample
rbind(FWD.ForwardReads = sapply(FWD.orients, primerHits, fn = fnFs.cut[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)),
FWD.ReverseReads = sapply(FWD.orients, primerHits, fn = fnRs.cut[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)),
REV.ForwardReads = sapply(REV.orients, primerHits, fn = fnFs.cut[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)),
REV.ReverseReads = sapply(REV.orients, primerHits, fn = fnRs.cut[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)))
## Forward Complement Reverse RevComp
## FWD.ForwardReads 0 0 0 0
## FWD.ReverseReads 2 0 0 0
## REV.ForwardReads 2 0 0 0
## REV.ReverseReads 0 0 0 0
Success! Primers are no longer detected in the cutadapted reads.
# Forward and reverse fastq filenames have the format:
cutFs <- sort(list.files(cut.fp, pattern = "_R1_001.fastq.gz", full.names = TRUE))
cutRs <- sort(list.files(cut.fp, pattern = "_R2_001.fastq.gz", full.names = TRUE))
# Extract sample names, assuming filenames have format:
get.sample.name <- function(fname) strsplit(basename(fname), "_")[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)[1]
sample.names <- unname(sapply(cutFs, get.sample.name))
head(sample.names)
## [1] "Q23" "Q24" "Q25" "Q26" "Q27" "Q28"
sample.namesR <- unname(sapply(cutRs, get.sample.name))
if(!identical(sample.names, sample.namesR)) stop("Forward and reverse files do not match.")
2. Run dada2 pipeline
2.1 Inspect Read Quality Profiles
From the dada2 tutorial:
In gray-scale is a heat map of the frequency of each quality score at each base position. The median quality score at each position is shown by the green line, and the quartiles of the quality score distribution by the orange lines. The red line shows the scaled proportion of reads that extend to at least that position.
# Inspect read quality profiles
# If the number of samples is 10 or less, plot them all, otherwise, just plot 10 randomly selected samples
if( length(cutFs) <= 10) {
fwd_qual_plots <- plotQualityProfile(cutFs)
rev_qual_plots <- plotQualityProfile(cutRs)
} else {
rand_samples <- sample(size = 10, 1:length(cutFs)) # grab 20 random samples to plot
fwd_qual_plots <- plotQualityProfile(paste0(cutFs[rand_samples]))
rev_qual_plots <- plotQualityProfile(paste0(cutRs[rand_samples]))
}
if(!dir.exists(filter.fp)) dir.create(filter.fp)
ggsave(paste0(filter.fp, "/its2_fwd_qual_10.png"), fwd_qual_plots)
ggsave(paste0(filter.fp, "/its2_rev_qual_10.png"), rev_qual_plots)
fwd_qual_plots

rev_qual_plots

# Put filtered reads into separate sub-directories for big data workflow
subF.fp <- file.path(filter.fp, "filt_F")
subR.fp <- file.path(filter.fp, "filt_R")
dir.create(subF.fp)
dir.create(subR.fp)
2.2 Fiter and Trim
Before chosing sequence variants, we want to trim reads where their quality scores begin to drop (the truncLen and truncQ values) and remove any low-quality reads that are left over after we have finished trimming (the maxEE value).
From dada2 tutorial:
If there is only one part of any amplicon bioinformatics workflow on which you spend time considering the parameters, it should be filtering! The parameters ... are not set in stone, and should be changed if they don’t work for your data. If too few reads are passing the filter, increase maxEE (perhaps especially on the reverse reads) and/or reduce truncQ. If quality drops sharply at the end of your reads, reduce truncLen. If your reads are high quality and you want to reduce computation time in the sample inference step, reduce maxEE.
Considerations for your own data:
THESE PARAMETERS ARE NOT OPTIMAL FOR ALL DATASETS. Make sure you try and determine the trim and filtering parameters for your data .
Due to the expected variable read lengths in ITS data you should run this command without the trunclen parameter. See here for more information and appropriate parameters for ITS data.
# Filter and Trim
filtFs <- file.path(subF.fp, basename(cutFs))
filtRs <- file.path(subR.fp, basename(cutRs))
#
out <- filterAndTrim(cutFs, filtFs, cutRs, filtRs, maxN = 0, maxEE = c(2, 5),
truncQ = 2, minLen = 50, rm.phix = TRUE, compress = TRUE, multithread = TRUE) # on windows, set multithread = FALSE
head(out)
## reads.in reads.out
## Q23_ITS_S185_R1_001.fastq.gz 45666 31514
## Q24_ITS_S197_R1_001.fastq.gz 41781 28024
## Q25_ITS_S209_R1_001.fastq.gz 56974 40868
## Q26_ITS_S221_R1_001.fastq.gz 51467 34088
## Q27_ITS_S233_R1_001.fastq.gz 69679 47830
## Q28_ITS_S245_R1_001.fastq.gz 58238 39014
2.3 Infer Sequence Variants and Merge
In this part of the pipeline dada2 will learn to distinguish error from biological differences using a subset of our data as a training set. After it understands the error rates, we will reduce the size of the dataset by combining all identical sequence reads into "unique sequences". Then, using the dereplicated data and error rates, dada2 will infer the sequence variants (ASVs) in our data. Finally, we will merge the corresponding forward and reverse reads to create a list of the fully denoised sequences and create a sequence table from the result.
Learn the Error Rates
# Set seed to ensure that randomized steps can be replicated
set.seed(100)
# Learn the Error Rates
errF <- learnErrors(filtFs, multithread = TRUE)
## 62630680 total bases in 221338 reads from 6 samples will be used for learning the error rates.
errR <- learnErrors(filtRs, multithread = TRUE)
## 62135669 total bases in 221338 reads from 6 samples will be used for learning the error rates.
errF_plot <- plotErrors(errF, nominalQ = TRUE)
errR_plot <- plotErrors(errR, nominalQ=TRUE)
ggsave(paste0(filter.fp, "/its2_errF_plot.png"), errF_plot)
ggsave(paste0(filter.fp, "/its2_errR_plot.png"), errR_plot)
We want to make sure that the machine learning algorithm is learning the error rates properly. In the plots below, the red line represents what we should expect the learned error rates to look like for each of the 16 possible base transitions (A->A, A->C, A->G, etc.) and the black line and grey dots represent what the observed error rates are. If the black line and the red lines are very far off from each other, it may be a good idea to increase the nbases parameter. This allows the machine learning algorithm to train on a larger portion of your data and may help improve the fit.
errF_plot
errR_plot

Dereplication, Sequence Inference, and Merging of paired-end Reads
In this part of the pipeline, dada2 will make decisions about assigning sequences to ASVs (called "sequence inference"). There is a major parameter option in the core function dada() that changes how samples are handled during sequence inference. The parameter pool = can be set to: pool = FALSE (default), pool = TRUE, or pool = psuedo. For details on parameter choice, please see below, and further information and explanation on the this dada2 tutorial.
Details
pool = FALSE: Sequence information is not shared between samples. Fast processing time, less sensitivity to rare taxa.
pool = psuedo: Sequence information is shared in a separate "prior" step. Intermediate processing time, intermediate sensitivity to rare taxa.
pool = TRUE: Sequence information from all samples is pooled together. Slow processing time, most sensitivity to rare taxa.
Default: SAMPLES NOT POOLED
For simple communities or when you do not need high sensitivity for rare taxa
# make lists to hold the loop output
mergers <- vector("list", length(sample.names))
names(mergers) <- sample.names
ddF <- vector("list", length(sample.names))
names(ddF) <- sample.names
ddR <- vector("list", length(sample.names))
names(ddR) <- sample.names
# For each sample, get a list of merged and denoised sequences
for(sam in sample.names) {
cat("Processing:", sam, "\n")
# Dereplicate forward reads
derepF <- derepFastq(filtFs[sam](/Yanmei-Zhang/DADA2_SchillingLab/wiki/sam))
# Infer sequences for forward reads
ddF[sam]] <- dada(derepF, err=errF, multithread=TRUE)
# Dereplicate reverse reads
derepR <- derepFastq(filtRs[sam](/Yanmei-Zhang/DADA2_SchillingLab/wiki/sam))
# Infer sequences for reverse reads
ddR[sam](/Yanmei-Zhang/DADA2_SchillingLab/wiki/sam) <- dada(derepR, err = errR, multithread = TRUE)
# Merge reads together
merger <- mergePairs(ddF[sam](/Yanmei-Zhang/DADA2_SchillingLab/wiki/sam), derepF, ddR[sam](/Yanmei-Zhang/DADA2_SchillingLab/wiki/sam), derepR)
mergers[sam](/Yanmei-Zhang/DADA2_SchillingLab/wiki/sam) <- merger
}
rm(derepF); rm(derepR)
Alternative: SAMPLES POOLED
For complex communities when you want to preserve rare taxa alternative: swap pool = TRUE with pool = "pseudo"
# Dereplicate identical reads
derepFs <- derepFastq(filtFs, verbose = TRUE)
derepRs <- derepFastq(filtRs, verbose = TRUE)
# Name the derep-class objects by the sample names
names(derepFs) <- sample.names
names(derepRs) <- sample.names
# Sample Inference
dadaFs <- dada(derepFs, err = errF, multithread = TRUE, pool = TRUE)
## 6 samples were pooled: 221338 reads in 41077 unique sequences.
dadaRs <- dada(derepRs, err = errR, multithread = TRUE, pool = TRUE)
## 6 samples were pooled: 221338 reads in 95169 unique sequences.
# Inspecting the returned dada-class object:
dadaFs[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1)
## dada-class: object describing DADA2 denoising results
## 467 sequence variants were inferred from 6824
## input unique sequences.
## Key parameters: OMEGA_A = 1e-40, OMEGA_C = 1e-40, BAND_SIZE = 16
# Merge paired reads
mergers <- mergePairs(dadaFs, derepFs, dadaRs, derepRs, verbose=TRUE)
## 28058 paired-reads (in 334 unique pairings) successfully merged out of 31000 (in 529 pairings) input.
## 23470 paired-reads (in 416 unique pairings) successfully merged out of 26951 (in 616 pairings) input.
## 32289 paired-reads (in 335 unique pairings) successfully merged out of 40464 (in 574 pairings) input.
## 30334 paired-reads (in 433 unique pairings) successfully merged out of 33188 (in 664 pairings) input.
## 39917 paired-reads (in 325 unique pairings) successfully merged out of 47252 (in 534 pairings) input.
## 34275 paired-reads (in 380 unique pairings) successfully merged out of 38488 (in 614 pairings) input.
#Inspect the merger data.frame from the first sample
head(mergers[1](/Yanmei-Zhang/DADA2_SchillingLab/wiki/1))
# Construct Sequence Table
seqtab <- makeSequenceTable(mergers)
dim(seqtab)
## [1] 6 968
# Inspect distribution of sequence lengths
table(nchar(getSequences(seqtab)))
2.4 Remove Chimeras and Summary of Reads
Although dada2 has searched for indel errors and substitutions, there may still be chimeric sequences in our dataset (sequences that are derived from forward and reverse sequences from two different organisms becoming fused together during PCR and/or sequencing). To identify chimeras, we will search for rare sequence variants that can be reconstructed by combining left-hand and right-hand segments from two more abundant "parent" sequences. After removing chimeras, we will use a taxonomy database to train a classifer-algorithm to assign names to our sequence variants.
# Remove Chimeras
seqtab.nochim <- removeBimeraDenovo(seqtab, method="consensus", multithread=TRUE, verbose=TRUE)
## Identified 257 bimeras out of 968 input sequences.
dim(seqtab.nochim)
## [1] 6 711
table(nchar(getSequences(seqtab.nochim)))
# Print percentage of our seqences that were not chimeric.
sum(seqtab.nochim)/sum(seqtab)
## [1] 0.9159884
# Track reads through the pipeline
getN <- function(x) sum(getUniques(x))
track <- cbind(out, sapply(dadaFs, getN), sapply(dadaRs, getN), sapply(mergers, getN), rowSums(seqtab.nochim))
# If processing a single sample, remove the sapply calls: e.g. replace sapply(dadaFs, getN) with getN(dadaFs)
colnames(track) <- c("input", "filtered", "denoisedF", "denoisedR", "merged", "nonchim")
rownames(track) <- sample.names
head(track)
## input filtered denoisedF denoisedR merged nonchim
## Q23 45666 31514 31183 31172 28058 23580
## Q24 41781 28024 27484 27179 23470 22340
## Q25 56974 40868 40608 40614 32289 29435
## Q26 51467 34088 33598 33390 30334 28682
## Q27 69679 47830 47488 47452 39917 36936
## Q28 58238 39014 38690 38623 34275 31547
Looks good! We kept the majority of our raw reads, and there is no over-large drop associated with any single step.
From dada2 tutorial: This is a great place to do a last sanity check. Outside of filtering (depending on how stringent you want to be) there should no step in which a majority of reads are lost. If a majority of reads were removed as chimeric, you may need to revisit the removal of primers, as the ambiguous nucleotides in unremoved primers interfere with chimera identification. If a majority of reads failed to merge, the culprit could also be unremoved primers, but could also be due to biological length variation in the sequenced ITS region that sometimes extends beyond the total read length resulting in no overlap.
# Save file
if(!dir.exists(table.fp)) dir.create(table.fp)
write.table(t(seqtab.nochim), paste0(table.fp, "/dada2_its2_counts.txt"), sep="\t", quote=F, row.names=T)
write.table(track , paste0(table.fp, "/dada2_its2_track.txt"), sep="\t", quote=F, row.names = T)
2.5 Assign Taxonomy
Here is a link to download the database we need.
# Assign taxonomy
unite.ref <- "~/dada2_tutorial/db_files/sh_general_release_dynamic_16.10.2022.fasta" # Change it to location on YOUR device
taxa <- assignTaxonomy(seqtab.nochim, unite.ref, multithread = TRUE, tryRC = TRUE)
## UNITE fungal taxonomic reference detected.
taxa.print <- taxa # Removing sequence rownames for display only
rownames(taxa.print) <- NULL
head(taxa.print)
## Kingdom Phylum Class
## [1,] "k__Fungi" "p__Basidiomycota" "c__Agaricomycetes"
## [2,] "k__Fungi" "p__Ascomycota" "c__Sordariomycetes"
## [3,] "k__Fungi" "p__Basidiomycota" "c__Agaricomycetes"
## [4,] "k__Fungi" "p__Ascomycota" "c__Leotiomycetes"
## [5,] "k__Fungi" "p__Ascomycota" "c__Leotiomycetes"
## [6,] "k__Fungi" "p__Basidiomycota" "c__Agaricomycetes"
## Order Family Genus
## [1,] "o__Auriculariales" "f__Hyaloriaceae" "g__Stypella"
## [2,] "o__Sordariales" "f__Podosporaceae" "g__Podospora"
## [3,] "o__Auriculariales" "f__Hyaloriaceae" "g__Stypella"
## [4,] "o__Helotiales" "f__Mollisiaceae" "g__Phialocephala"
## [5,] "o__Helotiales" "f__Helotiaceae" "g__Ascocoryne"
## [6,] "o__Polyporales" "f__Meruliaceae" "g__Ceraceomyces"
## Species
## [1,] "s__grilletii"
## [2,] NA
## [3,] "s__subgelatinosa"
## [4,] "s__catenospora"
## [5,] "s__cylichnium"
## [6,] "s__tessulatus"
write.table(taxa, paste0(table.fp, "dada2_its2_taxa.txt"), sep="\t", quote=F, row.names = T)
seqtable.taxa<- cbind('#seq'=rownames(taxa), t(seqtab.nochim), taxa)
write.table(seqtable.taxa, paste0(table.fp, "dada2_its2_counts.taxon.species.txt"), sep="\t", quote=F, row.names=F)
save.image(file= paste0(work.path, "/dada2_its2.RData"))
Summary of output files:
dada2_its2_counts.txt - A tab-delimited sequence-by-sample (i.e. OTU) table
dada2_its2_taxa.txt - a tab-demilimited file showing taxonomy information
dada2_its2_counts.taxon.species.txt - a tab-delimited file with sequence as rows, samples as columns and the last few columns showing the taxonomy of the ASV sequence
dada2_its2_track.txt - a tab-delimited file showing the tracking process of reads in each step