High Read Loss Due to Poor Merging and Chimeras During DADA denoising

Hi QIIME forum!

I am currently stuck at the denoising phase, where my data has really low pair-end merging rates and lots of loss due to chimeras. I am a total newbie to metabarcoding so while I have read a lot of posts on the forum and tweaked some parameters, I would love some specific guidance on my project. I (briefly) include my pipeline in case I am missing something in the early stages that's contributing to the problem.

Background: I am running a diet study on Piping Plover fecal samples using two genes, COI (ANML primer; Jusino et al. (2019), target amplicon length 157bp) and 16S (16S degenerate primers; Deagle et al. (2008), target amplicon length 190-210bp) using Novaseq 2x150 bp. I received demultiplexed data from the sequencer (as in, every fastq.gz file was R1 or R2 of a sample) and did further 'demultiplexing' to parse each sample into COI and 16S data respectively, similar to this QIIME forum post.

My pipeline is as follows:

  1. Trimming primers with standalone cutadapt (no quality filters, just pulling reads with target primers into their respective files)
    • 16S:

      cutadapt -g ^GACGAKAAGACCCTA -G ^CGCTGTTATCCCTADRGTAACT \
      --p-discard-untrimmed \
      -o trim-16s/${s}.R1.fastq.gz \
      -p trim-16s/${s}.R2.fastq.gz \
      ./${s}.R1.fastq.gz ./${s}.R2.fastq.gz 
      
    • COI:

      cutadapt 
      -g ^GGTCAACAAATCATAAAGATATTGG -G ^GGWACTAATCAATTTCCAAATCC \ 
      --p-discard-untrimmed \	
      -o trim-coi/${s}.R1.fastq.gz \	
      -p trim-coi/${s}.R2.fastq.gz \	
      ./${s}.R1.fastq.gz ./${s}.R2.fastq.gz 
      
  2. Import to QIIME + check quality of demultiplexing
  3. ASV Denoising with DADA (I decided not to do any truncating because I felt that the quality drops I saw in my data were scattered rather than dropping towards the ends of reads, so I opted for --p-trunc-q = 20 instead. I chose --p-min-overlap = 25 following advice here)
    • 16S:16S-denoising-stats.qzv (344.5 KB)

    • qiime dada2 denoise-paired --i-demultiplexed-seqs 16S-trim.qza \
      --p-trunc-len-f 0 --p-trunc-len-r 0 \
      --p-trunc-q 20 --p-min-overlap 25 \
      --o-representative-sequences 16S-representative-sequences.qza \
      --o-table 16S-table.qza \
      --o-denoising-stats 16S-denoising-stats.qza \
      --o-base-transition-stats 16S-base-transition-stats.qza
      

      COI:COI-denoising-stats.qzv (345.9 KB)

      qiime dada2 denoise-paired --i-demultiplexed-seqs .COI-trim.qza \
      --p-trunc-len-f 0 --p-trunc-len-r 0 \
      --p-trunc-q 20 --p-min-overlap 25 \
      --o-representative-sequences COI-representative-sequences.qza \
      --o-table COI-table.qza \
      --o-denoising-stats COI-denoising-stats.qza \
      --o-base-transition-stats COI-base-transition-stats.qza
      

I have the denoising qzv files linked, but here's screenshots of the COI one for illustrative purposes. Majority of my reads pass filtering, only to get really pinched in merging and chimera filtering. I am not sure why... I do also notice that the % retained for merged reads and chimeras are very similar, but am not sure if that means they are linked or related in any way.

I have a few ideas based on various forum posts about why this issue is occurring, but I am not sure if the issue stems from a denoising parameter or something further up the pipeline.

  1. I read posts like this and this that suggest remnant primers/ non-biological sequences may cause paired end reads to merge incorrectly or get flagged as chimeras, but I'm pretty sure I did the primer trimming right. I do use anchored primers (with ^ added to the g flag) during the trimming step, which I chose because the cutadapt documentation said it was useful for merging overlapping paired end reads. Do you see any issues with the way I've trimmed the data?
  2. Additionally, is my reasoning for choosing not to truncate reads sound? I had previously attempted denoising where 16S was truncated to --p-trunc-len-f 135 and --p-trunc-len-r 128, while COI was set to --p-trunc-len-f 125 and --p-trunc-len-r 126, but only 10-13% of reads passed filtering after that. At the time, I wasn't aware that reads shorter than the trunc-len get discarded, so I could maybe try truncating to an even shorter length like 130+120 for 16S and 110+110 for COI, but I'm not sure if that is a productive line of thinking.
  3. I am aware that I can set the --p-min-fold-parent-over-abundance to 8 or 16 to address some of the chimeras, but should I focus on improving the merging rates first? Does chimera removal come after merging or are they done at the same time?

Hopefully this was detailed enough without getting too long, I really appreciate those of you who gave this a read! Thanks!

Hello Clare,

This is a really detailed post! This is a classic issue trying to get reads to join with custom primers!

I think you are on the right track.

First, you have plenty of overlap to make merging possible:

So... how can we get this to play nice with DADA2?
Here are the docs for qiime dada2 denoise-pairs :memo:

Let's dive in :diving_mask:


First, this setting makes your reads variable length before joining.

trunc_q: Int
Reads are truncated at the first instance of a quality score less than or equal to this value.

I can see this for single-end reads, but I don't use this when I try to merge paired-end reads.


Second, did you know that a long area of overlap cases fewer reads to join because of this setting?

max_merge_mismatch: Int
The maximum number of mismatches allowed in the overlap region when merging reads. If 0, only exact overlaps are allowed.

Because the default is zero, any error in the area of overlap will cause these reads not to merge. With 50 to 90 bases overlap, some errors are expected. And you can even see the errors that need to be addressed in R1 on the quality plot!

I would try adding --max_merge_mismatch 20 to --p-min-overlap 25 so the reads are still overlapped but now allow mismatches.


When working on DADA2 setting for a run, I work across that table from left to right, trying to keep the numbers up as I work through.

For the COI file: filtering :white_check_mark: > denoising :white_check_mark: > merging :grimacing: > chimera checking :pause_button:

Hopefully once we fix the merging issue, the chimera number will look more normal :slight_smile:

Let's return to this check if the chimera seem high. Could be fine!

The quality plots after cutadapt look okay!

If you import raw data then run cutadapt in qiime2, you can see the quality plots before and after running cutadapt! This could be helpful! Like, does cutadapt make the quality look better? :thinking:

Yes! I can follow your logic through all of this. I think the only missing piece is that --max_merge_mismatch is 0 by default, which is just perfectly bad for your long-overlap reads.

When I get new primers, I usually run DADA2 five to ten times to find good settings. :repeat_button:

Let me what settings you run next!

Hi Colin,

Thank you so much for your detailed response! I have some followup questions:

  1. If trunc-q is not an appropriate setting for paired end data, do you have any suggestions for how to handle reads with quality scores of <24? Would I be able to discard them after merging or do some other quality filtering once the merging is complete? I recently learned that Novaseq uses binned quality scores, so I am worried about the 'true' quality of the poorer quality reads. In previous runs of the standalone Cutadapt I did try to run quality filtering, but was told by a collaborator that that would cause problems with read merging. Also, RE your suggestion

If you import raw data then run cutadapt in qiime2, you can see the quality plots before and after running cutadapt!

I chose to use standalone Cutadapt instead of the one integrated into QIIME because I had some 'fun artifacts' in my data (e.g. not all samples were sequenced for both target genes, but because they were all pooled together in a single lane, it was easier to leave the demultiplexed sample files as individual fastqs, trim the primers off, manipulate individual samples files as needed before importing them all into QIIME, where they are saved as a single qza). I suppose I could try using FastQC or something to assess the quality before Cutadapt...

  1. Concerning --max_merge_mismatch, is this parameter applied across the entire overlapping region/ does it function separately than --p-min-overlap? i.e., if a given pair of reads overlap by 90bp, the allowed mismatch of --max_merge_mismatch 20 would be applied across the 90bp versus within the --p-min-overlap 25 that I specified?

I have rerun the denoising with --max_merge_mismatch 20 and sans trunc_q as you've suggested, so i will update with results when I have them. Thanks again for taking the time to explain!

Hi Clare,

These are great!

No, reads are trimmed first ( --p-trunc-len-f 0 --p-trunc-len-r 0 \--p-trunc-q 20 )
Then expected-error filtering remove reads with many errors
Then denoising, merging, and chimera checking.

Ah, I'm still recommending expected-error filtering! It's on by default and it works better than trunc-q! Detailed guide on why we use expected-error instead of average q-score:

Right, and this is why it's all the more important to track exactly how you fixed these problems. I'm suggesting that you repeat this full pipeline in Qiime2, because then each .qzv and .qza file will have the full history if how this raw data was processed allowing replication in the future. It is a lot of work!

--p-min-overlap 25 is applied first, when the R1 and R2 for that ASV are being merged. Then the best merge for that ASV is only kept if the number of differences is under --max_merge_mismatch.

Because the overlap region is longer for COI, you might want to use a higher number?

We would expect more mismatches in the longer overlap!

I suggested --max_merge_mismatch 20 to cover both, but 20/55 is like 36% mismatch accepted for the 16S primer, and that's probably too high.

Yes please! There's no better test then to run it yourself, so I'm excited to see what you find

Hi Colin,

Thanks for your response! I have the results back from the denoising without trunc_q and with max_merge_mismatch. Unfortunately, they are only very slightly better, the average % merged reads has gone from 14.2% to 15.7% for COI and from 10.5% to 11.2% for 16S.

16S-denoising-stats.qzv (345.5 KB)

COI-denoising-stats.qzv (346.9 KB)

qiime dada2 denoise-paired --i-demultiplexed-seqs ./import2qiime/COI-trim.qza 
--p-trunc-len-f 0 --p-trunc-len-r 0 --p-min-overlap 25 
--p-max-merge-mismatch 20 
--o-representative-sequences ./asv-denoise/COI-representative-sequences.qza 
--o-table ./asv-denoise/COI-table.qza --o-denoising-stats ./asv-denoise/COI-denoising-stats.qza 
--o-base-transition-stats ./asv-denoise/COI-base-transition-stats.qza --p-n-threads 32

qiime dada2 denoise-paired --i-demultiplexed-seqs ./import2qiime/16S-trim.qza 
--p-trunc-len-f 0 --p-trunc-len-r 0 --p-min-overlap 25 
--p-max-merge-mismatch 20 
--o-representative-sequences ./asv-denoise/16S-representative-sequences.qza 
--o-table ./asv-denoise/16S-table.qza --o-denoising-stats ./asv-denoise/16S-denoising-stats.qza 
--o-base-transition-stats ./asv-denoise/16S-base-transition-stats.qza --p-n-threads 32

I had already run the 16S denoising with --p-max-merge-mismatch 20 when I read your reply, and will definitely lower that in future runs, but I was curious if you see anything else that may improve the paired end merging? Maybe I should tweak the max-ee parameters?:thinking:

I understand (and agree) that this is good practice, but when I was looking into how to remove or rename specific samples within qzas, I was brand new to QIIME and could only find 'old' documentation on doing so (e.g. rename-ids: Renames sample or feature ids in a table — QIIME 2 2024.10.1 documentation and Filtering data — QIIME 2 2024.2.0 documentation). Now that I understand qiime a little better and know what to look for within the current documentation, this is certainly a route I could pursue, though I am under a bit of a tight deadline right now and want to make sure it will be worth the effort in the short term :face_with_peeking_eye: ( I will certainly rectify this for publication). Do you think seeing the raw data in QIIME will help us understand what's going on with the poor merging, or could we try something else first?

Thank you again for your time and help!

Sincerely,

Clare

Interesting... Well, maybe we need to do something about the low quality ends of the reads?

I'm hoping that shorting trimming of the low quality ends of R1 and R2 will help with merging?

COI: 125+126 - 157 = 94
COI new: 100+100-157 = 43

qiime dada2 denoise-paired \
  --i-demultiplexed-seqs ./import2qiime/COI-trim.qza \
  --p-trunc-len-f 100 --p-trunc-len-r 100 \
  --p-min-overlap 30 --p-max-merge-mismatch 15 \
  ...

You have so many samples! I saw 5h for this run, wow!

It could help... I just realized that I can only see the first 100bp of your reads due to zoom from Qiime2 view. If there's another quality drop after 100 bp that could explain these issues.

You can upload the .qzv quality plots or reopen them and see if you can zoom out to see the full x-axis.

Thank you for sticking with it! We have a lot of old posts that link to old docs, so a new post lets me share all the new links with folks. This is super helpful for future users, so thank you.

Ah, I see what you mean with the x axis being cut off, sorry about that! The QZVs are linked in the original posts, but here are the screenshots as well.

16S:

COI:

Unless I am interpreting it incorrectly, I don't believe there is a drop in quality towards the end of reads. The reverse reads look good quality wise, too. Now that the correct screenshots are attached, let me know if you still think I should truncate to 100bp? I don't really know what else to try otherwise :thinking:

In case it's helpful, I looked up the Novaseq binned quality scores and attached a screenshot of the table that matches the scores within my data. Reads with a score of 9 could have scores between 3-17, which is a huge range, though as you point out that could be taken care of by expected error filtering...

Also,

I do! It's exciting but also intimidating; for COI I have 423 samples from 323 individuals, and for 16S I have 390 samples from 309 individuals. Also, I was reading this documentation and remembered the primary reason why I didn't use q2-cutadapt: my data is dual-indexed following Adapterama I, which isn't supported by q2-cutadapt or q2-demux. Do you know of any other way we can look at quality scores before trimming?

Thanks again for your time and responses!

Sincerely,

Clare

Sure! Try qiime vsearch fastq-stats on raw data imported into qiime
Or vseach --fastq-stats example.fastq.gz NAME | vsearch on raw data.

This gives you per-sample quality score data, which you then have to average and plot yourself.
Or better yet, keep separate plots for separate samples to see there's a batch effect for joining. (Like, all the 2022 samples fail to merge or something!)

Hi Colin,

I tried importing my raw data into qiime, then running qiime vsearch fastq-stats on it, but the output is a little confusing to me. Just so I understand the goal of running fastq-stats, we're trying to visualize the per-sample quality to see if there is anything we're missing that could be tweaked to produce better read-pair merging when we run the denoising?

diet-raw.qzv (236.4 KB)

Another thought I had is that there might be leftover primers left in the reads, even though I ran cutadapt before importing to QIIME... Is there any way to check a given QIIME artifact for specific sequences (similar to zcat on a fastq.gz file)? I noticed that in the COI representative sequences file

COI-representative-sequences.qzv (4.3 MB)

, the mean length is 182bp and the maximum length is 229bp, even though the target region length for COI ANML is 157bp. Since I am running a diet study with fecal samples, I expect my data to be a mix of bird (host), bacterial and prey (arthropod) DNA, but even so, would there be huge difference in length variation of real sequences, or is it more likely a sign that primers are still attached?

Thanks for reading!

Clare

Qiime2 view: diet-raw.qzv open online.

Just so I understand the goal of running fastq-stats, we're trying to visualize the per-sample quality to see if there is anything we're missing that could be tweaked to produce better read-pair merging when we run the denoising?

That right. These look really good! I would expect quality filtering to go well based on what I see here, and it goes. I'm not sure I see any clues for overlapping the reads...


Qiime2 view: COI-representative-sequences.qzv open online.

Yes, you can "Download your sequences as a raw FASTA file" and grep on that.

That page also lists every sequence so you can control+f to 'find' any string of text you want!


That does sound like a lot of extra sequences! Let us know what you find. Remember we can use data2 or cutadapt to remove unwanted sequences, so we have options!

Hi Qiime forum,

As an update, I did find leftover primer sequences despite having run Cutadapt before import to QIIME. I found 1) forward and reverse primers on my sequences (i.e. some of my sequences had more than one forward/ reverse primer), and 2) reverse complements of the forward and reverse primers on my reads. To address this, I ran two additional rounds of Cutadapt, the first to (again) trim forward and reverse primers that occur at the ends of reads, with the assumption that these would be real data, and the second to discard reads with the reverse complements. However, removing them made the read merging perform even more poorly, only an average 9% of reads were merged successfully for COI, versus the previous 15%. Including my output files in case that's helpful.

COI-denoising-stats.qzv (345.5 KB)

COI-table.qzv (841.5 KB)

COI-representative-sequences.qzv (1.7 MB)

I would appreciate more of a theoretical answer to what might be causing this... I am still trying to understand why paired end merging specifically is causing poor merging within my data, even though the quality looks ok. My input data (fecal samples) are very degraded and I did choose to sequence some samples with fairly faint gel bands, but I don't really understand how that would translate to poor paired end merging, versus just having low quality or number of reads. Could it be that my paired ends are very different from each other (due to sequencing errors?) and are therefore not being matched together and merged correctly? What other aspects within the data could cause poor merging? Let me know your thoughts! Thanks!

Hi Clare,

I checked your COI-denoising-stats.qzv and found this

  • min_overlap:20
  • max_merge_mismatch:0

Could it be that my paired ends are very different from each other (due to sequencing errors?) and are therefore not being matched together and merged correctly?

Yes! And it looks like that happened here...

(We talked about this before, was this from an old script perhaps?)

If the PCR product is longer then the overlap, this would also cause no reads to join.

I should note that merging reads is not required! You can process just your forward or just your reverse read fully through cutadapt > dada2 > alpha and beta diversity if joining does not work out for these samples.