Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Filter and select sequences by criteria (length, ID, GC content, patterns) using Biopython. Use when subsetting sequences, removing unwanted records, or selecting by specific criteria.
.claude/skills/bio-filter-sequences/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-22 | ✗→✓ | ▲ Improved | — | — |
| case-15 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✓→✓ | = Same ✓ | — | — |
| case-02 | ✓→✓ | = Same ✓ | — | — |
| case-12 | ✗→✗ | = Same ✗ | — | — |
Reference examples tested with: BioPython 1.83+, samtools 1.19+
Before using code patterns, verify installed versions match. If versions differ:
pip show <package> then help(module.function) to check signaturesIf code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.
"Filter sequences by length, quality, or content" → Apply boolean criteria to a stream of sequence records and write survivors to output.
SeqIO.parse() + SeqIO.write() (BioPython)seqkit seq -m 200 (SeqKit) or awk on FASTAFilter and select sequences based on various criteria using Biopython.
pythonfrom Bio import SeqIO from Bio.SeqUtils import gc_fraction
Use generator expressions for memory-efficient filtering:
pythonrecords = SeqIO.parse('input.fasta', 'fasta') filtered = (rec for rec in records if len(rec.seq) >= 100) SeqIO.write(filtered, 'output.fasta', 'fasta')
pythonrecords = SeqIO.parse('input.fasta', 'fasta') long_seqs = (rec for rec in records if len(rec.seq) >= 500) SeqIO.write(long_seqs, 'long.fasta', 'fasta')
pythonrecords = SeqIO.parse('input.fasta', 'fasta') sized = (rec for rec in records if 100 <= len(rec.seq) <= 1000) SeqIO.write(sized, 'sized.fasta', 'fasta')
pythonmin_length = 200 records = SeqIO.parse('input.fasta', 'fasta') filtered = (rec for rec in records if len(rec.seq) >= min_length) count = SeqIO.write(filtered, 'filtered.fasta', 'fasta')
pythonwanted_ids = {'seq1', 'seq2', 'seq3'} records = SeqIO.parse('input.fasta', 'fasta') selected = (rec for rec in records if rec.id in wanted_ids) SeqIO.write(selected, 'selected.fasta', 'fasta')
Goal: Extract sequences whose IDs appear in an external list file.
Approach: Load IDs into a set for O(1) lookup, then stream-filter and write matches.
Reference (BioPython 1.83+):
pythonwith open('ids.txt') as f: wanted_ids = {line.strip() for line in f} records = SeqIO.parse('input.fasta', 'fasta') selected = (rec for rec in records if rec.id in wanted_ids) SeqIO.write(selected, 'selected.fasta', 'fasta')
pythonexclude_ids = {'bad_seq1', 'bad_seq2'} records = SeqIO.parse('input.fasta', 'fasta') kept = (rec for rec in records if rec.id not in exclude_ids) SeqIO.write(kept, 'kept.fasta', 'fasta')
pythonimport re pattern = re.compile(r'^chr\d+$') # Match chr1, chr2, etc. records = SeqIO.parse('input.fasta', 'fasta') chromosomes = (rec for rec in records if pattern.match(rec.id)) SeqIO.write(chromosomes, 'chromosomes.fasta', 'fasta')
pythonfrom Bio.SeqUtils import gc_fraction records = SeqIO.parse('input.fasta', 'fasta') moderate_gc = (rec for rec in records if 0.4 <= gc_fraction(rec.seq) <= 0.6) SeqIO.write(moderate_gc, 'moderate_gc.fasta', 'fasta')
pythonhigh_gc = (rec for rec in records if gc_fraction(rec.seq) >= 0.6)
pythonlow_gc = (rec for rec in records if gc_fraction(rec.seq) <= 0.4)
pythonrecords = SeqIO.parse('input.fasta', 'fasta') clean = (rec for rec in records if 'N' not in str(rec.seq).upper()) SeqIO.write(clean, 'clean.fasta', 'fasta')
pythondef n_fraction(seq): return str(seq).upper().count('N') / len(seq) records = SeqIO.parse('input.fasta', 'fasta') low_n = (rec for rec in records if n_fraction(rec.seq) < 0.05)
pythonmotif = 'GAATTC' # EcoRI site records = SeqIO.parse('input.fasta', 'fasta') with_motif = (rec for rec in records if motif in str(rec.seq).upper()) SeqIO.write(with_motif, 'with_ecori.fasta', 'fasta')
pythonimport re pattern = re.compile(r'ATG.{30,100}T(AA|AG|GA)') # ORF-like pattern records = SeqIO.parse('input.fasta', 'fasta') matches = (rec for rec in records if pattern.search(str(rec.seq)))
pythonrecords = SeqIO.parse('input.fasta', 'fasta') kinases = (rec for rec in records if 'kinase' in rec.description.lower()) SeqIO.write(kinases, 'kinases.fasta', 'fasta')
pythonkeywords = ['kinase', 'phosphatase', 'transferase'] records = SeqIO.parse('input.fasta', 'fasta') enzymes = (rec for rec in records if any(k in rec.description.lower() for k in keywords))
Goal: Remove sequences that fail any of several quality/content thresholds.
Approach: Define a predicate function that checks all criteria, apply it as a generator filter, and write survivors.
Reference (BioPython 1.83+):
pythonfrom Bio.SeqUtils import gc_fraction def passes_filters(record): if len(record.seq) < 100: return False if gc_fraction(record.seq) < 0.3 or gc_fraction(record.seq) > 0.7: return False if 'N' in str(record.seq).upper(): return False return True records = SeqIO.parse('input.fasta', 'fasta') filtered = (rec for rec in records if passes_filters(rec)) SeqIO.write(filtered, 'filtered.fasta', 'fasta')
pythonimport random records = list(SeqIO.parse('input.fasta', 'fasta')) sample = random.sample(records, min(100, len(records))) SeqIO.write(sample, 'sample.fasta', 'fasta')
pythonfrom itertools import islice records = SeqIO.parse('input.fasta', 'fasta') first_100 = islice(records, 100) SeqIO.write(first_100, 'first100.fasta', 'fasta')
pythonrecords = SeqIO.parse('input.fasta', 'fasta') every_10th = (rec for i, rec in enumerate(records) if i % 10 == 0) SeqIO.write(every_10th, 'sampled.fasta', 'fasta')
Goal: Partition sequences into separate files based on a length threshold.
Approach: Load all records, apply list comprehension split, and write each partition.
Reference (BioPython 1.83+):
pythonrecords = list(SeqIO.parse('input.fasta', 'fasta')) short = [r for r in records if len(r.seq) < 500] long = [r for r in records if len(r.seq) >= 500] SeqIO.write(short, 'short.fasta', 'fasta') SeqIO.write(long, 'long.fasta', 'fasta')
| Error | Cause | Solution | |-------|-------|----------| | Generator exhausted | Used generator twice | Re-create generator or use list() | | Empty output | Filter too strict | Check filter conditions | | Memory error | List too large | Use generator expressions |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.