Skip to contents

This gallery showcases every plot function in ggforge (77 in total), organized by category. Functions requiring optional packages use eval=FALSE when the dependency is not guaranteed.

Statistics

ScatterPlot

sdata <- data.frame(
  expr_A = rnorm(120, 8, 2), expr_B = rnorm(120, 8, 2),
  tissue = sample(c("Normal", "Tumor"), 120, replace = TRUE)
)
sdata$expr_B <- sdata$expr_B + 0.6 * sdata$expr_A + rnorm(120, 0, 1.5)

ScatterPlot(sdata, x = "expr_A", y = "expr_B", group_by = "tissue",
  palette = "jco", add_smooth = TRUE, add_stat = TRUE,
  xlab = "Gene A Expression", ylab = "Gene B Expression",
  title = "Gene Correlation")

LinePlot

time_course <- data.frame(
  day = rep(c(0, 3, 7, 14, 21, 28), 2),
  tumor_vol = c(100, 120, 180, 320, 500, 780, 100, 110, 130, 150, 170, 200),
  group = rep(c("Vehicle", "Treatment"), each = 6)
)

LinePlot(time_course, x = "day", y = "tumor_vol", group_by = "group",
  palette = "lancet", title = "Tumor Growth Curve",
  xlab = "Day", ylab = "Tumor Volume (mm³)")

BarPlot

cell_freq <- data.frame(
  sample = rep(c("Patient 1", "Patient 2", "Patient 3"), each = 4),
  celltype = rep(c("T cell", "B cell", "Myeloid", "Stromal"), 3),
  fraction = c(0.45, 0.15, 0.25, 0.15, 0.30, 0.25, 0.30, 0.15,
               0.50, 0.10, 0.20, 0.20)
)

BarPlot(cell_freq, x = "sample", y = "fraction", group_by = "celltype",
  position = "stack", palette = "npg", label = TRUE,
  title = "Cell Composition", ylab = "Fraction")

BoxPlot

treat <- data.frame(
  group = rep(c("Control", "Low Dose", "High Dose"), each = 35),
  response = c(rnorm(35, 5, 1.5), rnorm(35, 7, 2), rnorm(35, 10, 2))
)

BoxPlot(treat, x = "group", y = "response", palette = "lancet",
  add_point = TRUE, pt_alpha = 0.3, comparisons = TRUE,
  title = "Dose-Response", ylab = "Response Score")

ViolinPlot

ViolinPlot(treat, x = "group", y = "response", palette = "npg",
  add_box = TRUE, add_point = TRUE, pt_alpha = 0.3,
  title = "Distribution by Treatment", ylab = "Response Score")

DensityPlot

DensityPlot(treat, x = "response", group_by = "group",
  palette = "npg", add_rug = TRUE,
  title = "Response Distribution", xlab = "Response Score")

JitterPlot

JitterPlot(treat, x = "group", y = "response", palette = "Set2",
  title = "Individual Observations", ylab = "Response Score")

BeeswarmPlot

Requires ggbeeswarm.

BeeswarmPlot(treat, x = "group", y = "response", palette = "npg",
  title = "Beeswarm Plot", ylab = "Response Score")

Histogram

Histogram(data.frame(x = c(rnorm(200, 5, 2), rnorm(200, 10, 2)),
  group = rep(c("A", "B"), each = 200)),
  x = "x", group_by = "group", palette = "Set1",
  title = "Histogram")

RidgePlot

ridge_df <- data.frame(
  value = c(rnorm(100, 3), rnorm(100, 5), rnorm(100, 7), rnorm(100, 9)),
  celltype = rep(c("T cell", "B cell", "Myeloid", "NK"), each = 100)
)

RidgePlot(ridge_df, x = "value", group_by = "celltype",
  palette = "npg", title = "Expression by Cell Type")

AreaPlot

comp <- data.frame(
  time = rep(paste0("T", 1:6), 3),
  fraction = c(0.50, 0.45, 0.40, 0.35, 0.30, 0.25,
               0.30, 0.30, 0.35, 0.35, 0.40, 0.40,
               0.20, 0.25, 0.25, 0.30, 0.30, 0.35),
  celltype = rep(c("Epithelial", "Immune", "Stromal"), each = 6)
)

AreaPlot(comp, x = "time", y = "fraction", group_by = "celltype",
  palette = "nejm", title = "Cell Composition Over Time")

TrendPlot

trend_df <- data.frame(
  x = rep(LETTERS[1:5], 2),
  y = c(2, 5, 8, 6, 3, 4, 7, 11, 9, 5),
  group = rep(c("Cohort 1", "Cohort 2"), each = 5)
)

TrendPlot(trend_df, x = "x", y = "y", group_by = "group",
  palette = "Set1", title = "Trend Comparison")

QQPlot

Requires qqplotr.

QQPlot(data.frame(values = rnorm(200)), val = "values",
  band = TRUE, title = "Normal Q-Q Plot")

DotPlot

dot_df <- data.frame(
  gene = rep(c("CD3D", "CD8A", "MS4A1", "CD68", "NKG7"), 4),
  cluster = rep(paste0("C", 1:4), each = 5),
  avg_expr = runif(20, -1, 2),
  pct_expr = runif(20, 0.1, 0.9)
)

DotPlot(dot_df, x = "gene", y = "cluster",
  size_by = "pct_expr", fill_by = "avg_expr",
  palette = "RdBu", title = "Marker Expression")

CorPlot

cor_df <- data.frame(
  BRCA1 = rnorm(80), TP53 = rnorm(80),
  tissue = sample(c("Normal", "Tumor"), 80, replace = TRUE)
)
cor_df$TP53 <- cor_df$BRCA1 * 0.7 + rnorm(80, sd = 0.5)

CorPlot(cor_df, x = "BRCA1", y = "TP53", group_by = "tissue",
  palette = "jco", add_smooth = TRUE, title = "Gene Correlation")

CorPairsPlot

CorPairsPlot(iris[, 1:4], palette = "Spectral",
  title = "Pairwise Correlations (Iris)")

LollipopPlot

lollipop_df <- data.frame(
  pathway = paste0("Pathway ", LETTERS[1:8]),
  score = c(3.2, 2.8, 2.5, 2.1, -1.5, -1.9, -2.3, -2.7)
)

LollipopPlot(lollipop_df, x = "score", y = "pathway",
  palette = "Set2", title = "Pathway Scores")

SplitBarPlot

split_bar <- data.frame(
  term = paste0("GO:", 1:10),
  nes = c(2.1, 1.8, 1.5, 1.3, 1.1, -1.2, -1.4, -1.7, -1.9, -2.3)
)

SplitBarPlot(split_bar, x = "nes", y = "term",
  palette = "RdBu", title = "NES Scores")

WaterfallPlot

wf_df <- data.frame(
  patient = paste0("Pt", 1:20),
  change = sort(runif(20, -80, 40), decreasing = TRUE)
)

WaterfallPlot(wf_df, x = "change", y = "patient",
  palette = "RdBu", title = "Tumor Size Change (%)")

PieChart

cell_comp <- data.frame(
  type = c("T cell", "B cell", "NK", "Monocyte", "Other"),
  count = c(35, 20, 15, 20, 10)
)

PieChart(cell_comp, x = "type", y = "count", palette = "Set2",
  title = "Cell Composition")

RingPlot

RingPlot(cell_comp, x = "type", y = "count", group_by = "type",
  palette = "Set2", title = "Ring Chart")

RadarPlot

radar_df <- data.frame(
  metric = rep(c("Proliferation", "Apoptosis", "Migration",
                 "Invasion", "Angiogenesis"), 2),
  value = c(8, 4, 7, 3, 6, 5, 8, 4, 9, 3),
  group = rep(c("Wild Type", "Mutant"), each = 5)
)

RadarPlot(radar_df, x = "metric", y = "value", group_by = "group",
  scale_y = "none", palette = "Set1", title = "Phenotype Comparison")

SpiderPlot

SpiderPlot(radar_df, x = "metric", y = "value", group_by = "group",
  scale_y = "none", palette = "lancet", title = "Spider Plot")

Enrichment & Pathway

EnrichMap

Requires igraph.

data(enrich_example)

EnrichMap(enrich_example, top_term = 20, layout = "fr",
  palette = "Spectral", title = "GO Enrichment Map")

EnrichNetwork

Requires igraph and ggraph.

data(enrich_multidb_example)

EnrichNetwork(enrich_multidb_example, top_term = 15, layout = "fr",
  palette = "Set3", title = "Enrichment Network")

GSEASummaryPlot

data(gsea_example)

GSEASummaryPlot(gsea_example, top_term = 15, palette = "RdBu",
  title = "GSEA Summary")

GSEAPlot

GSEAPlot(gsea_example, gs = gsea_example$ID[1],
  title = gsea_example$Description[1])

Single-Cell & Spatial

DimPlot

data(dim_example)

DimPlot(dim_example, dims = c("basis_1", "basis_2"),
  group_by = "clusters", palette = "igv",
  pt_size = 1.2, label = TRUE, label_insitu = TRUE,
  title = "UMAP Clustering")

FeatureDimPlot

dim_example$CD3D <- rnorm(nrow(dim_example))

FeatureDimPlot(dim_example, dims = c("basis_1", "basis_2"),
  features = "CD3D", palette = "viridis", pt_size = 1.2,
  title = "CD3D Expression")

VelocityPlot

Requires proxyC and Matrix.

embedding <- as.matrix(dim_example[, c("basis_1", "basis_2")])
v_embedding <- as.matrix(dim_example[, c("stochasticbasis_1", "stochasticbasis_2")])

VelocityPlot(embedding = embedding, v_embedding = v_embedding,
  plot_type = "grid", title = "RNA Velocity Field")

TrajectoryPlot

dim_example$pseudotime <- abs(rnorm(nrow(dim_example)))

TrajectoryPlot(dim_example, dims = c("basis_1", "basis_2"),
  pseudotime = "pseudotime", group_by = "clusters",
  palette = "viridis",
  title = "Pseudotime Trajectory")

StackedViolinPlot

marker_df <- data.frame(
  cluster = sample(c("T cell", "B cell", "NK", "Mono"), 200, replace = TRUE),
  CD3D = rnorm(200, 3), CD8A = rnorm(200, 2),
  MS4A1 = rnorm(200, 4), NKG7 = rnorm(200, 1)
)

StackedViolinPlot(marker_df,
  features = c("CD3D", "CD8A", "MS4A1", "NKG7"),
  group_by = "cluster", palette = "npg",
  title = "Marker Gene Expression")

ClustreePlot

Requires clustree.

ClustreePlot(data = seurat_obj, prefix = "RNA_snn_res.",
  title = "Clustering Resolution Tree")

SpatImagePlot

Requires spatial data objects. See ?SpatImagePlot for details.

SpatImagePlot(spe, feature = "gene_of_interest",
  palette = "viridis", title = "Spatial Expression")

SpatPointsPlot

SpatPointsPlot(spe, group_by = "celltype",
  palette = "igv", title = "Spatial Cell Types")

SpatShapesPlot

SpatShapesPlot(spe, group_by = "region",
  palette = "Set3", title = "Spatial Regions")

SpatMasksPlot

SpatMasksPlot(spe, group_by = "mask_type",
  palette = "Set2", title = "Spatial Masks")

Genomics

VolcanoPlot

real_genes <- c("TP53","EGFR","MYC","KRAS","BRCA1","CDK4","PTEN","RB1",
                "PIK3CA","AKT1","CD274","CTLA4","PDCD1","IDO1","VEGFA",
                "BRAF","JAK2","STAT3","NRAS","HAVCR2")
deg <- data.frame(
  gene = c(real_genes, paste0("Gene", 1:480)),
  log2FC = c(rnorm(10, 2.5, 0.8), rnorm(10, -2.5, 0.8), rnorm(480, 0, 0.8)),
  padj = c(runif(20, 1e-10, 1e-3), runif(480, 0.01, 1))
)

VolcanoPlot(deg, x = "log2FC", y = "padj", label_by = "gene",
  x_cutoff = 1, y_cutoff = 0.05, nlabel = 10,
  title = "Differential Expression")

ManhattanPlot

Requires ggmanh.

gwas <- data.frame(
  chr = rep(paste0("chr", 1:22), each = 500),
  pos = rep(1:500, 22) * 1e5,
  pvalue = runif(11000, 0, 1)
)
gwas$pvalue[sample(11000, 30)] <- runif(30, 0, 1e-8)

ManhattanPlot(gwas, chr_by = "chr", pos_by = "pos", pval_by = "pvalue",
  signif = 5e-8, title = "GWAS Results")

VennDiagram

Requires ggVennDiagram.

gene_sets <- list(
  "RNA-seq" = paste0("Gene", 1:100),
  "Proteomics" = paste0("Gene", 50:150),
  "Metabolomics" = paste0("Gene", 80:160)
)

VennDiagram(gene_sets, palette = "Set2", title = "Multi-Omics Overlap")

UpsetPlot

Requires ggupset.

pathways <- list(
  PI3K = paste0("Gene", sample(1:200, 50)),
  MAPK = paste0("Gene", sample(1:200, 60)),
  JAK_STAT = paste0("Gene", sample(1:200, 45)),
  Wnt = paste0("Gene", sample(1:200, 55))
)

UpsetPlot(pathways, palette = "Set2", title = "Pathway Intersection")

Clinical & Prediction

KMPlot

surv <- data.frame(
  time = c(rexp(80, 0.008), rexp(70, 0.015)),
  status = sample(0:1, 150, replace = TRUE, prob = c(0.35, 0.65)),
  risk = rep(c("Low", "High"), c(80, 70))
)

KMPlot(surv, time = "time", status = "status", group_by = "risk",
  palette = "jco", show_risk_table = TRUE, show_pval = TRUE,
  title = "Overall Survival")

CoxPlot

cox_df <- data.frame(
  time = rexp(200, 0.01),
  event = sample(0:1, 200, replace = TRUE, prob = c(0.3, 0.7)),
  age = rnorm(200, 60, 10),
  gender = sample(c("Male", "Female"), 200, replace = TRUE),
  stage = sample(c("I-II", "III-IV"), 200, replace = TRUE)
)

CoxPlot(cox_df, time = "time", event = "event",
  vars = c("age", "gender", "stage"),
  plot_type = "forest", palette = "nejm",
  title = "Cox Forest Plot")

ROCCurve

roc_df <- data.frame(
  truth = sample(0:1, 200, replace = TRUE),
  score = rnorm(200)
)
roc_df$score <- roc_df$score + roc_df$truth * 1.5

ROCCurve(roc_df, truth_by = "truth", score_by = "score",
  palette = "lancet", title = "ROC Analysis")

NomogramPlot

Requires rms.

Requires a pre-fitted rms model object.

library(rms)
dd <- datadist(df)
options(datadist = "dd")
fit <- cph(Surv(time, event) ~ age + grade + size, data = df, surv = TRUE)

NomogramPlot(fit, fun = function(x) 1 / (1 + exp(-x)),
  funlabel = "3-Year Survival",
  title = "Clinical Nomogram")

CalibrationPlot

cal_df <- data.frame(
  truth = sample(0:1, 500, replace = TRUE),
  predicted = runif(500)
)
cal_df$predicted <- ifelse(cal_df$truth == 1,
  pmin(cal_df$predicted + 0.2, 1),
  pmax(cal_df$predicted - 0.2, 0))

CalibrationPlot(cal_df, predicted = "predicted", observed = "truth",
  title = "Model Calibration")

DecisionCurvePlot

DecisionCurvePlot(cal_df, outcome = "truth", predictors = "predicted",
  title = "Decision Curve Analysis")

Networks & Relationships

Heatmap

Requires ComplexHeatmap and cluster.

genes <- c("CD3D","CD3E","CD8A","FOXP3","CD19","MS4A1","CD68","CSF1R","NCAM1","NKG7")
mat <- matrix(rnorm(120, 0, 1.5), nrow = 10,
  dimnames = list(genes, paste0("S", 1:12)))
mat[1:4, 1:4] <- mat[1:4, 1:4] + 2
mat[5:6, 5:8] <- mat[5:6, 5:8] + 2
mat[9:10, 9:12] <- mat[9:10, 9:12] + 2

Heatmap(mat, palette = "RdBu",
  show_row_names = TRUE, show_column_names = TRUE,
  title = "Immune Marker Heatmap")

ChordPlot

Requires circlize.

interactions <- data.frame(
  from = c("CD4 T", "CD8 T", "B cell", "NK", "Monocyte"),
  to = c("Fibroblast", "Endothelial", "Fibroblast", "Tumor", "Tumor"),
  weight = c(15, 20, 10, 25, 18)
)

ChordPlot(interactions, from = "from", to = "to", y = "weight",
  palette = "Set3", title = "Cell-Cell Interaction")

CircosPlot

Requires circlize.

CircosPlot(interactions, from = "from", to = "to", y = "weight",
  palette = "Paired", title = "Circos Plot")

SankeyPlot

Requires ggalluvial.

flow <- data.frame(
  stage1 = rep(c("Healthy", "At Risk", "Disease"), each = 3),
  stage2 = rep(c("Recovered", "Stable", "Progressed"), 3),
  count = c(40, 8, 2, 5, 20, 5, 2, 5, 13)
)

SankeyPlot(flow, x = c("stage1", "stage2"), y = "count",
  links_fill_by = "stage1", palette = "Set3", title = "Disease Flow")

AlluvialPlot

Requires ggalluvial.

AlluvialPlot(flow, x = c("stage1", "stage2"), y = "count",
  links_fill_by = "stage1", palette = "Paired",
  title = "Alluvial Plot")

Network

Requires igraph and ggraph.

edges <- data.frame(
  from = c("TP53", "EGFR", "MYC", "KRAS", "BRCA1", "PTEN"),
  to = c("MDM2", "ERBB2", "MAX", "BRAF", "RAD51", "AKT1"),
  score = c(0.9, 0.85, 0.8, 0.75, 0.7, 0.65)
)
nodes <- data.frame(
  name = unique(c(edges$from, edges$to)),
  type = c("Oncogene", "Oncogene", "Oncogene", "Oncogene",
           "TSG", "TSG", "TSG", "Oncogene", "Oncogene",
           "Oncogene", "TSG", "Oncogene")
)

Network(edges, nodes, link_weight_by = "score",
  node_fill_by = "type", layout = "fr",
  title = "Protein Interaction Network")

Specialized

DumbbellPlot

dumbbell_df <- data.frame(
  gene = paste0("Gene", 1:8),
  before = rnorm(8, 5, 1),
  after = rnorm(8, 8, 1.5)
)

DumbbellPlot(dumbbell_df, x_start = "before", x_end = "after", y = "gene",
  palette = "Set1",
  title = "Before vs After Treatment")

StreamGraph

Requires ggstream.

stream_df <- data.frame(
  year = rep(2015:2024, 4),
  count = abs(rnorm(40, 50, 20)),
  category = rep(c("Immunotherapy", "Targeted", "Chemo", "Radiation"), each = 10)
)

StreamGraph(stream_df, x = "year", y = "count", group_by = "category",
  palette = "Set2", title = "Treatment Trends")

TreemapPlot

Requires treemapify.

treemap_df <- data.frame(
  pathway = c("PI3K-Akt", "MAPK", "Wnt", "p53", "Cell Cycle",
              "Apoptosis", "JAK-STAT", "NF-kB"),
  gene_count = c(45, 38, 32, 28, 25, 22, 18, 15),
  category = c("Signaling", "Signaling", "Signaling", "TSG",
               "Cell Cycle", "Cell Death", "Signaling", "Signaling")
)

TreemapPlot(treemap_df, area = "gene_count", label = "pathway",
  fill = "category", palette = "Set2",
  title = "Pathway Gene Counts")

ParallelCoordPlot

ParallelCoordPlot(iris,
  columns = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"),
  group_by = "Species", palette = "Set1",
  title = "Iris Features")

WafflePlot

WafflePlot(cell_comp, x = "type", y = "count",
  palette = "Set2", title = "Cell Proportion (Waffle)")

TimelinePlot

timeline_df <- data.frame(
  event = c("Diagnosis", "Surgery", "Chemo Cycle 1", "Chemo Cycle 2",
            "Radiation", "Follow-up"),
  start = as.Date(c("2024-01-15", "2024-02-10", "2024-03-01",
                     "2024-04-15", "2024-06-01", "2024-09-01")),
  end = as.Date(c("2024-01-15", "2024-02-12", "2024-03-21",
                   "2024-05-05", "2024-07-15", "2024-12-01"))
)

TimelinePlot(timeline_df, start = "start", end = "end", label = "event",
  palette = "Set2", title = "Treatment Timeline")

DendrogramPlot

Requires ggdendro.

DendrogramPlot(mtcars[1:15, ],
  columns = c("mpg", "disp", "hp", "wt", "qsec"),
  k = 3, palette = "Set1",
  title = "Hierarchical Clustering")

SunburstPlot

Requires plotly. Interactive output.

sunburst_df <- data.frame(
  level1 = c("Immune", "Immune", "Immune", "Stromal", "Stromal"),
  level2 = c("T cell", "B cell", "NK", "Fibroblast", "Endothelial"),
  count = c(35, 20, 15, 20, 10)
)

SunburstPlot(sunburst_df, levels = c("level1", "level2"),
  values = "count", title = "Cell Hierarchy")

WordCloudPlot

Requires ggwordcloud.

terms <- data.frame(
  word = c("apoptosis", "proliferation", "migration", "invasion",
           "angiogenesis", "metastasis", "differentiation",
           "inflammation", "autophagy", "senescence"),
  score = c(8, 7, 6, 5, 9, 4, 7, 8, 3, 4)
)

WordCloudPlot(terms, word_by = "word", score_by = "score",
  palette = "Spectral", title = "Biological Processes")

RarefactionPlot

Requires iNEXT.

species <- list(
  Site_A = table(sample(1:50, 200, replace = TRUE, prob = 1/(1:50))),
  Site_B = table(sample(1:30, 200, replace = TRUE, prob = 1/(1:30)))
)

RarefactionPlot(species, palette = "Set1",
  title = "Species Rarefaction")

Earth & Environmental

ContourPlot

grid <- expand.grid(
  lon = seq(-3, 3, length.out = 50),
  lat = seq(-3, 3, length.out = 50)
)
grid$temp <- with(grid, sin(lon) * cos(lat) * exp(-(lon^2 + lat^2) / 8))

ContourPlot(grid, x = "lon", y = "lat", z = "temp",
  type = "filled", palette = "Spectral",
  title = "Temperature Field")

TernaryPlot

Requires ggtern.

ternary_df <- data.frame(
  sand = runif(50, 0.1, 0.8),
  silt = runif(50, 0.1, 0.5),
  clay = runif(50, 0.05, 0.4)
)
total <- rowSums(ternary_df)
ternary_df <- ternary_df / total
ternary_df$type <- sample(c("Alluvial", "Glacial"), 50, replace = TRUE)

TernaryPlot(ternary_df, x = "sand", y = "silt", z = "clay",
  group_by = "type", palette = "Set1",
  title = "Soil Composition")

PolarPlot

wind <- data.frame(
  direction = rep(seq(0, 350, by = 10), 3),
  speed = abs(rnorm(108, 10, 5)),
  season = rep(c("Spring", "Summer", "Autumn"), each = 36)
)

PolarPlot(wind, theta = "direction", r = "speed",
  group_by = "season", palette = "Set2",
  title = "Wind Pattern")

WindRosePlot

WindRosePlot(wind, theta = "direction", r = "speed",
  group_by = "season", palette = "Set1",
  title = "Wind Rose")

MapPlot

Requires rnaturalearth and sf.

MapPlot(region = "world", palette = "YlOrRd",
  title = "World Map")

Meta-Analysis & Agreement

ForestPlot

meta <- data.frame(
  study = c("Smith 2018", "Chen 2019", "Garcia 2020",
            "Kim 2021", "Patel 2022", "Overall"),
  or = c(1.32, 0.85, 1.51, 1.08, 0.92, 1.12),
  lower = c(0.95, 0.60, 1.05, 0.78, 0.65, 0.93),
  upper = c(1.84, 1.20, 2.17, 1.50, 1.30, 1.35),
  weight = c(22, 18, 15, 25, 20, NA),
  is_summary = c(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE)
)

ForestPlot(meta, estimate = "or", ci_lower = "lower", ci_upper = "upper",
  label = "study", weight = "weight", is_summary = "is_summary",
  null_value = 1, log_scale = TRUE,
  title = "Meta-Analysis Forest Plot")

FunnelPlot

funnel_df <- data.frame(
  effect = rnorm(20, 0.5, 0.3),
  se = runif(20, 0.05, 0.4)
)

FunnelPlot(funnel_df, estimate = "effect", se = "se",
  title = "Publication Bias Assessment")

BlandAltmanPlot

ba_df <- data.frame(
  method_A = rnorm(50, 100, 15),
  method_B = rnorm(50, 100, 15)
)
ba_df$method_B <- ba_df$method_A + rnorm(50, 2, 5)

BlandAltmanPlot(ba_df, method1 = "method_A", method2 = "method_B",
  title = "Method Agreement")

Ecology & Evolution

OrdinationPlot

Requires vegan.

Requires pre-computed ordination coordinates (e.g., from vegan::metaMDS).

library(vegan)
ord <- metaMDS(species_mat, k = 2, trace = 0)
ord_scores <- as.data.frame(scores(ord, display = "sites"))
ord_scores$habitat <- env$habitat

OrdinationPlot(ord_scores, x = "NMDS1", y = "NMDS2",
  group_by = "habitat", palette = "Set1",
  title = "NMDS Ordination")

PhyloTreePlot

Requires ape.

tree <- ape::rtree(15, tip.label = paste0("Species_", LETTERS[1:15]))

PhyloTreePlot(tree, palette = "Set2",
  title = "Phylogenetic Tree")

RankAbundancePlot

Requires vegan.


rank_df <- data.frame(
  species = paste0("Sp", 1:30),
  abundance = sort(rpois(30, 20), decreasing = TRUE),
  community = sample(c("Site A", "Site B"), 30, replace = TRUE)
)

RankAbundancePlot(rank_df, species = "species", abundance = "abundance",
  group_by = "community", palette = "Set1",
  title = "Rank-Abundance Curve")

Physics & Engineering

QuiverPlot

Requires metR.

field <- expand.grid(x = seq(-2, 2, 0.4), y = seq(-2, 2, 0.4))
field$u <- -field$y
field$v <- field$x

QuiverPlot(field, x = "x", y = "y", u = "u", v = "v",
  title = "Vector Field")

StreamlinePlot

Requires metR.

StreamlinePlot(field, x = "x", y = "y", u = "u", v = "v",
  title = "Streamline Plot")

3D & Interactive

Scatter3D

Requires plotly. Interactive output.

s3d <- data.frame(
  PC1 = rnorm(200), PC2 = rnorm(200), PC3 = rnorm(200),
  cluster = sample(c("A", "B", "C"), 200, replace = TRUE)
)

Scatter3D(s3d, x = "PC1", y = "PC2", z = "PC3",
  group_by = "cluster", palette = "Set1",
  title = "3D PCA")

Surface3D

Requires plotly. Interactive output.

surf <- expand.grid(x = seq(-3, 3, 0.2), y = seq(-3, 3, 0.2))
surf$z <- with(surf, sin(sqrt(x^2 + y^2)))

Surface3D(surf, x = "x", y = "y", z = "z",
  palette = "Spectral", title = "3D Surface")

ggforge_interactive

Converts any ggplot to an interactive plotly plot.

p <- BoxPlot(treat, x = "group", y = "response", palette = "lancet")
ggforge_interactive(p)

Machine Learning

ConfusionMatrixPlot

set.seed(42)
pred_df <- data.frame(
  actual = sample(c("Benign", "Malignant", "Normal"), 300,
    replace = TRUE, prob = c(0.4, 0.35, 0.25)),
  predicted = sample(c("Benign", "Malignant", "Normal"), 300,
    replace = TRUE, prob = c(0.38, 0.37, 0.25))
)
diag_idx <- sample(300, 200)
pred_df$predicted[diag_idx] <- pred_df$actual[diag_idx]

ConfusionMatrixPlot(pred_df, truth = "actual", predicted = "predicted",
  palette = "Blues", title = "Classification Results")

Session Info

sessionInfo()
#> R version 4.6.0 (2026-04-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
#>  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
#>  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
#> [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
#> 
#> time zone: UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] dplyr_1.2.1   ggforge_2.0.0 ggplot2_4.0.3
#> 
#> loaded via a namespace (and not attached):
#>   [1] RColorBrewer_1.1-3      ggdendro_0.2.0          jsonlite_2.0.0         
#>   [4] shape_1.4.6.1           magrittr_2.0.5          magick_2.9.1           
#>   [7] ggbeeswarm_0.7.3        farver_2.1.2            iNEXT_3.0.2            
#>  [10] rmarkdown_2.31          GlobalOptions_0.1.4     fs_2.1.0               
#>  [13] ragg_1.5.2              vctrs_0.7.3             Cairo_1.7-0            
#>  [16] memoise_2.0.1           rstatix_0.7.3           htmltools_0.5.9        
#>  [19] forcats_1.0.1           broom_1.0.12            gridGraphics_0.5-1     
#>  [22] Formula_1.2-5           sass_0.4.10             pracma_2.4.6           
#>  [25] bslib_0.10.0            htmlwidgets_1.6.4       desc_1.4.3             
#>  [28] plyr_1.8.9              zoo_1.8-15              cachem_1.1.0           
#>  [31] ggfittext_0.10.3        commonmark_2.0.0        igraph_2.3.0           
#>  [34] lifecycle_1.0.5         iterators_1.0.14        pkgconfig_2.0.3        
#>  [37] Matrix_1.7-5            R6_2.6.1                fastmap_1.2.0          
#>  [40] clue_0.3-68             digest_0.6.39           colorspace_2.1-2       
#>  [43] ggnewscale_0.5.2        patchwork_1.3.2         S4Vectors_0.49.3       
#>  [46] metR_0.18.3             textshaping_1.0.5       ggpubr_0.6.3           
#>  [49] labeling_0.4.3          abind_1.4-8             polyclip_1.10-7        
#>  [52] mgcv_1.9-4              compiler_4.6.0          withr_3.0.2            
#>  [55] doParallel_1.0.17       S7_0.2.2                backports_1.5.1        
#>  [58] carData_3.0-6           viridis_0.6.5           ggupset_0.4.1          
#>  [61] ggforce_0.5.0           ggsignif_0.6.4          MASS_7.3-65            
#>  [64] proxyC_0.5.2            rjson_0.2.23            caTools_1.18.3         
#>  [67] tools_4.6.0             vipor_0.4.7             otel_0.2.0             
#>  [70] beeswarm_0.4.0          ape_5.8-1               qqconf_1.3.2           
#>  [73] glue_1.8.1              treemapify_2.6.0        nlme_3.1-169           
#>  [76] gridtext_0.1.6          grid_4.6.0              checkmate_2.3.4        
#>  [79] cluster_2.1.8.2         reshape2_1.4.5          generics_0.1.4         
#>  [82] isoband_0.3.0           qqplotr_0.0.7           gtable_0.3.6           
#>  [85] tidyr_1.3.2             data.table_1.18.2.1     ggVennDiagram_1.5.7    
#>  [88] car_3.1-5               tidygraph_1.3.1         xml2_1.5.2             
#>  [91] BiocGenerics_0.57.1     markdown_2.0            ggrepel_0.9.8          
#>  [94] foreach_1.5.2           pillar_1.11.1           stringr_1.6.0          
#>  [97] robustbase_0.99-7       circlize_0.4.18         splines_4.6.0          
#> [100] tweenr_2.0.3            lattice_0.22-9          survival_3.8-6         
#> [103] tidyselect_1.2.1        ComplexHeatmap_2.27.1   knitr_1.51             
#> [106] gridExtra_2.3           litedown_0.9            IRanges_2.45.0         
#> [109] svglite_2.2.2           stats4_4.6.0            ggmanh_1.15.0          
#> [112] xfun_0.57               graphlayouts_1.2.3      plotROC_2.3.3          
#> [115] matrixStats_1.5.0       DEoptimR_1.1-4          stringi_1.8.7          
#> [118] yaml_2.3.12             evaluate_1.0.5          codetools_0.2-20       
#> [121] ggwordcloud_0.6.2       ggraph_2.2.2            twosamples_2.0.1       
#> [124] tibble_3.3.1            cli_3.6.6               pbmcapply_1.5.1        
#> [127] systemfonts_1.3.2       jquerylib_0.1.4         dichromat_2.0-0.1      
#> [130] Rcpp_1.1.1-1.1          png_0.1-9               parallel_4.6.0         
#> [133] ggstream_0.1.0          pkgdown_2.2.0           ggalluvial_0.12.6      
#> [136] opdisDownsampling_1.0.1 bitops_1.0-9            viridisLite_0.4.3      
#> [139] ggridges_0.5.7          scales_1.4.0            purrr_1.2.2            
#> [142] crayon_1.5.3            GetoptLong_1.1.1        rlang_1.2.0