Skip to content
Data
Skill

/bio-fastq-quality

Work with FASTQ quality scores using Biopython. Use when analyzing read quality, filtering by quality, trimming low-quality bases, or generating quality reports.

From plugin
openclaw-medical-skills
2.9k200 skills
Install
$ npx -y skills add FreedomIntelligence/OpenClaw-Medical-Skills --skill bio-fastq-quality --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/bio-fastq-quality

Context preview

The summary Claude sees to decide when to auto-load this skill.

Work with FASTQ quality scores using Biopython. Use when analyzing read quality, filtering by quality, trimming low-quality bases, or generating quality reports.

SKILL.md

bio-fastq-quality.SKILL.md
name: bio-fastq-quality
description: Work with FASTQ quality scores using Biopython. Use when analyzing read quality, filtering by quality, trimming low-quality bases, or generating quality reports.
tool_type: python
primary_tool: Bio.SeqIO

Version Compatibility

Reference examples tested with: BioPython 1.83+

Before using code patterns, verify installed versions match. If versions differ:

  • Python: `pip show <package>` then `help(module.function)` to check signatures

If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.

FASTQ Quality Scores

**"Filter my FASTQ reads by quality score"** → Access, analyze, and filter Phred quality scores, trim low-quality bases, and generate per-position quality profiles.

  • Python: `SeqIO.parse()` with `letter_annotations['phred_quality']` (BioPython)

Analyze and manipulate FASTQ quality scores using Biopython.

Required Imports

from Bio import SeqIO
from Bio.Seq import Seq

Accessing Quality Scores

Quality scores are stored in `letter_annotations['phred_quality']` as a list of integers.

for record in SeqIO.parse('reads.fastq', 'fastq'):
    qualities = record.letter_annotations['phred_quality']
    print(record.id, qualities[:10])  # First 10 quality scores

Quality Score Basics

| Phred Score | Error Probability | Accuracy | |-------------|-------------------|----------| | 10 | 1 in 10 | 90% | | 20 | 1 in 100 | 99% | | 30 | 1 in 1000 | 99.9% | | 40 | 1 in 10000 | 99.99% |

Code Patterns

Calculate Average Quality per Read

for record in SeqIO.parse('reads.fastq', 'fastq'):
    quals = record.letter_annotations['phred_quality']
    avg_qual = sum(quals) / len(quals)
    print(f'{record.id}: {avg_qual:.1f}')

Filter Reads by Mean Quality

def high_quality_reads(records, min_avg_qual=20):
    for record in records:
        quals = record.letter_annotations['phred_quality']
        if sum(quals) / len(quals) >= min_avg_qual:
            yield record

records = SeqIO.parse('reads.fastq', 'fastq')
good_reads = high_quality_reads(records, min_avg_qual=25)
SeqIO.write(good_reads, 'filtered.fastq', 'fastq')

Filter by Minimum Quality at Any Position

def all_bases_above(records, min_qual=20):
    for record in records:
        if min(record.letter_annotations['phred_quality']) >= min_qual:
            yield record

Trim Low-Quality Ends (3' Trimming)

def trim_low_quality(record, min_qual=20):
    quals = record.letter_annotations['phred_quality']
    trim_pos = len(quals)
    for i in range(len(quals) - 1, -1, -1):
        if quals[i] >= min_qual:
            trim_pos = i + 1
            break
    return record[:trim_pos]

records = SeqIO.parse('reads.fastq', 'fastq')
trimmed = (trim_low_quality(rec) for rec in records)
SeqIO.write(trimmed, 'trimmed.fastq', 'fastq')

Sliding Window Quality Trim

**Goal:** Trim a read at the first position where average quality in a sliding window drops below threshold.

**Approach:** Slide a fixed-size window across quality scores; when the window average falls below the cutoff, truncate the record at that position.

**Reference (BioPython 1.83+):**

def sliding_window_trim(record, window_size=5, min_avg_qual=20):
    quals = record.letter_annotations['phred_quality']
    for i in range(len(quals) - window_size + 1):
        window = quals[i:i + window_size]
        if sum(window) / window_size < min_avg_qual:
            return record[:i] if i > 0 else None
    return record

Quality Statistics Summary

import statistics

all_quals = []
for record in SeqIO.parse('reads.fastq', 'fastq'):
    all_quals.extend(record.letter_annotations['phred_quality'])

print(f'Mean quality: {statistics.mean(all_quals):.1f}')
print(f'Median quality: {statistics.median(all_quals):.1f}')
print(f'Min quality: {min(all_quals)}')
print(f'Max quality: {max(all_quals)}')

Per-Position Quality Profile

**Goal:** Compute mean quality at each read position to identify systematic quality drops (e.g., read-end degradation).

**Approach:** Accumulate quality scores by position across all reads, then compute per-position means.

**Reference (BioPython 1.83+):**

from collections import defaultdict

position_quals = defaultdict(list)
for record in SeqIO.parse('reads.fastq', 'fastq'):
    for i, q in enumerate(record.letter_annotations['phred_quality']):
        position_quals[i].append(q)

for pos in sorted(position_quals.keys())[:20]:
    quals = position_quals[pos]
    print(f'Position {pos}: mean={sum(quals)/len(quals):.1f}')

Count Reads by Quality Threshold

thresholds = [20, 25, 30, 35]
counts = {t: 0 for t in thresholds}

for record in SeqIO.parse('reads.fastq', 'fastq'):
    avg = sum(record.letter_annotations['phred_quality']) / len(record.seq)
    for t in thresholds:
        if avg >= t:
            counts[t] += 1

for t, c in counts.items():
    print(f'Q>={t}: {c} reads')

Remove N Bases and Low Quality Together

def clean_read(record, min_qual=20):
    seq = str(record.seq)
    quals = record.letter_annotations['phred_quality']
    keep = [(s, q) for s, q in zip(seq, quals) if s != 'N' and q >= min_qual]
    if not keep:
        return None
    new_seq, new_quals = zip(*keep)
    new_record = record[:0]  # Empty copy with same metadata
    new_record.seq = Seq(''.join(new_seq))
    new_record.letter_annotations['phred_quality'] = list(new_quals)
    return new_record

FASTQ Format Variants

| Variant | Format String | Quality Encoding | ASCII Range | |---------|---------------|------------------|-------------| | Sanger/Illumina 1.8+ | `'fastq'` | Phred+33 (standard) | 33-126 | | Solexa | `'fastq-solexa'` | Solexa+64 | 59-126 | | Illumina 1.3-1.7 | `'fastq-illumina'` | Phred+64 | 64-126 |

Most modern data uses standard `'fastq'` (

Read more
Ships withopenclaw-medical-skills

The largest open-source medical AI skill library for OpenClaw.

Get the whole plugin
Stats
2,921
Stars
410
Forks
Active
Maintenance
Python
Language
20d ago
Last commit
5mo ago
Created

Repo: FreedomIntelligence/OpenClaw-Medical-Skills