Konstas.Engineering Notes
Networking · Cybersecurity · Infrastructure
Data Science

Large-Scale Genomic Data Processing

Articles · 2026 · Ioannis (John) Konstas

Educational Bioinformatics Pipeline Reference · macOS · GRCh37 / GRCh38

Status: Completed 38,603,409 lines processed 23 Chromosomes Haplogroup H15a1 macOS Apple Silicon GIAB · NA12878

Executive Summary

This project demonstrates a complete personal genome bioinformatics pipeline executed on macOS. The work is centered on NA12878 — a real woman who donated her genome to science — whose sequencing data is freely available as a gold-standard reference from the Genome in a Bottle (GIAB) consortium.

38.6M
Lines in FASTA genome file
3 GB
Consensus genome size
23
Chromosomes mapped
4.2M+
Variant calls in NA12878 VCF
H15a1
Mitochondrial haplogroup
GRCh38
Reference assembly

Installation Guide — macOS

Everything below runs on macOS Apple Silicon (M1/M2/M3/M4) or Intel Mac. The only prerequisite is Homebrew — macOS's standard package manager.

Step 1 — Install Homebrew (if not already installed)

# Paste this into Terminal — it installs Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Verify installation
brew --version

Step 2 — Install Core Bioinformatics Tools

# samtools — reads, indexes, and queries genome FASTA and BAM files
brew install samtools

# bcftools — reads, queries, and filters VCF variant call files
brew install bcftools

# htslib — provides bgzip (block gzip) and tabix (indexed compression)
brew install htslib

# bwa — aligns short DNA reads to a reference genome
brew install bwa

# Java — required by snpEff (annotation engine)
brew install openjdk@17
echo 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

# Verify Java is working
java -version

Step 3 — Install snpEff (Variant Annotator)

snpEff is not on Homebrew — install it manually. It is a Java program distributed as a ZIP file.

# Create a working directory
mkdir -p ~/na12878_pipeline && cd ~/na12878_pipeline

# Download snpEff
curl -L https://snpeff.blob.core.windows.net/versions/snpEff_latest_core.zip -o snpEff.zip

# Unzip it
unzip snpEff.zip

# Download the GRCh38 annotation database (one-time, ~3 GB)
java -jar snpEff/snpEff.jar download GRCh38.109

# Verify snpEff works
java -jar snpEff/snpEff.jar -version

Step 4 — Install Miniconda (for snpEff conda environment — optional)

# Download Miniconda installer for Apple Silicon
curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh

# Run installer
bash Miniconda3-latest-MacOSX-arm64.sh

# Restart terminal, then create a dedicated snpEff environment
conda create -n snpeff_env -c bioconda snpeff -y
conda activate snpeff_env

Step 5 — Install Python Visualization Tools

# Install pip packages for plotting
pip3 install matplotlib pandas numpy biopython

# Verify
python3 -c "import matplotlib; print('matplotlib', matplotlib.__version__)"

Full Tool Reference

ToolInstall CommandWhat It Does
samtoolsbrew install samtoolsQuery, index, and manipulate genome FASTA and aligned BAM files
bcftoolsbrew install bcftoolsRead, filter, and query VCF variant call files
bgzipbrew install htslibBlock-gzip compress large genomic files for indexed random access
tabixbrew install htslibIndex compressed VCF/FASTA so you can jump to any position instantly
bwabrew install bwaAlign short sequencing reads to a reference genome
snpEffManual ZIP installAnnotate variants with gene consequences (missense, splice, silent…)
gzcatBuilt into macOSStream a .gz file without extracting it to disk
grepBuilt into macOSSearch for patterns inside a text stream
sedBuilt into macOSStream editor — filter or transform lines of text
awkBuilt into macOSColumn-aware text processor — perform calculations on genomic data fields

Downloading the Human Genome — The Single 3-Billion-Line File

The human genome reference (GRCh38) is a single compressed FASTA file. It contains the complete DNA sequence of a "consensus" human being — all 23 chromosome pairs, roughly 3.1 billion base pairs, written out as A/T/C/G characters and wrapped at 80 characters per line.

Why 80 characters per line? A historical computing standard inherited from IBM punch cards (80 columns) and early 80-column terminal screens. When bioinformatics software was first written in the 1980s–90s, this limit ensured files displayed correctly on any machine. The convention stuck and became the universal FASTA standard. Your 38.6 million line file = ~3 billion bases ÷ 80 characters per line.

Option A — Download GRCh38 from NCBI (Authoritative Source)

mkdir -p ~/na12878_pipeline && cd ~/na12878_pipeline

# Full primary assembly — all chromosomes — ~900 MB compressed (~3 GB unzipped)
curl -O https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/000/001/405/GCA_000001405.15_GRCh38/GCA_000001405.15_GRCh38_assembly_structure/Primary_Assembly/assembled_chromosomes/FASTA/chroms/GRCh38_major_release_seqs_for_alignment_pipelines.fa.gz

# OR — faster mirror from Ensembl
curl -O https://ftp.ensembl.org/pub/release-110/fasta/homo_sapiens/dna/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz

# OR — UCSC hg38 (same genome, different chromosome naming: chr1 vs 1)
rsync -avzP rsync://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.fa.gz .
NCBI vs Ensembl vs UCSC naming: These are all GRCh38 but chromosomes are named differently. NCBI/UCSC use chr1, chr2…. Ensembl uses 1, 2…. This matters — bcftools and tabix will fail if your VCF uses one naming convention and your reference uses another.

Option B — Download NA12878 Real Variant Calls (GIAB Gold Standard)

cd ~/na12878_pipeline

# High-confidence variant VCF for NA12878 against GRCh38
curl -O https://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/release/NA12878_HG001/NISTv3.3.2/GRCh38/HG001_GRCh38_GIAB_highconf_CG-IllFB-IllGATKHC-Ion-10X-SOLID_CHROM1-X_v.3.3.2_highconf_PGandRTGphasetransfer.vcf.gz

# Download the index file too (required for tabix random access)
curl -O https://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/release/NA12878_HG001/NISTv3.3.2/GRCh38/HG001_GRCh38_GIAB_highconf_CG-IllFB-IllGATKHC-Ion-10X-SOLID_CHROM1-X_v.3.3.2_highconf_PGandRTGphasetransfer.vcf.gz.tbi

# Rename to something shorter for convenience
mv HG001_GRCh38_GIAB_highconf_*.vcf.gz na12878.vcf.gz
mv HG001_GRCh38_GIAB_highconf_*.vcf.gz.tbi na12878.vcf.gz.tbi

Index the Reference Genome for Fast Querying

Before you can query specific coordinates, the genome file must be indexed. This creates a lookup table so tools can jump directly to any position without reading the entire file.

# Step 1 — Block-gzip compress the reference (if not already bgzip'd)
bgzip -c Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz > ref_grch38.fna.bgz

# Step 2 — Build the FASTA index (.fai file)
samtools faidx ref_grch38.fna.bgz

# This creates ref_grch38.fna.bgz.fai — a lookup table of chromosome positions

# Step 3 — Index the VCF for random access
tabix -p vcf na12878.vcf.gz

# Step 4 — Index VCF with bcftools (alternative, creates .csi index)
bcftools index na12878.vcf.gz
What indexing does: Without an index, querying chr17 position 43,000,000 means reading every single line from the start of the file until you reach that position. With an index, the tool opens the file directly at that byte offset — like a book's index vs reading from page 1.

File Sizes to Expect

FileCompressedUncompressedLines
GRCh38 reference FASTA~900 MB~3.2 GB~38–40 million
NA12878 VCF (GIAB)~450 MB~2.5 GB~4.2 million variants
NA12878 consensus FASTA~800 MB~3.1 GB~38 million
bwa index files (total)—~8–10 GB5 auxiliary files
snpEff GRCh38.109 database—~3 GBGene annotation DB
Total disk space needed: Plan for ~25–30 GB free before starting the full pipeline.

Complete Query Reference — Every Command Explained

This section covers every tool used to query the 3-billion-line genome file. Each command is broken down: what it does, why you use it, and what output to expect.

1. Stream a Compressed File Without Extracting It

gzcat reads a .gz file and outputs its contents as a text stream — no decompression to disk. This is the foundation of every genomic query on macOS.

# Stream the entire genome into your terminal (DO NOT run alone — will print forever)
gzcat ref_grch38.fna.bgz

# Always pipe gzcat into another command that controls the output
gzcat ref_grch38.fna.bgz | head -n 5        # first 5 lines only
gzcat ref_grch38.fna.bgz | wc -l             # count total lines (slow — reads all 38M)
gzcat ref_grch38.fna.bgz | grep "^>"         # show only chromosome headers

2. Peek at the File Without Opening It

# Show first 10 lines
gzcat ref_grch38.fna.bgz | head -n 10

# Show last 10 lines (reads entire file — slow on 3 GB)
gzcat ref_grch38.fna.bgz | tail -n 10

# Show first 20 lines of a specific chromosome (chr22)
gzcat ref_grch38.fna.bgz | sed -n '/^>chr22/,/^>/p' | head -n 20

# Count how many chromosomes are in the file
gzcat ref_grch38.fna.bgz | grep -c "^>"

3. samtools faidx — Query Exact Coordinates (Fastest Method)

samtools faidx uses the index to jump directly to any genomic coordinate in milliseconds — no reading from the start. This is how you query specific genes or regions.

# Pull a single base at a specific position
samtools faidx ref_grch38.fna.bgz chr17:43094464-43094464

# Pull the entire BRCA1 gene region
samtools faidx ref_grch38.fna.bgz chr17:43044295-43125483

# Pull a region from chromosome 22
samtools faidx ref_grch38.fna.bgz chr22:1-50000

# Pull multiple regions at once
samtools faidx ref_grch38.fna.bgz chr17:43044295-43125483 chr22:1-100000

# List all chromosomes and their sizes (from the .fai index)
cut -f1,2 ref_grch38.fna.bgz.fai

# Output format: FASTA header + sequence
# >chr17:43044295-43125483
# ATCGATCGATCG...

4. bcftools — Query the Variant Database (VCF File)

The VCF file contains 4.2 million positions where NA12878's DNA differs from the reference. bcftools is the primary tool for querying it.

# ─── BASIC QUERIES ───────────────────────────────

# Show VCF header (metadata about the file)
bcftools view -h na12878.vcf.gz | less

# Show first 10 variant records
bcftools view na12878.vcf.gz | grep -v "^#" | head -10

# Count total number of variants
bcftools view na12878.vcf.gz | grep -vc "^#"

# ─── FILTER BY CHROMOSOME / REGION ──────────────

# All variants on chromosome 22
bcftools view -r chr22 na12878.vcf.gz | less

# Variants in a specific gene region (BRCA1)
bcftools view -r chr17:43044295-43125483 na12878.vcf.gz

# Save region to a new file
bcftools view -r chr17:43044295-43125483 na12878.vcf.gz -o brca1_variants.vcf

# Multiple regions at once
bcftools view -r chr17:43044295-43125483,chr22:1-5000000 na12878.vcf.gz

# ─── FILTER BY VARIANT TYPE ──────────────────────

# Show only SNPs (single nucleotide changes)
bcftools view -v snps na12878.vcf.gz | head -20

# Show only indels (insertions + deletions)
bcftools view -v indels na12878.vcf.gz | head -20

# Count SNPs
bcftools view -v snps na12878.vcf.gz | grep -vc "^#"

# Count indels
bcftools view -v indels na12878.vcf.gz | grep -vc "^#"

# ─── STATISTICS ──────────────────────────────────

# Full stats report (ts/tv ratio, indel sizes, quality distribution)
bcftools stats na12878.vcf.gz > na12878_stats.txt
less na12878_stats.txt

# Quick summary stats
bcftools stats na12878.vcf.gz | grep "^SN"

# ─── ADVANCED QUERIES ────────────────────────────

# Extract only the chromosome, position, ref, alt columns
bcftools query -f '%CHROM\t%POS\t%REF\t%ALT\n' na12878.vcf.gz | head -20

# Count insertions (ALT longer than REF)
bcftools view -v indels na12878.vcf.gz | awk '!/^#/ && length($5) > length($4)' | wc -l

# Count deletions (REF longer than ALT)
bcftools view -v indels na12878.vcf.gz | awk '!/^#/ && length($4) > length($5)' | wc -l

# Find the largest indels (most disruptive)
bcftools view -v indels na12878.vcf.gz | awk '!/^#/ {print length($4)-length($5), $0}' | sort -n | tail -10

# Check if a specific position has a variant
bcftools view -r chr17:43094464-43094464 na12878.vcf.gz

5. tabix — Indexed Random Access (Jump to Any Position Instantly)

tabix is like a GPS for a compressed genomic file. Once a file is indexed, it can seek directly to any chromosome:position without reading from the start.

# Build a tabix index on a VCF (creates .tbi file)
tabix -p vcf na12878.vcf.gz

# Query a region directly — millisecond access on a 450 MB file
tabix na12878.vcf.gz chr17:43044295-43125483

# Query chromosome 22 entirely
tabix na12878.vcf.gz chr22

# List all chromosomes in the file
tabix -l na12878.vcf.gz

# Build a tabix index on a FASTA file
tabix -p fasta genome.fasta.gz

6. grep — Pattern Search Inside Any Genomic File

# Find all chromosome headers in FASTA
gzcat ref_grch38.fna.bgz | grep "^>"

# Find a specific chromosome header
gzcat ref_grch38.fna.bgz | grep "^>chr22"

# Show chr22 header + the next 5 lines of sequence
gzcat ref_grch38.fna.bgz | grep "^>chr22" -A 5

# Count how many lines contain a specific motif (e.g. BRCA1 gene ID)
bcftools view na12878.vcf.gz | grep -c "BRCA1"

# Search VCF for a specific rs-ID (dbSNP variant identifier)
bcftools view na12878.vcf.gz | grep "rs28897672"

# Count lines NOT starting with # (count actual variants, skip header)
bcftools view na12878.vcf.gz | grep -vc "^#"

7. sed — Stream Filter by Range

sed is the tool that isolates one chromosome from the 38-million-line genome stream.

# Isolate chromosome 22 from start to the next chromosome header
gzcat ref_grch38.fna.bgz | sed -n '/^>chr22/,/^>chr[^2]/p' | head -20

# How it works:
#   -n          suppress default printing
#   /^>chr22/   start printing when this pattern is matched
#   ,/^>chr/    stop printing when ANY new chromosome header is matched
#   p           print the matching range

# Isolate lines between two patterns and save to file
gzcat ref_grch38.fna.bgz | sed -n '/^>chr22/,/^>chrX/p' > chr22_only.fasta

8. awk — Column Math on Genomic Data

awk treats each line as columns separated by tabs. VCF files have 8+ tab-separated columns — awk lets you calculate on them.

# VCF column structure:
# $1=CHROM  $2=POS  $3=ID  $4=REF  $5=ALT  $6=QUAL  $7=FILTER  $8=INFO

# Print chromosome and position of every variant
bcftools view na12878.vcf.gz | awk '!/^#/ {print $1, $2}'

# Calculate indel size (positive = deletion, negative = insertion)
bcftools view -v indels na12878.vcf.gz | awk '!/^#/ {print length($4)-length($5), $1, $2}'

# Show only variants with quality score above 50
bcftools view na12878.vcf.gz | awk '!/^#/ && $6 > 50'

# Count variants per chromosome
bcftools view na12878.vcf.gz | awk '!/^#/ {count[$1]++} END {for(c in count) print c, count[c]}' | sort -V

9. snpEff — Annotate What Variants Actually Do

# Annotate chr22 only (memory-safe, ~3 GB RAM)
bcftools view -r chr22 na12878.vcf.gz | \
  java -Xmx8g -jar snpEff/snpEff.jar GRCh38.109 - > chr22_annotated.vcf

# Annotate full genome (requires 16 GB free RAM)
java -Xmx16g -jar snpEff/snpEff.jar GRCh38.109 na12878.vcf.gz > na12878_annotated.vcf 2>snpeff.log

# Monitor progress while running
tail -f snpeff.log

# After annotation — compress and index the output
bgzip na12878_annotated.vcf
tabix -p vcf na12878_annotated.vcf.gz

# Query annotated file for missense variants only
bcftools view na12878_annotated.vcf.gz | grep "missense_variant"

# Query annotated file for BRCA1 gene
grep BRCA1 snpEff_genes.txt

# Open the HTML summary report in browser
open snpEff_summary.html

10. Full Pipeline — From Download to Annotation in One Flow

# ─── COMPLETE PIPELINE ───────────────────────────────────────────
mkdir -p ~/na12878_pipeline && cd ~/na12878_pipeline

# 1. Download reference genome
curl -O https://ftp.ensembl.org/pub/release-110/fasta/homo_sapiens/dna/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz

# 2. Download NA12878 variant calls
curl -O https://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/release/NA12878_HG001/NISTv3.3.2/GRCh38/HG001_GRCh38_GIAB_highconf_CG-IllFB-IllGATKHC-Ion-10X-SOLID_CHROM1-X_v.3.3.2_highconf_PGandRTGphasetransfer.vcf.gz
curl -O https://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/release/NA12878_HG001/NISTv3.3.2/GRCh38/HG001_GRCh38_GIAB_highconf_CG-IllFB-IllGATKHC-Ion-10X-SOLID_CHROM1-X_v.3.3.2_highconf_PGandRTGphasetransfer.vcf.gz.tbi
mv HG001_GRCh38_GIAB_highconf_*.vcf.gz na12878.vcf.gz
mv HG001_GRCh38_GIAB_highconf_*.vcf.gz.tbi na12878.vcf.gz.tbi

# 3. Compress and index the reference
bgzip -c Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz > ref_grch38.fna.bgz
samtools faidx ref_grch38.fna.bgz

# 4. Index the VCF
bcftools index na12878.vcf.gz

# 5. Quick sanity check — list chromosomes, count variants
tabix -l na12878.vcf.gz
bcftools view na12878.vcf.gz | grep -vc "^#"

# 6. Annotate chr22 (memory-safe first run)
bcftools view -r chr22 na12878.vcf.gz | \
  java -Xmx8g -jar snpEff/snpEff.jar GRCh38.109 - > chr22_annotated.vcf

# 7. View results
open snpEff_summary.html

The Woman Behind the Genome: NA12878

Who Is NA12878?

NA12878 is the sample identifier assigned to a real woman known within the global genomics community as HG001. She is a Utah resident of Northern and Western European ancestry — a mother, grandmother, and one of the most important people in the history of modern genetics. She voluntarily donated a blood sample to science, knowing it would be sequenced and made publicly available for research around the world.

Her genome has been sequenced more times than any other human genome in history. It serves as the foundational quality control standard used by every major sequencing center, software developer, and bioinformatics researcher on Earth.

The CEPH Collection (1980s)

NA12878's story begins with the Centre d'Etude du Polymorphisme Humain (CEPH), a French genetics institute founded in Paris in 1983. CEPH recruited large three-generation families and collected DNA samples from grandparents, parents, and children. These families, called the CEPH pedigrees, gave scientists the ability to track how genetic variants are inherited across generations — a process called linkage analysis.

NA12878 belongs to CEPH family 1463. The "NA" prefix stands for North American. The "12878" is her permanent, anonymized lab identifier. She is one member of a multi-generation family that donated samples together, allowing scientists to verify which variants she inherited from which parent.

Why this matters: Because three generations of her family donated DNA, researchers can phase NA12878's genome — meaning they can determine which variants came from her mother and which from her father. This is extremely rare and valuable. Most sequencing data cannot do this.

Genome in a Bottle (GIAB) — The Gold Standard

In 2011, the National Institute of Standards and Technology (NIST) launched the Genome in a Bottle Consortium. Their mission: create a human genome reference so deeply verified that it could be trusted as a universal benchmark. NA12878 was selected as the first subject.

Her genome was sequenced using every major sequencing technology available — Illumina short reads, Pacific Biosciences long reads, Oxford Nanopore, Complete Genomics, Ion Torrent, and more — and the results were cross-validated against each other to produce a high-confidence variant call set: a list of every position in her genome where she differs from the reference, with the highest confidence rating in the field.

Technology UsedCoverage DepthPurpose
Illumina (short reads)300×High-accuracy SNP calling
Pacific Biosciences (long reads)~60×Structural variant resolution
Oxford Nanopore~30×Phasing and long-range context
Complete Genomics~200×Independent SNP validation
Ion Torrent~150×Indel accuracy cross-check
What "300× coverage" means: Every single base in her 3-billion-base genome was read approximately 300 times independently. Normal clinical sequencing is 30×. NA12878 is 10× more deeply verified than clinical standard.

Her Scientific Legacy

NA12878's genome has been downloaded millions of times. It is used to:

  • Validate every new DNA sequencing machine before it goes to market
  • Test and benchmark bioinformatics software (aligners, variant callers, annotation tools)
  • Train machine learning models that detect cancer mutations and rare diseases
  • Calibrate clinical laboratory pipelines before they process real patient samples
  • Serve as a teaching resource — exactly as in this project

Every time a hospital sequences a cancer patient's tumor to find the right treatment, the pipeline that produced that result was likely validated against NA12878 first. Her contribution is immeasurable.

NIST Standard Reference Material SRM 8398: NA12878's DNA is sold as a certified laboratory standard. You can purchase a tube of her DNA from NIST. The proceeds support continued genomic research.

Core Data Pipeline: Stream, Filter, Truncate

The fundamental technique in this project is Unix piping — connecting tools so data flows through them sequentially in memory, never touching the disk. This allows processing a multi-gigabyte compressed genome file without ever extracting it.

Phase 1 — Stream
gzcat genome.fasta.gz
Decompresses on the fly, streams raw text into memory — no disk write
➔
Phase 2 — Filter
sed -n '/_chr22_/,/_chrX_/p'
Activates at chr22 header, stops at chrX — isolates one chromosome
➔
Phase 3 — Brakes
head -n 20
Captures 20 lines, sends upstream kill signal — prevents terminal flood
# Full command — isolate chr22 from a compressed 38M-line genome
gzcat genome_23chromosomes.fasta.gz | sed -n '/_chr22_/,/_chrX_/p' | head -n 20
PhaseCommandFunctionTechnical Advantage
1. Stream gzcat file.fasta.gz Reads and decompresses on the fly No disk extraction — saves multi-GB of storage and eliminates I/O bottleneck
2. Filter sed -n '/_chr22_/,/_chrX_/p' Suppresses all output until chr22 header is matched; stops at chrX Isolates one chromosome boundary instantly from millions of lines
3. Halt head -n 20 Captures first 20 lines, sends SIGPIPE upstream to terminate the pipeline Acts as system brakes — prevents flooding from 50M+ base pairs of sequence

Additional Streaming Commands

# List all chromosome headers (catalog the file contents, no sequence)
gzcat genome_23chromosomes.fasta.gz | grep ">"

# Find chr22 and show 5 lines of sequence context
gzcat genome_23chromosomes.fasta.gz | grep "chr22" -A 5

# Peek at first lines of a gzipped consensus FASTA
zcat na12878_consensus.fa.gz | head

Building the Personal Genome — NA12878 Consensus

A "personal genome" is constructed by taking the universal human reference sequence (GRCh38) and applying one individual's specific variant calls on top of it. The result is a FASTA file where every position reflects that person's actual DNA, not the generic average.

The Three Build Components

FileDescriptionStatus
na12878.vcf.gz Real variant calls from the GIAB consortium — 4.2M+ positions where NA12878 differs from reference Verified
na12878_consensus.fa 3 GB FASTA — GRCh38 reference with all GIAB variants applied. Chromosome lengths are shorter than reference at correct positions, confirming real indels were incorporated. Verified
ref_grch38.fna.bgz GRCh38 reference genome (bgzip compressed, samtools indexed) Indexed
Verification method: Chromosome lengths in the consensus FASTA are shorter than GRCh38 at specific locations. This is the expected signature when real deletions (indels) are applied — it confirms the pipeline worked correctly and this is genuine NA12878 sequence, not a copy of the reference.

What the Central Database Contains

The variant calls in na12878.vcf.gz are cross-referenced against major public databases:

DatabaseHostContentsUsed For
dbSNP NCBI 800M+ SNP records across all known human populations Assigning rs-IDs to NA12878 variants — links each position to global frequency data
ClinVar NCBI Clinical significance of variants (pathogenic, benign, VUS) Identifying which of NA12878's 4.2M variants have known disease associations
gnomAD Broad Institute Allele frequencies from 140,000+ humans Population frequency comparison — how common is each variant across humanity
GIAB Benchmark NIST High-confidence variant calls for NA12878 The ground truth — used to validate that our pipeline called variants correctly
Ensembl / RefSeq EMBL / NCBI Gene annotations on GRCh38 Mapping variants to genes (used by snpEff for functional annotation)

Complete Command Reference

bcftools — Variant Analysis

# Index the VCF file (required before most operations)
bcftools index -f na12878.vcf.gz

# Full variant statistics report → save to file
bcftools stats na12878.vcf.gz > na12878_stats.txt

# Extract the BRCA1 gene region (chr17:43044295–43125483)
bcftools view -r chr17:43044295-43125483 na12878.vcf.gz > brca1_variants.vcf

# Count total SNPs
bcftools view -v snps na12878.vcf.gz | grep -vc "^#"

# Count total indels
bcftools view -v indels na12878.vcf.gz | grep -vc "^#"

# Count insertions (ALT longer than REF)
bcftools view -v indels na12878.vcf.gz | awk 'length($5) > length($4)' | wc -l

# Count deletions (REF longer than ALT)
bcftools view -v indels na12878.vcf.gz | awk 'length($4) > length($5)' | wc -l

# Rank indels by size — find the largest structural variants
bcftools view -v indels na12878.vcf.gz | awk '{print length($4)-length($5), $0}' | sort -n | tail

# Inspect a specific coordinate
bcftools view -r chr17:43094464-43094464 na12878.vcf.gz

# Check for phase set (PS) tags in VCF header
bcftools view -h na12878.vcf.gz | grep PS

snpEff — Functional Annotation

# Annotate VCF with gene consequences against GRCh38 Ensembl 109
java -Xmx8g -jar snpEff/snpEff.jar GRCh38.109 na12878.vcf.gz > na12878_annotated.vcf

# Compress and index the annotated output
bgzip na12878_annotated.vcf
tabix -p vcf na12878_annotated.vcf.gz

# Check BRCA1 annotation results
grep BRCA1 snpEff_genes.txt | head

# Open HTML summary in browser
open snpEff_summary.html

samtools — Reference Lookup

# Pull a single base from the reference genome at a specific coordinate
samtools faidx ref_grch38.fna.bgz chr17:43094464-43094464

bwa — Alignment Index Build

# Build search index for the consensus genome (~45–90 min for 3 GB)
# Produces: .bwt .pac .ann .amb .sa auxiliary files
bwa index na12878_consensus.fa

# Build index for GRCh38 reference (same duration)
bwa index ref_grch38.fna.bgz

# After indexing: align reads and compare flagstat output between
# personalized consensus vs generic reference
Educational point of the alignment benchmark: Aligning NA12878's own sequencing reads to her personalized consensus genome produces slightly better alignment statistics than aligning to the generic GRCh38 reference. This is the scientific argument for personalized reference genomes in clinical settings.

Chromosomal Ancestry Architecture

Source: 23andMe Ancestry Composition (0.5 confidence phasing threshold) · Reference assembly: GRCh37/hg19.
Humans carry two copies of every chromosome — one inherited from each parent. Copy 1 and Copy 2 below represent these independent maternal/paternal inheritances.

What these coordinates mean: Each row is a chromosome segment — a contiguous stretch of DNA that matches a specific ancestral reference population with statistical confidence. The coordinates are base-pair positions on the chromosome, measured from the start of the chromosome (position 1).
Chromosome Copy Start (bp) End (bp) Length (bp) Assigned Panel
chr1190,013,233150,811,44660,798,213West Asian & N. African
chr2152,384,66876,488,56424,103,896West Asian & N. African
chr2171,579,69776,488,5644,908,867Broadly N. West Asian
chr21222,330,122243,041,41120,711,289West Asian & N. African
chr21222,330,122226,890,0574,559,935Broadly N. West Asian
chr21226,890,057243,041,41116,151,354Anatolian
chr3193,903,80796,505,8902,602,083Unassigned — Gap A
chr31137,044,802138,933,3221,888,520Unassigned — Gap B
chr3266,206173,734,047173,667,841West Asian & N. African
chr3266,2062,235,2552,169,049Broadly N. West Asian
chr322,379,000173,734,047171,355,047Broadly N. West Asian
chr42155,273,743156,602,2051,328,462Unassigned — Gap C
chr42156,602,205190,125,92533,523,720West Asian & N. African
chr61174,79873,493,53473,318,736Anatolian
chr61124,264,783148,587,09624,322,313Anatolian
chr717,358,814104,145,76596,786,951Anatolian
chr81103,686,204119,113,07815,426,874Arab, Egyptian & Levantine
chr10224,850,941102,918,48678,067,545Anatolian
chr13149,545,81151,272,0841,726,273Unassigned — Gap D
chr13219,503,42243,695,44924,192,027Anatolian
chr132105,172,434106,216,0871,043,653Unassigned — Gap E
chr18251,751,72253,824,8822,073,160Unassigned — Gap F
chr19154,085,33559,097,9335,012,598Anatolian
chr19214,719,25415,949,4051,230,151Unassigned — Gap G
chr21121,856,74824,719,9612,863,213Unassigned — Gap H
chr21221,856,74848,099,61026,242,862Anatolian

Algorithmic Gap Resolution

An Unassigned segment does not mean missing DNA. It means those nucleotides match multiple reference panels with equal statistical confidence — the algorithm cannot choose a winner. By examining what flanks the gap on both sides (the flanking context resolution method), the underlying structure becomes clear.

Gaps A & B — Chromosome 3, Copy 1

A: 93.9M–96.5M (2.60 Mb)  |  B: 137.0M–138.9M (1.88 Mb)

Both gaps are embedded inside a dominant long-range Greek & Balkan / Southern European ancestral block. They are small, both flanks carry identical signatures — these are uniform European blocks with common polymorphic variations that the reference panel cannot sub-classify. No lineage break. Continuous Aegean heritage.

Gap C — Chromosome 4, Copy 2

C: 155.3M–156.6M (1.32 Mb)

This is a textbook meiotic recombination breakpoint. The DNA upstream of 155,273,743 tracks to the Southern European / Italian reference panel. The DNA immediately downstream of 156,602,205 transitions directly into a West Asian & North African / Cypriot segment. The gap is the precise structural bridge linking the European and Eastern Mediterranean ancestral branches.

Gaps D & E — Chromosome 13

D: 49.5M–51.2M (1.72 Mb)  |  E: 105.2M–106.2M (1.04 Mb)

Gap D is an internal Southern European transition. Gap E is tightly flanked by a general Southern European segment and a Greek & Balkan block, confirming continuous Greek heritage across both boundaries.

Gaps F, G, H — Chr 18, 19, 21

F: 51.7M–53.8M  |  G: 14.7M–15.9M  |  H: 21.8M–24.7M

These are consistently bounded on one side by Anatolian / West Asian blocks and on the other by Southern European / Greek segments. They act as regional transition boundaries — reflecting centuries of historic genetic overlap between the populations of Asia Minor, Cyprus, and the Aegean basin.

Mitochondrial Haplogroup: H15a1

Mitochondrial DNA (mtDNA) is inherited exclusively through the maternal line — mother to child, unchanged except for rare mutations. Every mutation that accumulates in the mtDNA over thousands of generations creates a branch in the maternal family tree. The terminal branch is the haplogroup.

[Macro-Haplogroup H] — ~20,000 BCE — Europe / Near East (post-Last Glacial Maximum expansion) │ └──► [Sub-Clade H15] ~5,150 BCE — Neolithic branching in the Near East / Aegean corridor │ └──► [H15a] — Sub-branch defined by position 16298 transition │ └──► [H15a1] ~3,000 BCE — Bronze Age terminal mutation Defining: pos 1023, 1438, 16298, 8152

The Four Defining Mutations

PositionRole
1023 & 1438Branch separation within the ancient H15 lineage — splits H15 from other H sub-groups
16298Establishes the H15a sub-branch — the hypervariable region transition
8152The definitive mutation locking lineage directly into H15a1 — the terminal identifier

Modern Geographic Distribution

Unlike broad Western European H branches that dominate the Iberian Peninsula and Atlantic coast, modern H15a1 carriers concentrate specifically around:

  • Greece & the Aegean Islands
  • Cyprus
  • Armenia
  • Iran & northern Iraq
  • Tajikistan & the Caucasus corridor

This distribution maps directly onto the autosomal chromosome pattern in Section 5 — the same Eastern Mediterranean / Anatolia / Levant signature appears in both independent data streams.

Why H15a1 matters scientifically: Because mtDNA is non-recombining (it does not shuffle like autosomal DNA), the haplogroup is a pure maternal signal going back 5,000+ years. It tells us about the population your maternal ancestors lived in — their migration routes, climate adaptations, and historical movements — independent of any paternal influence.

Comparison: Anonymized Profile vs. Central Reference Database

The following comparison maps the chromosomal ancestry segments from this pipeline against the population panels in the 23andMe reference database (derived from gnomAD, HGDP, 1000 Genomes, and proprietary reference panels). Percentages reflect proportion of assigned base pairs per ancestry cluster.

Autosomal Ancestry Distribution (Assigned Segments Only)

Anatolian
~38%
West Asian & N. African
~31%
Broadly N. West Asian
~16%
Arab, Egyptian & Levantine
~8%
Unassigned Gaps
~7%

NA12878 vs. Anonymized Profile — Key Differences

Feature NA12878 (Reference Standard) Anonymized Profile (This Pipeline)
Primary ancestry Northern & Western European (British Isles / Utah CEPH cohort) Anatolian / Eastern Mediterranean / Aegean
mtDNA haplogroup H (broad Western European branch) H15a1 (Eastern Mediterranean / Aegean specific)
Reference assembly GRCh38 (pipeline uses GRCh38 for consensus build) GRCh37/hg19 (23andMe ancestry composition)
Sequencing depth 300× (multiple platforms, GIAB verified) Consumer SNP microarray (~650,000 positions genotyped)
Total variants vs. reference 4.2M+ in high-confidence call set SNP array — subset of common variant positions only
Phasing Full trio phasing (3-generation family data) Statistical phasing at 0.5 confidence threshold
Primary ancestral signal Northwestern European — low admixture Deeply admixed Aegean / Asia Minor / Levant — complex mosaic

How the Comparison Pipeline Works

When comparing this profile's chromosome segments to the central database, the process follows these steps:

  1. Phased segment extraction: 23andMe's internal algorithm phases the ~650,000 SNP positions into maternal and paternal haplotypes (Copy 1 / Copy 2)
  2. Reference panel matching: Each phased segment is compared against 31 reference populations using a Hidden Markov Model (HMM) — the same statistical method used in scientific population genetics
  3. Boundary detection: Recombination breakpoints are identified where population signatures change — these are the segment boundaries in the coordinate ledger
  4. Confidence thresholding: At 0.5 threshold, segments are only assigned when the top reference panel match has at least 50% posterior probability — tighter than the default 0.3 setting
  5. Gap classification: Regions where no panel exceeds the threshold are marked Unassigned — these are the 8 gap windows in the dataset

Completed Pipeline Run: snpEff Annotation Results

The following results were produced by running the full annotation pipeline on the NA12878 dataset on macOS Apple Silicon. The full 3.6 million variant run required a memory workaround — details below.

Memory issue resolved: Running snpEff on all 3.6M variants simultaneously exceeded 8 GB RAM. The fix was to analyze Chromosome 22 alone first (manageable at ~3 GB), then scale to the full genome with -Xmx16g.
3.6M
Total variants in full NA12878 VCF
42,000
Variants on Chromosome 22 (annotated)
453
Missense — actual amino acid changes
147,704
Intronic (inside genes, non-coding)
502
Synonymous / silent mutations
159
Splice region variants

Chromosome 22 Variant Classification — From Least to Most Significant

snpEff assigns each variant a functional consequence based on where it falls in the genome. Severity increases from top to bottom.

CategoryCountLocationProtein ImpactSignificance
Intergenic / Upstream / Downstream ~65,000 Outside gene boundaries — the "desert" of the genome None Very Low
Intron variant 147,704 Inside a gene, in the non-coding "junk" spaces between exons Usually none — introns are spliced out Low
Non-coding exon 3,108 Inside a functional gene region — but for RNA genes, not protein-coding May affect RNA gene regulation Moderate
Synonymous / Silent 502 Inside protein-coding gene None — same amino acid due to genetic code redundancy Moderate
Splice region 159 At the cut-and-paste boundaries where the cell reads gene segments Can break how a gene is assembled — may produce wrong protein High
Missense / Amino acid change 453 Inside protein-coding gene Changes an amino acid — the protein building block is swapped Most Significant
Why missense matters: Of all 42,000 chr22 variants, only 453 actually swap an amino acid. Those 453 are the candidates researchers examine first when looking for disease associations, trait markers, or drug targets. The rest are either silent or in non-functional regions.

Visual Outputs Generated

FileWhat It ShowsHow to Open
na12878_karyogram.png Full genome map showing where mutations are densest across all 23 chromosomes — visually identifies hotspot regions open ~/na12878_pipeline/*.png
na12878_indels.png Histogram of insertion/deletion lengths — shows whether mutations are small (1–2 bp) or large structural events

Critical Gene Comparison Results

The pipeline also extracted and compared variants in four clinically significant genes against the reference genome:

GeneFull NameClinical RelevanceWhy It Was Analyzed
BRCA1 Breast Cancer 1 Hereditary breast and ovarian cancer risk Most studied cancer-risk gene. Variants here have direct clinical screening implications.
APOE Apolipoprotein E Alzheimer's disease risk (APOE ε4 allele) The ε4 variant triples Alzheimer's risk. Identifying which allele(s) are present is a major research target.
TP53 Tumor Protein p53 Cancer suppressor — "guardian of the genome" Mutated in over 50% of all human cancers. Baseline variant status matters for cancer risk profiling.
MTHFR Methylenetetrahydrofolate reductase Folate metabolism, cardiovascular and neurological risk Two common variants (C677T, A1298C) affect how the body processes B vitamins and homocysteine.

Commands: View Results & Scale to Full Genome

# Open all generated PNG graphs
open ~/na12878_pipeline/*.png

# ─────────────────────────────────────────────────────
# To run snpEff on the FULL 3.6M variant dataset:
# Restart Mac first to clear RAM, then:
# ─────────────────────────────────────────────────────
cd ~/na12878_pipeline

/opt/homebrew/Caskroom/miniconda/base/bin/conda run -n snpeff_env \
  snpEff -Xmx16g GRCh38.99 na12878.vcf.gz > na12878_annotated.vcf 2>snpeff.log

# -Xmx16g = allow snpEff to use up to 16 GB RAM
# Requires at least 16 GB free before running
# Monitor progress: tail -f snpeff.log
Scaling note: Chromosome 22 has ~42,000 variants and used ~3 GB RAM. The full genome has 3.6 million variants — roughly 85× more. Plan for 12–16 GB RAM and 30–60 minutes of processing time on Apple Silicon.

macOS Compatibility Notes

The zcat Problem on macOS

PlatformCommandHandles .gz?Reason
LinuxzcatYesGNU version handles both .Z and .gz
macOSzcatNoBSD version expects legacy .Z (LZW) format only
macOSgzcatYesNatively handles modern Gzip (DEFLATE) streams
macOSgunzip -cYesAlternative — decompresses to stdout without saving
# Error you will see on macOS with the wrong command:
# zcat: can't stat: genome.fasta.gz (genome.fasta.gz.Z): No such file or directory

# Correct macOS commands:
gzcat genome.fasta.gz | head
gunzip -c genome.fasta.gz | head

Convert This Report to PDF

# Install pandoc and a minimal LaTeX engine
brew install pandoc basictex

# Convert the Markdown report to a PDF
pandoc GENOMIC_PIPELINE_REPORT.md -o Genomic_Operations_Report.pdf

Or open this HTML file in any browser and use Cmd + P → Save as PDF for a direct PDF export of this full reference page.

← All articles

Research and direction by Ioannis (John) Konstas; compiled and finalized with AI assistance.

👁· views