plot_tm: Compare Tm distributions across groups

View source: R/plot_tm.R

plot_tmR Documentation

Compare Tm distributions across groups

Description

Visualise how melting temperature (and optionally other numeric metadata) differs between region classes such as peak vs. non-peak, mutant vs. wild-type, or any categorical annotation stored in a GRanges object. Designed as the visual companion to compare_groups().

Usage

plot_tm(
  gr,
  group,
  value = "Tm",
  plot_type = c("box", "violin", "rank", "density", "ridgeline", "ecdf", "sina"),
  color_palette = c("viridis", "magma", "plasma", "inferno", "cividis"),
  show_points = FALSE,
  point_size = 1,
  point_alpha = 0.3,
  notch = FALSE,
  add_mean = FALSE,
  facet_by = NULL,
  show_pvalue = FALSE,
  p_adjust_method = "BH",
  title = NULL,
  ylab = "Tm (°C)",
  xlab = NULL,
  show_legend = TRUE
)

Arguments

gr

A GRanges object containing at least a numeric Tm metadata column and a categorical grouping column.

group

Character. Name of the metadata column that defines the groups to compare (e.g. "in_mutH").

value

Character. Numeric metadata column to plot on the y-axis. Default: "Tm". Can be any numeric column such as "GC".

plot_type

Character. Visualisation style:

"box"

Box plot (default). Shows median, quartiles, and outliers per group.

"violin"

Violin plot with embedded box plot. Shows the full density shape of each group.

"rank"

Rank plot. All values sorted ascending on the x-axis, coloured by group. Visually demonstrates whether one group clusters at higher or lower values — a graphical Wilcoxon test.

"density"

Overlaid density curves per group.

"ridgeline"

Stacked density ridges per group (requires ggridges).

"ecdf"

Empirical cumulative distribution function per group. Useful for visualising distributional shifts.

"sina"

Sina (strip) plot — jittered points shaped by the local density, combining the resolution of a strip chart with the density information of a violin plot.

color_palette

Character. Viridis palette for group colours: "viridis" (default), "magma", "plasma", "inferno", or "cividis".

show_points

Logical. Overlay jittered points on box / violin plots. Default: FALSE. Ignored for rank, density, ridgeline, ecdf.

point_size

Numeric. Point size. Default: 1.

point_alpha

Numeric in [0, 1]. Point transparency. Default: 0.3.

notch

Logical. Draw notched box plots (approximate 95% CI for median). Default: FALSE.

add_mean

Logical. Add a diamond marker at the group mean on box / violin plots. Default: FALSE.

facet_by

Character or NULL. Optional metadata column to facet the plot by (e.g. "chromosome"). Default: NULL.

show_pvalue

Logical. Annotate the plot with Wilcoxon rank-sum test p-values. For two groups a single p-value is shown; for three or more groups all pairwise comparisons are displayed. P-values are placed as bracket annotations on box / violin / sina plots, or as a subtitle on density / ecdf / rank / ridgeline plots. Default: FALSE.

p_adjust_method

Character. Method for p-value adjustment when there are more than two groups (passed to p.adjust). Default: "BH" (Benjamini-Hochberg).

title

Character or NULL. Plot title. A sensible default is generated when NULL.

ylab

Character. Y-axis label. Default: "Tm (\u00B0C)".

xlab

Character. X-axis label. Default: group column name for box/violin/sina, "Rank" for rank, value for density/ecdf.

show_legend

Logical. Show colour legend. Default: TRUE.

Details

The function pairs naturally with integrate_granges() and compare_groups():

  1. Use integrate_granges() to annotate Tm windows with feature overlaps (e.g. ChIP-seq peaks, repeat classes).

  2. Use compare_groups() for the statistical test.

  3. Use plot_tm() to visualise the distributional difference.

Value

A ggplot object.

Examples

## Not run: 
library(GenomicRanges)
data(ecoli_rep_hotspots)

library("BSgenome.Ecoli.NCBI.ASM584v2")
genome_name <- "BSgenome.Ecoli.NCBI.ASM584v2"
chr_name    <- "U00096.3"
genome <- get(genome_name, envir = asNamespace(genome_name))
chr_length  <- length(genome[[chr_name]])
genome_name="BSgenome.Ecoli.NCBI.ASM584v2"
bins_gc <- make_genomiccoord(
  bsgenome    = genome_name,
  chromosomes = chr_name,
  window      = 200L,
  slide       = 200L,
  start       = 1,
  end         = chr_length,
  strand      = "+"
)
input_new <- list(pkg_name = genome_name, seq = bins_gc)
gr_batch <- to_genomic_ranges_fast(input_new)
tm_ASM584v2 <- tm_calculate(
  gr_batch,
  method   = "tm_nn"
)
gr_tm <- tm_ASM584v2$gr

# Annotate with MutL-AR peak membership
mutH_peaks <- GRanges(
  seqnames = ecoli_rep_hotspots$all_peaks_IP_mutH$chr,
  ranges   = IRanges(start = ecoli_rep_hotspots$all_peaks_IP_mutH$start,
                     end   = ecoli_rep_hotspots$all_peaks_IP_mutH$end)
)
mutH_peaks$peak_id <- paste0("mutH_", seq_along(mutH_peaks))
gr_annot <- integrate_granges(
  gr_tm = gr_tm, gr_features = mutH_peaks,
  strategy = "overlap", feature_cols = "peak_id",
  keep_unmatched = TRUE
)
gr_annot$in_mutH <- ifelse(is.na(gr_annot$peak_id), "non_peak", "peak")

# Box plot — peak vs non-peak Tm
plot_tm(gr_annot, group = "in_mutH")

# Box plot with Wilcoxon p-value bracket
plot_tm(gr_annot, group = "in_mutH", show_pvalue = TRUE)

# Violin plot with p-value and jittered points
plot_tm(gr_annot, group = "in_mutH", plot_type = "violin",
        show_points = TRUE, show_pvalue = TRUE)

# Rank plot — visual Wilcoxon test with p-value subtitle
plot_tm(gr_annot, group = "in_mutH", plot_type = "rank",
        show_pvalue = TRUE)

# Density overlay with p-value
plot_tm(gr_annot, group = "in_mutH", plot_type = "density",
        show_pvalue = TRUE)

# ECDF — cumulative distribution comparison
plot_tm(gr_annot, group = "in_mutH", plot_type = "ecdf",
        show_pvalue = TRUE)

# Compare GC content instead of Tm
plot_tm(gr_annot, group = "in_mutH", value = "GC", ylab = "GC content",
        show_pvalue = TRUE)

# Notched box plot with mean markers and p-value
plot_tm(gr_annot, group = "in_mutH", notch = TRUE, add_mean = TRUE,
        show_pvalue = TRUE)

## End(Not run)


TmCalculator documentation built on Aug. 28, 2026, 5:09 p.m.