omics.co.in logo omics.co.in

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:

  1. Histograms & Density Plots: Reveal underlying distributional shape, bimodality, and extreme tails.
  2. 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.
  3. Scatter Plots with Trend Lines: Depict continuous bivariate relationships with ordinary least squares (method = "lm") or non-linear Loess smoothing (method = "loess").
  4. 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 chr1 or 1; divergent naming causes silent alignment drops.
Was this guide helpful to your research?
Help us maintain 100% accurate, peer-reviewed bioinformatics standards.
📝 Propose Edit on GitHub ↗