Biopython Basics: Parse, Manipulate, Write

Biopython is the Swiss-army knife for biological data in Python. Learn the few objects and methods that handle 90% of everyday sequence work.

๐ŸŸขโ†’๐ŸŸก Beginner โฑ๏ธ ~1 hr ๐Ÿ Python ยท Biopython ๐ŸŒ Runs free in Colab

Before you start

You've met FASTA/FASTQ in lesson 1 and can run Python. In Colab, start each notebook with !pip install biopython.

Learning objectives

By the end of this lesson you will be able to: create a Biopython Seq object and use its biology-aware methods, read sequence files with SeqIO.parse, filter records to keep only the ones you want, and write your results back out to a file.

The one import to remember

Biopython gives you two workhorses: the Seq object (a sequence with biology-aware methods) and SeqIO (read/write sequence files). Almost everything starts with these.

from Bio.Seq import Seq
from Bio import SeqIO

The Seq object: a sequence that knows biology

A plain Python string can't transcribe or translate itself. A Biopython Seq can.

dna = Seq("ATGGCCCTGTGGATGCGCTAA")

print(len(dna))                 # length
print(dna.complement())        # pair each base (Aโ†”T, Gโ†”C)
print(dna.reverse_complement()) # the other strand, read 5'โ†’3'
print(dna.transcribe())        # DNA โ†’ RNA (T becomes U)
print(dna.translate())          # RNA/DNA โ†’ protein (amino acids)

Decode the jargon: reverse complement

DNA is double-stranded. If one strand reads ATGC, the partner strand reads GCAT (complement each base, then reverse the order). You need the reverse complement constantly - for example, when a gene sits on the opposite strand. Biopython does it in one call.

SeqIO: reading files (the pattern that scales)

Two methods cover almost everything. SeqIO.read() for a file with one record; SeqIO.parse() for a file with many.

# make a multi-record FASTA to work with
with open("genes.fasta", "w") as f:
    f.write(">insulin\nATGGCCCTGTGGATGCGCCTC\n")
    f.write(">globin\nATGGTGCATCTGACTCCTGAG\n")
    f.write(">short\nATGAAA\n")

for rec in SeqIO.parse("genes.fasta", "fasta"):
    print(rec.id, len(rec.seq), "bp")

Each rec is a SeqRecord - a sequence plus its metadata: rec.id (the name), rec.description, and rec.seq (the Seq itself).

Manipulate: filter records

A real task: keep only the records longer than some cutoff. Just loop and test.

keep = [rec for rec in SeqIO.parse("genes.fasta", "fasta")
        if len(rec.seq) >= 15]

print("Kept", len(keep), "of 3 records")

Write: save your results

Whatever records you've kept or changed, SeqIO.write() saves them back to a file in any format.

SeqIO.write(keep, "filtered.fasta", "fasta")
print("Saved filtered.fasta")

That's the full cycle - read โ†’ manipulate โ†’ write - and it's the backbone of countless real scripts. You now have the tools to process a sequence file of any size.

๐Ÿš€ Make it your own

  • Print the reverse complement of each record in genes.fasta.
  • Translate each sequence to protein and print the result (remember a clean coding sequence is a multiple of 3).
  • Write only the records whose ID contains "globin" to a new file.
  • Convert genes.fasta to a different format in one line: SeqIO.convert("genes.fasta","fasta","genes.tab","tab").

Check your understanding

When do you use SeqIO.read() vs SeqIO.parse()?
read() for a file with exactly one record (it returns that single record); parse() for a file with one or many (it returns an iterator you loop over).
What does a SeqRecord contain that a plain Seq doesn't?
Metadata - the .id, .description, and other annotations - wrapped around the .seq. A Seq is just the letters; a SeqRecord is the letters plus their label.
Why use a Seq object instead of a regular string?
Because it carries biology-aware methods: complement, reverse_complement, transcribe, translate. A plain string can't do those.
Which Biopython method saves your records back out to a file?
SeqIO.write() writes records to a file in whatever format you name, completing the read, manipulate, write cycle.
What does a Seq object's reverse_complement() return?
reverse_complement() gives the opposite strand: it complements each base (A with T, G with C) and reverses the order. You need it constantly when a gene sits on the other strand.
Next in Track 1

Where the data lives: NCBI, Ensembl, GEO, SRA โ†’