Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I align peak labels?

Tags:

r

ggplot2

I am attempting to graph data with peaks in R. The graphing itself has progressed well, but I've run into issues with labelling the relevant peaks. My current labelling system, detailed below, shifts the peak labels oddly to the side and results in lines crossing each other. Is there a way to align labels with the peaks themselves, or otherwise organize them aesthetically?

The following code reproduces my problem, using this data.

library(ggplot2)
library(ggpmisc)
library(ggrepel)

x=read.csv("data.csv")

colnames(x)=c("wv", "abs")

ggplot(x, aes(x=wv, y=abs)) + geom_line() + xlab(bquote('Wavenumbers ('~cm^-1*')')) + ylab("Absorbance (A.U.)") + scale_x_reverse(limits=c(2275,1975), expand=c(0,0)) + ylim(-0.01,0.29) + stat_peaks(colour = "black", span = 11,  geom ="text_repel", direction = "y", angle = 90, ignore_threshold = 0.09, size = 3, x.label.fmt = "%.2f", vjust = 1, hjust = 0, segment.color = "red") + ggtitle("FTIR - Carbon Monoxide, Fundamentals")

Problematic Labels

like image 288
Alexandra Avatar asked Mar 11 '26 14:03

Alexandra


2 Answers

hjust = 0.5 should work better. Using hjust = 0 aligns your labels a little to the right, with the top edge of the text aligned with the middle of each peak.

Here's a reproducible example that doesn't rely on external data that might not remain available at that link. (See bottom for application to the OP dataset.)

library(ggpmisc)
library(ggrepel)
library(ggplot2)
x <- data.frame(wv = 2300:2000)
x$abs = abs(cos(x$wv/50) * sin(x$wv/2))
ggplot(x, aes(wv, abs)) +
  geom_line() +
  stat_peaks(colour = "black", span = 11,  
             geom ="text_repel", direction = "y", 
             angle = 90, ignore_threshold = 0.09, 
             size = 3, x.label.fmt = "%.2f", 
             vjust = 1, hjust = 0.5, segment.color = "red") +
  scale_x_reverse(limits = c(2300,2000))

enter image description here

Here's loading the original data:

library(readr)
x <- read_csv("~/Downloads/CO-FTIR Spectrum-1800 mTorr-2021.csv")
colnames(x)=c("wv", "abs")

Here with these parameters added:

box.padding = 0.0, nudge_y = 0.02,

enter image description here

like image 175
Jon Spring Avatar answered Mar 13 '26 10:03

Jon Spring


Here's an approach using ggplot2::stage and the built-in segment and text geometries:

library(ggplot2)
library(ggpmisc)

id <- "1S345TaPqANriDPLN6H_PyunuM1QHi485"
x <- read.csv(sprintf("https://docs.google.com/uc?id=%s&export=download", id))
colnames(x)=c("wv", "abs")

ggplot(x, aes(x=wv, y=abs)) + geom_line() +
  xlab(bquote('Wavenumbers ('~cm^-1*')')) + ylab("Absorbance (A.U.)") + ggtitle("FTIR - Carbon Monoxide, Fundamentals") + ylim(-0.01,0.29) +
  stat_peaks(mapping = aes(x = stage(wv, after_scale = x + 0.25)),
             geom ="text", colour = "black", span = 11, angle = 90,
             ignore_threshold = 0.09, size = 2.5, x.label.fmt = "%.2f",
             vjust = 0.5, hjust = -1) +
  stat_peaks(mapping = aes(xend = stage(wv, after_scale = x + 0.25),
                           y = stage(abs, after_stat = y + 0.005),
                           yend = after_stat(y + 0.02)),
             geom ="segment", lwd = 0.5, colour = "red", 
             span = 11, ignore_threshold = 0.09) +
  scale_x_reverse(expand=c(0,0), limits = c(2275,1975))

enter image description here

From help(stat_peaks) we can see that x and y stats are calculated for each peak. Typically we can access these stats with after_stat, but because you've also transformed the x-axis, you need to actually access that stat after it's been scaled.

In the first layer of stat_peaks we use stage(wv, after_scale = x + 0.25) to add a bit of nudge to the x coordinate. In the second call of stat_peaks we set the geometry to segment. Segment requires an xend and yend. We can use stage and after_stat to again add a nudge and line length.

like image 39
Ian Campbell Avatar answered Mar 13 '26 10:03

Ian Campbell