A Simple Guide to Building Phylogenetic Trees and Heatmaps in R
In this quick tutorial, we will build a simple pipeline to map out the evolutionary history of the Canidae family (dogs, wolves, and foxes), using a domestic cat as an outgroup. We will fetch real DNA data directly from a public database, align the sequences, and generate both a phylogenetic tree and a genetic distance heatmap.
Get Maooz Abdullah’s stories in your inbox
Join Medium for free to get updates from this writer.
Here is how you can do it in just a few steps.
1. Setting Up and Fetching Real Data
First, we need to load our core bioinformatics packages. Instead of downloading files manually, we will use the rentrez package to pull the real mitochondrial Cytochrome b gene sequences directly from the NCBI database using their unique Accession Numbers.
library(rentrez)
library(Biostrings)
library(msa)
library(ape)
library(ggtree)
library(ggplot2)
setwd(tempdir())# Fetch real data from NCBI (Cytochrome B)
accession_numbers <- c(
"AB004237", "AM181037", "KM224347", "AJ441334","MN990717","DQ480509", "MG490401","AY291430")
# Fetch the raw FASTA data
fasta_data <- entrez_fetch(db="nucleotide", id=accession_numbers, rettype="fasta")
# Create a secure temporary file and read it into Biostrings
temp_fasta <- tempfile(fileext = ".fasta")
write(fasta_data, temp_fasta)
dna_seqs <- readDNAStringSet(temp_fasta)
# Rename the sequences to match our species
names(dna_seqs) <- c(
"Felis_catus",
"Vulpes_vulpes",
"Vulpes_lagopus",
"Canis_lupus",
"Canis_familiaris",
"Canis_latrans",
"Lycaon_pictus",
"Cuon_alpinus"
)2. Aligning and Calculating Genetic Distance
DNA sequences naturally have mutations, so before we can compare them, we have to line them up perfectly. We use the msa package to run a ClustalW alignment. Once aligned, we use the ape package to calculate a mathematical distance matrix—essentially scoring how many mutations separate each species.
# Run the ClustalW alignment algorithm
alignment <- msa(dna_seqs, method="ClustalW")# Convert to standard format and calculate genetic distance
dna_bin <- as.DNAbin(alignment)
distance_matrix <- dist.dna(dna_bin, model="K80")3. Drawing the Phylogenetic Tree
With our math done, visualizing the tree is incredibly straightforward. We use the Neighbor-Joining (nj) method to build the structure, and R's base plot function to draw it.
# Build the tree using the Neighbor-Joining method
tree <- nj(distance_matrix)# Draw the tree
plot(tree,
main="Evolutionary Divergence of Canidae (Cytochrome b)",
cex=1.1,
edge.width=2,
type="phylogram",
align.tip.label=FALSE)When you run this, you will clearly see the evolutionary splits: the foxes branch off first, while the domestic dog and gray wolf sit closely together on their own branch, far away from the feline outgroup.
4. Creating a Distance Heatmap
While trees are great for showing timelines, heatmaps are fantastic for showing raw genetic differences in a color-coded grid. We can pass the exact same distance matrix into the pheatmap package to get a completely different perspective on our data.
if (!requireNamespace("pheatmap", quietly = TRUE)) install.packages("pheatmap")
library(pheatmap)dist_mat <- as.matrix(distance_matrix)
pheatmap(dist_mat,
main = "Canidae Genetic Distance Matrix",
color = colorRampPalette(c("#007f5f", "#aacc00", "#ffff3f"))(50),
display_numbers = TRUE,
fontsize_number = 10,
fontsize_row = 8,
fontsize_col = 8,
angle_col = 0)The custom green-to-yellow color palette highlights similarity. Deep green squares instantly show us which species are genetically nearly identical, while the bright yellow highlights the massive evolutionary gap between the canine group and the cat.









