-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This dataset consisted of 60 soil samples collected from around 60 kauri trees in the Waitakere Ranges, Auckland, New Zealand, in 2022.
Soil was collected from four cardinal points around each of 60 kauri trees to depth of 10 cm. Soil was pooled together to create one sample per tree before DNA was extracted. DNA was sequenced using amplicon sequencing (Illumina MiSeq) targeting the V3-V4 region of the 16S rRNA gene and the ITS1 gene region of the ITS gene. DNA was also sequenced using shotgun metagenome sequencing (Illumina NovaSeq 6000 S4). All 60 soil samples additionally underwent LAMP analysis to determine the presence and viability of Phytophthora agathidicida.
For this workflow we are looking at comparing amplicon and shotgun metagenome data to determine the taxonomy and functional potential of the soil microbial community surrounding kauri trees. Additionally, we want to assess the concordance of the two sequencing methods in their patterns for determining variation in the microbial communities between PA-detected and PA-not-detected samples (as determined by LAMP analysis).
- Baiting dataset workflow
For a detailed description of the DADA2 pipeline used to generate ASVs, please refer to this GitHub repository.
After processing reads using the standard DADA2 pipeline to generate ASVs we will look at how we can identify the taxonomic composition and functional potential of this community.
After generating the ASVs from the DADA2 pipeline, we can analyse the data using the scripts in the amplicon-data/01_taxonomy_scripts/ directory.
We used PICRUST2 to infer functional potential based on the taxonomic composition of the soil microbial community.
Will be installing PICRUSt2 on z6. Initially I tried to install from bioconda, however, one of the default files was missing (as seen here). To fix this it is suggested to install PICRUSt2 from source, described here.
PICRUSt2 requires a few different input files, described here:
- Sequence file (
.fna) = sequence information of ASVs - Abundance file (
BIOMor.tsv) = sequence abundance information
We can create a BIOM file or edit the output from DADA2 for the abundance information. As I already created a BIOM file for another analysis, I will just use that file. Instructions for creating a BIOM file from a phyloseq object can be found here. Instructions for formatting the DADA2 output to be compatible with PICRUSt2 can be found here.
Filtering low abundance taxa: More information on data pre-processing for PICRUSt2 here.
Running a 10% prevalence filter on the ASVs using 00_asv-prevalence-filtering.R script.
tmux new -s picrust
tmux attach -t picrust
conda activate picrust2
cd picrust2-2.6.1
scripts/picrust2_pipeline.py -s ../picrust-analysis/asv-16s-prev10.fna -i ../picrust-analysis/16S_prev10_biom.biom -o ../picrust-analysis/picrust-output-1404 --stratified -p 10 --verbose >> picrust_log.txtExtract and processing KEGG KO information is discussed in the KEGG KO analysis section below.
Extract ASV sequences (After completion of DADA2 workflow)
# Extract from phyloseq object
asv_seqs <- DNAStringSet(taxa_names(ps)) # Extracts DNA strings
names(asv_seqs) <- paste0("ASV", seq_along(asv_seqs))
# Save to FASTA
writeXStringSet(asv_seqs, filepath = "asvs.fasta")
Build reference database (on NeSI)
Download sequences from NCBI - ITS sequences from Phytophthra agathidicida species
makeblastdb -in phytophthora_refs.fasta -dbtype nucl -out phytophthora_db
Run BLASTn for higher sensitivity
blastn -task blastn \
-query its-asvs.fasta \
-db phytophthora_refs.fasta \
-strand both \
-evalue 1e-10 \
-word_size 24 \
-perc_identity 97 \
-qcov_hsp_perc 90 \
-dust no \
-outfmt "6 qseqid sseqid pident length mismatch gaps qstart qend sstart send evalue bitscore" \
-max_target_seqs 25 > asv_vs_PA_blastn.tsvBLAST analysis
Primer sequences:
>ITS1F
CTTGGTCATTTAGAGGAAGTAA
>ITS2
GCTGCGTTCTTCATCGATGC
The primer binding sites are in the 18S and 5.8S regions.
- ITS1-F: 18S binding (SSU rRNA)
- ITS2: 5.8S binding (LSU rRNA)
-
Check forward primer binding to the SSU (18S rRNA) region
- Download the PA SSU sequence from SILVA (accession number LGTR01001481).
- Run an NCBI pairwise BLAST using the forward primer sequence.
- The BLAST result shows a short 13 bp alignment between the forward primer and the PA SSU sequence, located near the end of the sequence.
- The reverse primer does not bind to this SSU sequence.
-
Check reverse primer binding to the LSU region
- Download LSU rRNA sequence from UNITE database.
- UNITE does not contain specific entries for PA but it does include entries from other Phytophthora species, e.g., P. cinnamomi.
- One relevant entry links to a GenBank accession (L76535.1).
- Download LSU rRNA sequence from UNITE database.
-
Locate LSU in the PA genome
- Use the P. cinnamomi LSU sequence as a query and BLAST it against the PA whole genome in NCBI.
- Results of this search provide coordinates for the LSU region in the PA genome.
- Extend this genomic region slightly to capture the adjacent SSU sequence as well.
-
Final primer alignment test
- Extract the extended LSU–SSU region from the PA genome.
- Run pairwise BLASTs of both the forward and reverse primers against this sequence to determine their binding potential.
To check the primer sequences that do align with the PA genome are in the correct place, I ran a pairwise BLAST with 4 sequences:
- ITS1-F primer
- ITS2 primer
- PA-18S sequence from SILVA (LGTR01001481)
- PA-ITS sequence from NCBI (JX122749.1)
blastn -task blastn-short \
-query its-primers.fasta \
-subject phyt-wg-CP106980.fasta \
-strand both \
-evalue 1000 \
-word_size 7 \
-outfmt "6 qseqid sseqid pident length mismatch gaps qstart qend sstart send evalue bitscore qseq sseq" \
> primer_vs_PA_WG.tsv
-
blastn-short= optimised for short sequences like primers. -
-strand both= searches both forward and reverse-complement orientations. -
-evalue 1000= relaxed for short sequences so nothing is filtered out. -
-word_size 7= smaller word size improves sensitivity for short sequences
Firstly, we will run a series of QC steps to clean and filter the reads before assembly and gene prediction.
- Run FastQC and MultiQC on reads
00_00a-meta-fastqc-slurm.slurm- Transfer outputs to central directory before running
multiqc
- Trim adapters and PhiX reads
-
00_01a-00_01a-trim-adapters-slurm.slurmand00_01b-trim-adapters-workflow.sh -
00_02a-trim-phix-slurm.slurmand00_02b-trim-phix-workflow.sh
-
- Filter out human associated DNA
-
00_03a-human-filt-bbmap-slurm.slurmand00_03b-human-filt-bbmap-workflow.sh
-
To determine the taxonomic composition of the reads in this dataset we can use a few different tools/methods, described here. We will use Kraken2 and Bracken in this workflow.
In addition to running the Kraken2 analysis, we will also use Bracken for better abundance estimates.
The standard kraken2 bacterial and fungal databases have already been downloaded and built on the NeSI HPC. We now need to create the associated Bracken databases. If the database generation fails, you need to remove the files it created before resubmitting the script, if you don't the script will fail with a segmentation fault error - described here.
Build bracken script - 01_00-bracken-build.slurm.
Run kraken2 using scripts 01_01a-kraken-classify-slurm.slurm and 01_01b-kraken-classify-workflow.sh.
Running bracken takes seconds to run and no memory so we can run as a shell script - 01_02a-bracken-report.sh and 01_02b-bracken-workflow.sh.
Now that we have generate the bracken outputs for each sample, we can use the combine_bracken_outputs.py script to combine reports across samples.
# Download script
wget https://raw.githubusercontent.com/jenniferlu717/Bracken/refs/heads/master/analysis_scripts/combine_bracken_outputs.py
# Make script executable
chmod +x combine_bracken_outputs.py
# Move bracken outputs (not reports) to a central directory
mkdir bracken-output
# Create list of directories
find -name "*-bacteria-bracken" > dir-list.txt
# Sanity check for correct number of directories
wc -l dir-list.txt
# For loop to move outputs
for dirnames in $(cat dir-list.txt)
do
cd $dirnames || continue
cp *.bracken ../../../filter-output/bracken-output/bacteria/
cd "$OLDPWD"
done
# Load python module
module purge
module load Python/3.11.6-foss-2023a
# Run combine script
python combine_bracken_outputs.py --files *.bracken --output all-bracken.tsvWith the combined bracken reports, we can add lineage information to the taxIDs using a script from bit.
Firstly, we need to create a list of the taxIDs identified by the kraken2 analysis, we can then run the bit-get-lineage-from-taxids script to obtain the linage information.
# Extract column of taxIDs from bracken analysis
cut -f2 all-fungi-bracken.tsv > fungi-taxid.txt
# Remove the header row
sed '1d' -i fungi-taxid.txt
# Sanity check that number of rows are the same
wc -l all-fungi-bracken.tsv
#93 all-fungi-bracken.tsv (incl header row)
wc -l fungi-taxid.txt
#92 fungi-taxid.txt
# Get lineage information
bit-get-lineage-from-taxids -i fungi-taxid.txt -o fungi-lineages.tsv
# Sanity check that number of rows are the same
wc -l fungi-lineages.tsv
#93 fungi-lineages.tsv (incl header row)
# Combine tables together
paste all-fungi-bracken.tsv fungi-lineages.tsv > fungi-bracken.tsv
This output can now be analysed with the scripts within the folder metagenome-data/01_taxonomy-scripts/R-scripts/.
For functional annotation, we will first filter out non-target DNA such as plant and animal DNA that may be present in our samples.
Using kraken2 we can filter out the DNA we are not interested in against a set of both standard and custom kraken2 databases. These databases have all be built on the NeSI HPC and encompass the following taxonomic groups:
- Plant (standard database)
- Annelida
- Arthropoda
- Chordata
- Mollusca
- Nematoda
- Platyhelminthes
- Tardigrada
- Oomycota
Filtering of DNA can be done using the scripts: 02_01a-kraken-exclude-reads-slurm.slurm and 02_01b-kraken-exclude-reads-workflow.sh.
We can then start functional gene prediction and annotation.
-
Assembly of reads in contigs using
MEGAHIT-
02_02a-megahit-slurm.slurmand02_02b-megahit-workflow.sh
Generate some stats on the assemblies
module purge module load BBMap/39.01-GCC-11.3.0 for sample in LIC034-*/*megahit-assembly/final.contigs.fa do statswrapper.sh in=$sample, format=6 >> assembly-stats.txt done # Tidy up output file to remove extra header rows sed -n '3~2!p' assembly-stats-adj-kmer-settings.txt > assembly-stats-adj-kmer-settings-tidy.txt
-
-
Gene prediction using
prodigal-
02_03a-prodigal-assembly-slurm.slurmand02_03b-prodigal-assembly-workflow.sh. - After running gene prediction we need to prepare the files for creating a non-redundant gene catalogue.
-
Firstly, concatenate all predicted sequences into one master
.fnafile.# Create list of directories find . -type d -name "LIC*-prodigal" > dir-list.txt # Concatenate all .fna files for dirname in $(cat dir-list.txt) do cd $dirname || continue find *.fna | xargs cat >> ../../all-cds.fna cd "$OLDPWD" done
- Next, strip the metadata from the prodigal output for easier handling.
cut -f1 -d ' ' all-cds.fna > all-cds-no-meta.fna
- Adjust ID names using
seqkitas there are likely entries with the same name but different sequences (due to the same contig names being used across the different assemblies).
module purge module load SeqKit/2.4.0 seqkit rename all-cds-no-meta.fna -o all-cds-no-meta-rename.fna
-
-
-
Create a non-redundant gene catalogue
02_04-cd-hit-est.slurm
-
Functional annotation using eggNOG database
02_05-eggnog-annotation.slurm
-
Generate coverage information
02_06a-cds-map-index.slurm-
02_06b-cds-map-reads-slurm.slurmand02_06c-cds-map-reads-workflow.sh 02_06d-coverm-cds.slurm
-
Normalise coverage information
-
02_07a-norm-gene-length.pyand02_07b-norm-gene-length.slurm - Before running the scripts for this section you need to create the
seq-lengths.txtfile
module purge module load SeqKit/2.4.0 seqkit fx2tab --length --name non-redundant-cds.fna > seq-lengths.txt # Optional to convert these base pair counts to kilbase counts # If you do this you have to carry through the rest of your analysis using kilobases # Mathematically using either is fine, its a matter of scaling that will be adjusted #awk '{printf "%s\t%.3f\n", $1, $2 / 1000}' seq-lengths.txt > gen-lengths-kb.txt # Sanity check that all genes were processed wc -l seq-lengths.txt # 8519250 #wc -l non-redundant-cds.fna grep ">" -c non-redundant-cds.fna # 8519250
-
-
Merge coverage and annotation tables
-
02_08a-merge-tables.pyand02_08b-merge-tables.slurm
-
-
Filter out genes that don't have a KO number
-
02_09a-filter-kegg.pyand02_09b-filter-kegg.slurm
-
-
Sum genes by KO number
-
02_10a-sum-abund-by-ko.pyand02_10b-sum-abund-by-ko.slurm
-
To compare functional annotations between PICRUSt2 outputs and eggNOG annotations we can compare the identified KOs by each method. We want to group KOs based on their BRITE hierarchy information. To do this we will pull down information from the list of KOs using kegg_pull, parse the .txt flat files to extract the BRITE text block, then process this parsed output in R to generate a dataframe that has the KOs and their BRITE hierarchy levels split. We can then combine this dataframe with abundance information, normalise using TSS and plot some barcharts.
Firstly, extract a list of KOs identified by eggNOG and PICRUSt2 (two separate lists).
# KO abundance info per sample
shot_dat <- read_tsv("../metagenome/summed_by_ko.tsv") %>%
mutate(KEGG_ko = str_remove(KEGG_ko, "^ko:")) %>%
data.frame() %>%
column_to_rownames(var = "KEGG_ko")
# List of KOs
kos <- rownames(shot_dat)
# Write to file with no quotes or row numbers
writeLines(kos, "kegg-pull/ko_ids.txt")
Run kegg_pull on z6
conda activate kegg_env
cat ko_ids.txt | kegg_pull pull entry-ids - --multi-process --output=ko_entries --sleep-time=8.0
# 1:00:12 to completeUnfortunately, this does not pull down all our KOs in one go and a large portion tend to fail each time. We can extract the names of the failed searches using the 02_11a-extract-failed-kos.py script. The output of this script then becomes the input for kegg_pull. To keep track of the failed and retried KO searches I would rename the pull-results.json and failed_ids.txt files each time I resubmitted. I also move the pull KOs in the ko_entries/ directory into a new central directory so they don't get overwritten.
Some KOs will always fail and this is likely due to depreciated KOs that are no longer present on the KEGG website but are still in the eggNOG database that uses an older version of KEGG. Once the failed list is small enough you can manually check the KOs on the KEGG website to see if they are depreciated.
# Some quick code to find missing KOs (likely depreciated)
ls ko_entries/*.txt | xargs -n1 basename > found_files.txt
sed 's/\.txt$//' found_files.txt > found_files_stripped.txt
comm -23 <(sort ko_ids.txt) <(sort found_files_stripped.txt) > missing_kos.txtOnce all the KO info files have been pulled from KEGG, we can combine the BRITE info into one file using the 02_11b-extract-brite-batch.py script. Copy the output of this script back to a local computer for further analysis with R.
We can extract the mapping information using the kegg-parse-info.R script (in the misc-scripts directory). The output of this script is essentially a mapping file that you can use to link annotated KOs to their function.
This mapping file can now be used with the coverage/abundance information to analyse this data using the scripts in metagenome-data/02_function-scripts/R-scripts/.
After generating all of the outputs from the code described above we can run the scripts within the R-combined-scripts directory to combine the plots from the amplicon and shotgun datasets to compare outputs.