Python Introduction for Bioinformatics
When to Use
- Onboarding someone new to Python who wants a biology-flavored first program (nucleotide counting, GC content).
- Choosing which scientific/bio Python packages to install for a given task (BioPython, pandas, pysam, scanpy, scikit-bio).
- Setting up a reproducible environment with
venv or conda before starting any bioinformatics project.
- Explaining core language pitfalls (f-strings, mutable defaults, 0- vs 1-based coordinates) that trip up biologists writing their first scripts.
- Quick BioPython
Seq demo (complement, reverse complement, transcription, translation).
Version Compatibility
- Python ≥ 3.10 (f-strings,
str.maketrans, walrus operator all stable)
- biopython ≥ 1.83 (
Bio.SeqUtils.gc_fraction; older code used the removed GC() function)
- pandas ≥ 2.1, numpy ≥ 1.26 (only needed once you move past raw strings to tabular data)
Prerequisites
- No prior programming experience required for this skill itself.
pip install biopython (or conda install -c bioconda biopython) for the Bio.Seq demo.
- A terminal for
venv/conda environment setup.
Goal: Count nucleotides and compute GC content from a raw DNA string
Approach: Use str.count() for a one-off tally, or a loop over a dict when you need per-base percentages in one pass. GC content (fraction of G+C) is one of the first statistics computed on any new sequence — it correlates with melting temperature and gene density.
def nucleotide_counts(dna: str) -> dict:
"""Return counts of A/C/G/T in a DNA string using str.count()."""
dna = dna.upper()
return {base: dna.count(base) for base in "ACGT"}
def nucleotide_percentages(dna: str) -> dict:
"""Return per-base percentages via a single pass through the sequence."""
counts = {"A": 0, "C": 0, "G": 0, "T": 0}
for nt in dna.upper():
if nt in counts:
counts[nt] += 1
total = len(dna)
return {base: count / total * 100 for base, count in counts.items()}
def gc_content(sequence: str) -> float:
"""Calculate GC content of a DNA sequence as a percentage (0-100)."""
sequence = sequence.upper()
gc = sequence.count("G") + sequence.count("C")
return gc / len(sequence) * 100
if __name__ == "__main__":
# From Rosalind "Counting DNA Nucleotides"
dna = "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"
counts = nucleotide_counts(dna)
print(f"Counts: {counts} (total={sum(counts.values())}, len={len(dna)})")
gc = gc_content(dna)
print(f"GC content: {gc:.2f}%")
if gc < 40:
print("AT-rich (low GC).")
elif gc > 60:
print("GC-rich.")
else:
print("Moderate GC range.")
Goal: Basic sequence manipulation with BioPython's Seq
Approach: Bio.Seq.Seq wraps a string with biology-aware methods (complement, reverse_complement, transcribe, translate) so you don't hand-roll base-pairing tables for routine tasks.
def biopython_demo(sequence: str = "ATGAAACCCGGGTAA") -> None:
"""Show core Bio.Seq operations: complement, RC, transcription, translation, GC."""
from Bio.Seq import Seq
from Bio.SeqUtils import gc_fraction
seq = Seq(sequence)
print(f"Sequence: {seq}")
print(f"Complement: {seq.complement()}")
print(f"Reverse complement: {seq.reverse_complement()}")
print(f"Transcribed (RNA): {seq.transcribe()}")
print(f"Translated: {seq.translate()}")
print(f"GC fraction: {gc_fraction(seq):.3f}")
if __name__ == "__main__":
biopython_demo()
Goal: Set up an isolated environment for a bioinformatics project
Approach: Use venv for a pure-Python project; use conda when you also need compiled, non-Python tools (BLAST, samtools) in the same environment.
# --- pip / venv ---
python -m venv bioenv
source bioenv/bin/activate # macOS/Linux; use bioenv\Scripts\activate on Windows
pip install biopython pandas numpy matplotlib seaborn
pip install -r requirements.txt # if you have one
pip list
deactivate
# --- conda (preferred when you also need CLI tools like blast/samtools) ---
conda create -n bioenv python=3.11
conda activate bioenv
conda install -c conda-forge biopython pandas matplotlib
conda install -c bioconda blast samtools
Pitfalls
- f-strings vs
% formatting: f-strings (f"GC = {gc:.2f}%") are the modern approach (Python ≥3.6); older code uses "GC = %.2f%%" % gc.
print() returns None: never write result = print(...) expecting to capture output — assign the value directly instead.
- Mutable default arguments: never
def f(x=[]); use def f(x=None): x = x if x is not None else [].
- 0-based vs 1-based coordinates: Python slicing/ranges are half-open
[start, stop) and 0-based, but genomic coordinate systems (GFF, VCF, 1-based) are not — off-by-one errors are the most common bug when converting between them.
- Deep vs shallow copy: nested structures (e.g. a list of per-sample count dicts) need
copy.deepcopy(); list.copy() only copies the top level.
Bio.SeqUtils.GC() is gone: newer BioPython uses gc_fraction() (returns 0-1, not 0-100) — multiply by 100 if you want a percentage.
See Also
biopython — deeper Bio.Seq/Bio.SeqIO/Bio.SeqUtils reference
bio-sequence-io-read-sequences — reading FASTA/FASTQ files instead of raw strings
bio-sequence-manipulation-seq-objects — Seq object operations in depth
bio-sequence-manipulation-transcription-translation — transcription/translation details
1---2name: python-bio-python-introduction3description: Foundational Python for biology - count nucleotides, compute GC content, use f-strings/loops/functions, and set up biopython/pandas/numpy via pip/venv/conda. Use when a beginner asks how to start with Python for bioinformatics, write a first DNA-parsing script, calculate GC content from a raw string, or install BioPython/scanpy/pysam in a virtualenv or conda environment.4---56# Python Introduction for Bioinformatics78## When to Use910- Onboarding someone new to Python who wants a biology-flavored first program (nucleotide counting, GC content).11- Choosing which scientific/bio Python packages to install for a given task (BioPython, pandas, pysam, scanpy, scikit-bio).12- Setting up a reproducible environment with `venv` or `conda` before starting any bioinformatics project.13- Explaining core language pitfalls (f-strings, mutable defaults, 0- vs 1-based coordinates) that trip up biologists writing their first scripts.14- Quick BioPython `Seq` demo (complement, reverse complement, transcription, translation).1516## Version Compatibility1718- Python ≥ 3.10 (f-strings, `str.maketrans`, walrus operator all stable)19- biopython ≥ 1.83 (`Bio.SeqUtils.gc_fraction`; older code used the removed `GC()` function)20- pandas ≥ 2.1, numpy ≥ 1.26 (only needed once you move past raw strings to tabular data)2122## Prerequisites2324- No prior programming experience required for this skill itself.25- `pip install biopython` (or `conda install -c bioconda biopython`) for the `Bio.Seq` demo.26- A terminal for `venv`/`conda` environment setup.2728## Goal: Count nucleotides and compute GC content from a raw DNA string2930**Approach:** Use `str.count()` for a one-off tally, or a loop over a `dict` when you need per-base percentages in one pass. GC content (fraction of G+C) is one of the first statistics computed on any new sequence — it correlates with melting temperature and gene density.3132```python33def nucleotide_counts(dna: str) -> dict:34 """Return counts of A/C/G/T in a DNA string using str.count()."""35 dna = dna.upper()36 return {base: dna.count(base) for base in "ACGT"}373839def nucleotide_percentages(dna: str) -> dict:40 """Return per-base percentages via a single pass through the sequence."""41 counts = {"A": 0, "C": 0, "G": 0, "T": 0}42 for nt in dna.upper():43 if nt in counts:44 counts[nt] += 145 total = len(dna)46 return {base: count / total * 100 for base, count in counts.items()}474849def gc_content(sequence: str) -> float:50 """Calculate GC content of a DNA sequence as a percentage (0-100)."""51 sequence = sequence.upper()52 gc = sequence.count("G") + sequence.count("C")53 return gc / len(sequence) * 100545556if __name__ == "__main__":57 # From Rosalind "Counting DNA Nucleotides"58 dna = "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"5960 counts = nucleotide_counts(dna)61 print(f"Counts: {counts} (total={sum(counts.values())}, len={len(dna)})")6263 gc = gc_content(dna)64 print(f"GC content: {gc:.2f}%")65 if gc < 40:66 print("AT-rich (low GC).")67 elif gc > 60:68 print("GC-rich.")69 else:70 print("Moderate GC range.")71```7273## Goal: Basic sequence manipulation with BioPython's `Seq`7475**Approach:** `Bio.Seq.Seq` wraps a string with biology-aware methods (`complement`, `reverse_complement`, `transcribe`, `translate`) so you don't hand-roll base-pairing tables for routine tasks.7677```python78def biopython_demo(sequence: str = "ATGAAACCCGGGTAA") -> None:79 """Show core Bio.Seq operations: complement, RC, transcription, translation, GC."""80 from Bio.Seq import Seq81 from Bio.SeqUtils import gc_fraction8283 seq = Seq(sequence)84 print(f"Sequence: {seq}")85 print(f"Complement: {seq.complement()}")86 print(f"Reverse complement: {seq.reverse_complement()}")87 print(f"Transcribed (RNA): {seq.transcribe()}")88 print(f"Translated: {seq.translate()}")89 print(f"GC fraction: {gc_fraction(seq):.3f}")909192if __name__ == "__main__":93 biopython_demo()94```9596## Goal: Set up an isolated environment for a bioinformatics project9798**Approach:** Use `venv` for a pure-Python project; use `conda` when you also need compiled, non-Python tools (BLAST, samtools) in the same environment.99100```bash101# --- pip / venv ---102python -m venv bioenv103source bioenv/bin/activate # macOS/Linux; use bioenv\Scripts\activate on Windows104pip install biopython pandas numpy matplotlib seaborn105pip install -r requirements.txt # if you have one106pip list107deactivate108109# --- conda (preferred when you also need CLI tools like blast/samtools) ---110conda create -n bioenv python=3.11111conda activate bioenv112conda install -c conda-forge biopython pandas matplotlib113conda install -c bioconda blast samtools114```115116## Pitfalls117118- **f-strings vs `%` formatting:** f-strings (`f"GC = {gc:.2f}%"`) are the modern approach (Python ≥3.6); older code uses `"GC = %.2f%%" % gc`.119- **`print()` returns `None`:** never write `result = print(...)` expecting to capture output — assign the value directly instead.120- **Mutable default arguments:** never `def f(x=[])`; use `def f(x=None): x = x if x is not None else []`.121- **0-based vs 1-based coordinates:** Python slicing/ranges are half-open `[start, stop)` and 0-based, but genomic coordinate systems (GFF, VCF, 1-based) are not — off-by-one errors are the most common bug when converting between them.122- **Deep vs shallow copy:** nested structures (e.g. a list of per-sample count dicts) need `copy.deepcopy()`; `list.copy()` only copies the top level.123- **`Bio.SeqUtils.GC()` is gone:** newer BioPython uses `gc_fraction()` (returns 0-1, not 0-100) — multiply by 100 if you want a percentage.124125## See Also126127- `biopython` — deeper Bio.Seq/Bio.SeqIO/Bio.SeqUtils reference128- `bio-sequence-io-read-sequences` — reading FASTA/FASTQ files instead of raw strings129- `bio-sequence-manipulation-seq-objects` — Seq object operations in depth130- `bio-sequence-manipulation-transcription-translation` — transcription/translation details