{"spec_id":"waveform-audio","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' waveform-audio: Audio Waveform Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-06-03\n\nlibrary(ggplot2)\nlibrary(ragg)\n\nset.seed(42)\n\n# Theme tokens\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nELEVATED_BG <- if (THEME == \"light\") \"#FFFDF6\" else \"#242420\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\n\n# Imprint palette — position 1 is always first series (brand green)\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\n\n# Data: synthetic seismogram with P-wave and S-wave arrivals\nn         <- 8000\ntime      <- seq(0, 2, length.out = n)\n\nnoise     <- rnorm(n, 0, 0.03)\n\np_arrival <- 0.4\np_env     <- ifelse(time >= p_arrival, exp(-3.0 * (time - p_arrival)), 0)\np_wave    <- 0.35 * p_env * sin(2 * pi * 8 * (time - p_arrival))\n\ns_arrival <- 0.8\ns_env     <- ifelse(time >= s_arrival, exp(-1.5 * (time - s_arrival)), 0)\ns_wave    <- 0.90 * s_env * sin(2 * pi * 4 * (time - s_arrival) + 0.3)\n\ncoda_start <- 1.3\ncoda_env   <- ifelse(time >= coda_start, exp(-2.0 * (time - coda_start)), 0)\ncoda_wave  <- 0.20 * coda_env * sin(2 * pi * 2 * (time - coda_start) + 0.8)\n\nraw       <- noise + p_wave + s_wave + coda_wave\namplitude <- raw / max(abs(raw)) * 0.92\n\ndf <- data.frame(time = time, amplitude = amplitude)\n\n# Title length-based font size (baseline 67 chars → size 12)\nplot_title <- paste0(\n  \"Seismic P-wave & S-wave Arrivals · \",\n  \"waveform-audio · r · ggplot2 · anyplot.ai\"\n)\ntitle_size <- max(8L, round(12 * 67 / nchar(plot_title)))\n\n# Plot\np <- ggplot(df, aes(x = time)) +\n  geom_ribbon(\n    aes(ymin = pmin(amplitude, 0), ymax = pmax(amplitude, 0)),\n    fill  = IMPRINT_PALETTE[1],\n    alpha = 0.78\n  ) +\n  geom_hline(yintercept = 0, color = INK_MUTED, linewidth = 0.4) +\n  geom_vline(xintercept = p_arrival, color = INK_SOFT,\n             linetype = \"dashed\", linewidth = 0.5) +\n  geom_vline(xintercept = s_arrival, color = INK_SOFT,\n             linetype = \"dotdash\", linewidth = 0.5) +\n  annotate(\"text\", x = p_arrival + 0.04, y = 0.90,\n           label = \"P\", color = INK, size = 3.5, hjust = 0, fontface = \"bold\") +\n  annotate(\"text\", x = s_arrival + 0.04, y = 0.90,\n           label = \"S\", color = INK, size = 3.5, hjust = 0, fontface = \"bold\") +\n  scale_x_continuous(\n    breaks = seq(0, 2, by = 0.25),\n    expand = expansion(mult = 0, add = 0.01)\n  ) +\n  scale_y_continuous(\n    limits = c(-1.05, 1.05),\n    breaks = c(-1, -0.5, 0, 0.5, 1)\n  ) +\n  labs(\n    x     = \"Time (s)\",\n    y     = \"Normalized Amplitude\",\n    title = plot_title\n  ) +\n  theme_minimal(base_size = 8) +\n  theme(\n    plot.background  = element_rect(fill = PAGE_BG, color = PAGE_BG),\n    panel.background = element_rect(fill = PAGE_BG, color = NA),\n    panel.grid.major = element_line(color = INK_MUTED, linewidth = 0.2),\n    panel.grid.minor = element_blank(),\n    panel.border     = element_blank(),\n    axis.line        = element_line(color = INK_SOFT, linewidth = 0.4),\n    axis.ticks       = element_blank(),\n    axis.title       = element_text(color = INK,      size = 10),\n    axis.text        = element_text(color = INK_SOFT, size = 8),\n    plot.title       = element_text(color = INK,      size = title_size,\n                                    margin = margin(b = 10)),\n    plot.margin      = margin(20, 24, 16, 16)\n  )\n\n# Save\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 8,\n  height   = 4.5,\n  units    = \"in\",\n  dpi      = 400\n)\n"}