First Script
Build a BioLang script that reads FASTQ records, computes quality statistics, filters reads, and writes a tab-separated report.
Inputs
BioLang scripts are .bl files evaluated from top to bottom. The current
bl run command accepts a script path, so configure input values in the
script or read them from environment variables with env().
# qc_report.bl
let input_path = env("FASTQ_INPUT") ?? "sample_R1.fastq"
let min_quality = 25.0
let output_path = "qc_report.tsv"
println(f"Processing: {input_path}")
println(f"Quality threshold: {min_quality}")
Read FASTQ Records
let records = read_fastq(input_path)
let total = len(records)
println(f"Total reads: {total}")
Compute Per-Read Metrics
let qualities = records |> map(|record| {
{
name: record.id,
length: record.length,
mean_quality: mean_phred(record.quality),
gc_content: gc_content(record.seq)
}
})
let mean_qual = qualities |> map(|r| r.mean_quality) |> mean()
let mean_len = qualities |> map(|r| r.length) |> mean()
let mean_gc = qualities |> map(|r| r.gc_content) |> mean()
println(f"Mean quality: {round(mean_qual, 2)}")
println(f"Mean length: {round(mean_len, 1)}")
println(f"Mean GC: {round(mean_gc, 3)}")
Filter and Classify
fn quality_tier(mean_q) {
if mean_q >= 35.0 {
"excellent"
} else if mean_q >= 25.0 {
"good"
} else if mean_q >= 20.0 {
"acceptable"
} else {
"poor"
}
}
let passing = qualities
|> filter(|r| r.mean_quality >= min_quality)
|> filter(|r| r.length >= 50)
let pass_rate = float(len(passing)) / float(total) * 100.0
println(f"Passing reads: {len(passing)} ({round(pass_rate, 1)}%)")
let tier_counts = passing
|> map(|r| quality_tier(r.mean_quality))
|> frequencies()
for tier in keys(tier_counts) {
println(f" {tier}: {tier_counts[tier]}")
}
Write the Report
let header = "read_name\tlength\tmean_quality\tgc_content\ttier"
let lines = passing |> map(|r| {
let tier = quality_tier(r.mean_quality)
f"{r.name}\t{r.length}\t{round(r.mean_quality, 2)}\t{round(r.gc_content, 4)}\t{tier}"
})
write_text(output_path, join(concat([header], lines), "\n"))
println(f"Report written to {output_path}")
Complete Script
# qc_report.bl
let input_path = env("FASTQ_INPUT") ?? "sample_R1.fastq"
let min_quality = 25.0
let output_path = "qc_report.tsv"
fn quality_tier(mean_q) {
if mean_q >= 35.0 { "excellent" }
else if mean_q >= 25.0 { "good" }
else if mean_q >= 20.0 { "acceptable" }
else { "poor" }
}
let records = read_fastq(input_path)
let qualities = records |> map(|record| {
{
name: record.id,
length: record.length,
mean_quality: mean_phred(record.quality),
gc_content: gc_content(record.seq)
}
})
let passing = qualities
|> filter(|r| r.mean_quality >= min_quality)
|> filter(|r| r.length >= 50)
let header = "read_name\tlength\tmean_quality\tgc_content\ttier"
let lines = passing |> map(|r| {
let tier = quality_tier(r.mean_quality)
f"{r.name}\t{r.length}\t{round(r.mean_quality, 2)}\t{round(r.gc_content, 4)}\t{tier}"
})
write_text(output_path, join(concat([header], lines), "\n"))
println(f"Done. {len(passing)}/{len(records)} reads passed. Report: {output_path}")
Run It
# PowerShell
$env:FASTQ_INPUT = "sample_R1.fastq"
bl run qc_report.bl
# Bash
FASTQ_INPUT=sample_R1.fastq bl run qc_report.bl