omics.co.in logo omics.co.in

Module 10: Capstone Project: End-to-End Environmental Case Study & Reproducible Reporting

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 10 • Capstone & Reporting Track 19 • Applied Environmental Statistics Hands-On R & RStudio Included

Module 10: Capstone Project: End-to-End Environmental Case Study & Reproducible Reporting

Complete real-world investigation: analyzing river water quality, nutrient runoff, and heavy metal concentrations along an urban-agricultural gradient, generating reproducible R Markdown / Quarto reports and high-res figures.

10. Capstone Project: End-to-End Environmental Case Study & Reproducible Reporting

In this capstone module, you synthesize all foundational statistical concepts into an end-to-end scientific research project. You will analyze a real-world multi-site watershed investigation assessing the impact of urbanization and agricultural runoff on river ecosystem health.

The 6-Step Publication-Grade Workflow:

  1. Data Ingestion & Tidy Architecture: Load field monitoring matrices and inspect variable types.
  2. Exploratory Data Analysis: Compute central tendency, spread, and standard error across ecological strata.
  3. Assumption Verification: Test residual normality (Shapiro-Wilk) and homoscedasticity (Levene's test).
  4. Inferential Modeling: Execute ANOVA, post-hoc Tukey HSD, and linear regression models.
  5. Publication Graphics: Build multi-panel figures (ggplot2 + patchwork) with statistical annotation brackets.
  6. Reproducible Synthesis: Compile findings into dynamic R Markdown / Quarto documents with complete session info metadata.

Complete Production R Script: The Watershed Case Study

# Complete Capstone Watershed Analysis Script
library(tidyverse)

# 1. Generate Synthetic Multi-Site Watershed Dataset (n = 80 samples)
set.seed(2026)
watershed <- tibble(
  sample_id  = paste0("SAMP_", sprintf("%03d", 1:80)),
  zone       = factor(rep(c("Pristine_Headwater", "Agricultural_Midstream", "Urban_Downstream", "Restored_Wetland"), each = 20)),
  turbidity  = c(rnorm(20, 2.1, 0.4), rnorm(20, 8.4, 1.2), rnorm(20, 19.5, 3.1), rnorm(20, 4.2, 0.8)), # NTU
  nitrate    = c(rnorm(20, 0.35, 0.08), rnorm(20, 6.2, 1.1), rnorm(20, 8.9, 1.4), rnorm(20, 1.8, 0.4)), # mg/L
  bio_index  = c(rnorm(20, 88, 6), rnorm(20, 52, 8), rnorm(20, 24, 7), rnorm(20, 71, 5)) # EPT Biotic Index
)

# 2. Descriptive Statistics Summary Table
stats_summary <- watershed %>%
  group_by(zone) %>%
  summarise(
    n           = n(),
    mean_bio    = mean(bio_index),
    sd_bio      = sd(bio_index),
    sem_bio     = sd(bio_index) / sqrt(n()),
    mean_nitrate = mean(nitrate),
    sd_nitrate  = sd(nitrate)
  )
print(stats_summary)

# 3. Hypothesis Testing: Does Macroinvertebrate Health Differ Significantly by Zone?
anova_bio <- aov(bio_index ~ zone, data = watershed)
summary(anova_bio)

# Check Normality of Model Residuals
shapiro_res <- shapiro.test(residuals(anova_bio))
cat("Shapiro-Wilk p-value:", shapiro_res$p.value, "
")

# Post-Hoc Comparisons
tukey_bio <- TukeyHSD(anova_bio)
print(tukey_bio)

# 4. Regression Analysis: Predicting Biotic Health from Nutrient Pollution
model_nitrate_bio <- lm(bio_index ~ nitrate, data = watershed)
summary(model_nitrate_bio)

# 5. Publication Visualization with ggplot2
fig_a <- ggplot(watershed, aes(x = zone, y = bio_index, fill = zone)) +
  geom_boxplot(alpha = 0.7, width = 0.5, outlier.shape = NA) +
  geom_jitter(width = 0.15, alpha = 0.8, size = 2, shape = 21, color = "black") +
  theme_bw(base_size = 11) +
  theme(legend.position = "none", axis.text.x = element_text(angle = 20, hjust = 1)) +
  labs(title = "A: Biotic Integrity Across River Zones", y = "Macroinvertebrate Biotic Index", x = "")

fig_b <- ggplot(watershed, aes(x = nitrate, y = bio_index)) +
  geom_point(aes(color = zone), size = 2.5, alpha = 0.85) +
  geom_smooth(method = "lm", color = "black", se = TRUE) +
  theme_bw(base_size = 11) +
  labs(title = "B: Biotic Health vs. Nitrate Pollution", x = "Nitrate Concentration (mg/L)", y = "Biotic Index")

# Print figures
print(fig_a)
print(fig_b)

How to Report Statistical Results in Scientific Journals

Scientific Paper Reporting Template:

"One-way ANOVA revealed a statistically significant difference in macroinvertebrate biotic integrity across the four river zones ($F_{3, 76} = 284.1, p < 0.001, \eta^2 = 0.91$). Post-hoc pairwise comparisons using Tukey's HSD indicated that pristine headwaters exhibited significantly higher biotic health ($ ext{Mean} = 88.0, ext{SD} = 6.0$) compared to midstream agricultural reaches ($ ext{Mean} = 52.0, ext{SD} = 8.0, p < 0.001$) and urban downstream sites ($ ext{Mean} = 24.0, ext{SD} = 7.0, p < 0.001$). Linear regression analysis demonstrated that nitrate pollution explained $86\%$ of the variation in biotic degradation ($\beta = -7.21 ext{ mg}^{-1} ext{L}, R^2 = 0.86, p < 0.001$)."

⚠️

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 ↗