An NMR spectrum plots signal intensity versus chemical shift (in ppm) to reveal the electronic environment of atomic nuclei in a molecule. It is the primary analytical tool in organic chemistry for determining molecular structure, with peak positions indicating functional groups and splitting patterns (multiplets) revealing connectivity between neighboring atoms. The x-axis is conventionally reversed (high ppm on the left) and peaks appear as sharp signals rising from a baseline.

#' anyplot.ai
#' spectrum-nmr: NMR Spectrum (Nuclear Magnetic Resonance)
#' Library: ggplot2 3.5.1 | R 4.4.1
#' Quality: 89/100 | Created: 2026-06-03
library(ggplot2)
library(ragg)
set.seed(42)
# Theme tokens (Imprint palette, theme-adaptive chrome)
THEME <- Sys.getenv("ANYPLOT_THEME", "light")
PAGE_BG <- if (THEME == "light") "#FAF8F1" else "#1A1A17"
ELEVATED_BG <- if (THEME == "light") "#FFFDF6" else "#242420"
INK <- if (THEME == "light") "#1A1A17" else "#F0EFE8"
INK_SOFT <- if (THEME == "light") "#4A4A44" else "#B8B7B0"
INK_MUTED <- if (THEME == "light") "#6B6A63" else "#A8A79F"
IMPRINT_PALETTE <- c("#009E73", "#C475FD", "#4467A3", "#BD8233",
"#AE3030", "#2ABCCD", "#954477", "#99B314")
# Simulated 1H NMR spectrum of ethanol (CH3CH2OH) at 400 MHz
ppm <- seq(5.2, -0.5, length.out = 7000)
# J-coupling constant: 7 Hz at 400 MHz = 0.0175 ppm
J <- 0.0175
hw_sharp <- 0.004 # sharp peak half-width (ppm)
hw_broad <- 0.030 # broad OH singlet half-width (ppm)
# CH3 triplet at 1.17 ppm (3H): 1:2:1 intensity ratio
ch3_ppm <- c(1.17 - J, 1.17, 1.17 + J)
ch3_h <- c(0.55, 1.10, 0.55)
# CH2 quartet at 3.69 ppm (2H): 1:3:3:1 intensity ratio
ch2_ppm <- c(3.69 - 1.5 * J, 3.69 - 0.5 * J, 3.69 + 0.5 * J, 3.69 + 1.5 * J)
ch2_h <- c(0.22, 0.65, 0.65, 0.22)
# OH singlet at 2.60 ppm (1H, broad) + TMS reference at 0.00 ppm
intensity <- numeric(length(ppm))
for (i in seq_along(ch3_ppm)) {
intensity <- intensity + ch3_h[i] * (hw_sharp / 2)^2 / ((ppm - ch3_ppm[i])^2 + (hw_sharp / 2)^2)
}
for (i in seq_along(ch2_ppm)) {
intensity <- intensity + ch2_h[i] * (hw_sharp / 2)^2 / ((ppm - ch2_ppm[i])^2 + (hw_sharp / 2)^2)
}
intensity <- intensity + 0.35 * (hw_broad / 2)^2 / ((ppm - 2.60)^2 + (hw_broad / 2)^2)
intensity <- intensity + 0.40 * (hw_sharp / 2)^2 / ((ppm - 0.00)^2 + (hw_sharp / 2)^2)
intensity <- intensity + rnorm(length(ppm), 0, 0.003)
intensity <- pmax(intensity, 0)
df <- data.frame(ppm = ppm, intensity = intensity)
# Title length check — only shrink when > 67 chars baseline
plot_title <- "Ethanol ¹H NMR · spectrum-nmr · r · ggplot2 · anyplot.ai"
title_n <- nchar(plot_title)
title_size <- max(8, round(12 * min(1.0, 67 / title_n)))
p <- ggplot(df, aes(x = ppm, y = intensity)) +
geom_hline(yintercept = 0, color = INK_SOFT, linewidth = 0.35) +
geom_line(color = IMPRINT_PALETTE[1], linewidth = 0.65) +
annotate("label", x = 1.17, y = 1.33,
label = "CH₃ 1.17 ppm\ntriplet (3H)",
color = INK_MUTED, fill = PAGE_BG, label.size = 0,
size = 3.0, hjust = 0.5, lineheight = 0.9) +
annotate("label", x = 3.69, y = 0.87,
label = "CH₂ 3.69 ppm\nquartet (2H)",
color = INK_MUTED, fill = PAGE_BG, label.size = 0,
size = 3.0, hjust = 0.5, lineheight = 0.9) +
annotate("label", x = 2.60, y = 0.59,
label = "OH 2.60 ppm\nsinglet (1H)",
color = INK_MUTED, fill = PAGE_BG, label.size = 0,
size = 3.0, hjust = 0.5, lineheight = 0.9) +
annotate("label", x = 0.00, y = 0.64,
label = "TMS 0.00 ppm\n(reference)",
color = INK_MUTED, fill = PAGE_BG, label.size = 0,
size = 3.0, hjust = 0.5, lineheight = 0.9) +
scale_x_reverse(breaks = seq(5, 0, by = -1)) +
scale_y_continuous(
limits = c(-0.05, 1.75),
breaks = c(0, 0.5, 1.0),
expand = c(0, 0)
) +
labs(
title = plot_title,
x = "Chemical Shift (δ, ppm)",
y = "Intensity (a.u.)"
) +
theme_minimal(base_size = 8) +
theme(
plot.background = element_rect(fill = PAGE_BG, color = PAGE_BG),
panel.background = element_rect(fill = PAGE_BG, color = NA),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
axis.line.x = element_line(color = INK_SOFT, linewidth = 0.5),
axis.line.y = element_line(color = INK_SOFT, linewidth = 0.5),
axis.title = element_text(color = INK, size = 10),
axis.text = element_text(color = INK_SOFT, size = 8),
axis.text.y = element_text(color = INK_MUTED, size = 7),
plot.title = element_text(color = INK, size = title_size, face = "bold"),
plot.margin = margin(20, 30, 15, 20, unit = "pt")
)
ggsave(
filename = sprintf("plot-%s.png", THEME),
plot = p,
device = ragg::agg_png,
width = 8,
height = 4.5,
units = "in",
dpi = 400
)
Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/spectrum-nmr/ggplot2/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.
{
"spec_id": "spectrum-nmr",
"language": "r",
"library": "ggplot2",
"page": "https://anyplot.ai/spectrum-nmr/r/ggplot2",
"hub": "https://anyplot.ai/spectrum-nmr",
"code_json": "https://api.anyplot.ai/specs/spectrum-nmr/ggplot2/code",
"spec_json": "https://api.anyplot.ai/specs/spectrum-nmr",
"render_light_png": "https://storage.googleapis.com/anyplot-images/plots/spectrum-nmr/r/ggplot2/plot-light.png",
"render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/spectrum-nmr/r/ggplot2/plot-dark.png",
"quality_score": 89.0,
"license": "MIT",
"guide": "https://anyplot.ai/llms.txt"
}Part of NMR Spectrum (Nuclear Magnetic Resonance) on anyplot.ai.