Module 4: Visualizing Scientific Data & Exploring Patterns with ggplot2
Tested Stacks:
GATK 4.6.1
Samtools 1.21
Nextflow 24.10
Seurat v5.1
Python 3.12
Prerequisites: Basic Linux CLI & Sequencing Formats
Module 04 • Data Visualization
Track 19 • Applied Environmental Statistics
Hands-On R & RStudio Included
Module 4: Visualizing Scientific Data & Exploring Patterns with ggplot2
The Grammar of Graphics in R: distribution histograms, kernel density curves, publication boxplots with jittered raw observation points, violin plots, temporal pollution trends, and multi-panel faceting.
4. Scientific Data Visualization with ggplot2: Exploring Patterns & Trends
Visual exploration is the foundation of sound scientific analysis. The ggplot2 package implements Wilkinson's Grammar of Graphics, composing charts from decoupled aesthetic mappings (aes()), geometric objects (geom_*), coordinate scales, and visual themes.
The 4 Essential Visualizations for Scientific Papers:
- Histograms & Density Plots: Reveal underlying distributional shape, bimodality, and extreme tails.
- Boxplots with Overlaid Jitter: Never show bare bar charts ("dynamite plungers")! Combine Tukey boxplots showing median & quartiles with semi-transparent jittered points showing actual sample size.
- Scatter Plots with Trend Lines: Depict continuous bivariate relationships with ordinary least squares (
method = "lm") or non-linear Loess smoothing (method = "loess"). - Faceted Multi-Panel Grids: Compare trends across seasons, monitoring depths, or geographic watersheds using
facet_wrap(~ site).
Hands-On R Script: Publication-Ready Boxplot with Jittered Observations
library(ggplot2)
library(dplyr)
# Generate publication-grade figure of Heavy Metal Lead (Pb) across 3 Estuary Basins
set.seed(88)
estuary_data <- tibble(
basin = factor(rep(c("North Bay", "Central Harbor", "South Estuary"), each = 25)),
lead_mg_kg = c(rlnorm(25, meanlog = 1.2, sdlog = 0.4),
rlnorm(25, meanlog = 2.4, sdlog = 0.5),
rlnorm(25, meanlog = 1.8, sdlog = 0.3))
)
p <- ggplot(estuary_data, aes(x = basin, y = lead_mg_kg, fill = basin)) +
# 1. Semi-transparent boxplot showing median and IQR
geom_boxplot(alpha = 0.6, outlier.shape = NA, width = 0.5, color = "#1e293b") +
# 2. Overlaid jittered raw data points to display sample size and density
geom_jitter(width = 0.18, alpha = 0.8, size = 2.2, shape = 21, stroke = 0.5, color = "black") +
# 3. Scientific color palette & publication theme
scale_fill_manual(values = c("#38bdf8", "#f43f5e", "#10b981")) +
theme_bw(base_size = 12) +
theme(
legend.position = "none",
panel.grid.minor = element_blank(),
axis.title = element_text(face = "bold"),
plot.title = element_text(face = "bold", size = 13)
) +
labs(
title = "Sediment Lead (Pb) Concentrations Across Estuary Basins",
subtitle = "Points represent individual sediment core samples (n = 25 per basin)",
x = "Estuary Monitoring Basin",
y = expression(paste("Sediment Lead Concentration (mg ", kg^{-1}, ")"))
)
print(p)
# Save at 300 DPI for journal submission
# ggsave("figure1_lead_sediments.png", plot = p, width = 7, height = 5, dpi = 300)
⚠️
Common Pitfalls & Troubleshooting Checklist
- Java Heap Exhaustion (GATK / Picard): If processes terminate with
java.lang.OutOfMemoryError, set your environment variable explicitly:export _JAVA_OPTIONS="-Xmx16g -Djava.io.tmpdir=/tmp". - Index Timestamp Mismatch: If tools complain that a BAM index is missing or out of date, regenerate with
samtools index -@ 4 sample.bam. - Conda Channel Conflicts: Avoid ABI incompatibilities between bioconda and conda-forge by setting strict priority:
conda config --set channel_priority strict. - Chromosome Naming Contamination: Always verify whether reference FASTA headers use
chr1or1; divergent naming causes silent alignment drops.
Was this guide helpful to your research?
Help us maintain 100% accurate, peer-reviewed bioinformatics standards.