{"spec_id":"eye-diagram-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' eye-diagram-basic: Signal Integrity Eye Diagram\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 92/100 | Created: 2026-06-18\n\nlibrary(ggplot2)\nlibrary(ragg)\n\nset.seed(42)\n\n# Theme tokens (Imprint palette, theme-adaptive chrome)\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# NRZ simulation parameters\nn_bits       <- 600\nsamp_per_ui  <- 100\nnoise_sigma  <- 0.05   # Gaussian noise (5% of amplitude)\njitter_sigma <- 0.03   # Timing jitter std dev (3% of UI)\nsigmoid_k    <- 18     # Bandwidth-limiting sharpness\n\n# Random bit stream and per-transition jitter\nbits       <- sample(c(0L, 1L), n_bits, replace = TRUE)\njitter_raw <- rnorm(n_bits - 1L, 0.0, jitter_sigma)\nj_arr      <- c(0.0, jitter_raw)\n\n# Vectorized waveform generation with sigmoid transitions and jitter\nn_total   <- n_bits * samp_per_ui\nt_all     <- (seq_len(n_total) - 0.5) / samp_per_ui\nbit_idx   <- pmin(as.integer(floor(t_all)) + 1L, n_bits)\nt_within  <- t_all - floor(t_all)\nprev_bits <- c(bits[1L], bits[-n_bits])\nprev_at_t <- prev_bits[bit_idx]\ncurr_at_t <- bits[bit_idx]\nj_vals    <- j_arr[bit_idx]\n\ndt    <- (t_within - j_vals) * sigmoid_k\nsig_s <- 1.0 / (1.0 + exp(-dt))\nsame  <- (prev_at_t == curr_at_t)\nrise  <- (!same & curr_at_t > prev_at_t)\nv_sig <- ifelse(same, curr_at_t * 1.0, ifelse(rise, sig_s, 1.0 - sig_s))\nv_sig <- v_sig + rnorm(n_total, 0.0, noise_sigma)\n\n# Fold waveform into 2-UI eye traces (start at each bit boundary)\nwindow_sz <- 2L * samp_per_ui\nn_traces  <- n_bits - 2L\nt_axis    <- seq(0.0, 2.0, length.out = window_sz + 1L)[-1L]\nstart_idx <- (seq_len(n_traces) - 1L) * samp_per_ui + 1L\nsamp_mat  <- outer(0L:(window_sz - 1L), start_idx, `+`)\neye_df    <- data.frame(\n    time    = rep(t_axis, n_traces),\n    voltage = v_sig[as.vector(samp_mat)]\n)\n\n# Pre-compute 2D density grid: vectorised findInterval + tabulate → geom_raster\nn_bins_x <- 200\nn_bins_y <- 150\nt_breaks <- seq(0.0,  2.0,  length.out = n_bins_x + 1L)\nv_breaks <- seq(-0.18, 1.18, length.out = n_bins_y + 1L)\nt_mids   <- (t_breaks[-1L] + t_breaks[-length(t_breaks)]) / 2\nv_mids   <- (v_breaks[-1L] + v_breaks[-length(v_breaks)]) / 2\n\nt_bin_idx <- pmin(pmax(findInterval(eye_df$time,    t_breaks), 1L), n_bins_x)\nv_bin_idx <- pmin(pmax(findInterval(eye_df$voltage, v_breaks), 1L), n_bins_y)\nlin_idx   <- (t_bin_idx - 1L) * n_bins_y + v_bin_idx\ncount_vec <- tabulate(lin_idx, nbins = n_bins_x * n_bins_y)\n\n# Full rectangular grid required for geom_raster interpolation;\n# zero-count cells → NA so scale maps them to PAGE_BG (eye opening shows through)\nraster_df <- data.frame(\n    time    = rep(t_mids, each = n_bins_y),\n    voltage = rep(v_mids, times = n_bins_x),\n    density = ifelse(count_vec > 0L, sqrt(count_vec), NA_real_)\n)\n\n# Estimate eye opening at optimal sampling point (t ≈ 1.5 UI, centre of second eye)\nat_center  <- eye_df$time >= 1.40 & eye_df$time <= 1.60\ncenter_v   <- eye_df$voltage[at_center]\nlow_level  <- center_v[center_v < 0.5]\nhigh_level <- center_v[center_v > 0.5]\neye_lo     <- if (length(low_level)  > 10L) as.numeric(quantile(low_level,  0.995)) else 0.15\neye_hi     <- if (length(high_level) > 10L) as.numeric(quantile(high_level, 0.005)) else 0.85\neye_ht_mv  <- max(0L, round((eye_hi - eye_lo) * 1000L))\n\nplot_title <- \"eye-diagram-basic · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(raster_df, aes(x = time, y = voltage)) +\n    # Smooth density heatmap via bilinear-interpolated raster (publication-quality)\n    geom_raster(aes(fill = density), interpolate = TRUE) +\n    # Optimal sampling point (t=0.5, centre of first eye) — vertical dashed reference\n    annotate(\"segment\", x = 0.5, xend = 0.5,\n             y = min(v_breaks), yend = max(v_breaks),\n             color = INK_MUTED, linewidth = 0.45, linetype = \"dashed\") +\n    # Eye height bracket: bracket bar + serif ticks + measurement label\n    annotate(\"segment\", x = 1.72, xend = 1.72, y = eye_lo, yend = eye_hi,\n             color = \"#AE3030\", linewidth = 0.6) +\n    annotate(\"segment\", x = 1.70, xend = 1.74, y = eye_lo, yend = eye_lo,\n             color = \"#AE3030\", linewidth = 0.5) +\n    annotate(\"segment\", x = 1.70, xend = 1.74, y = eye_hi, yend = eye_hi,\n             color = \"#AE3030\", linewidth = 0.5) +\n    annotate(\"text\", x = 1.76, y = (eye_lo + eye_hi) / 2,\n             label = paste0(eye_ht_mv, \" mV\"),\n             color = \"#AE3030\", size = 2.5, hjust = 0.0, fontface = \"bold\") +\n    scale_fill_gradient(\n        name     = \"Density\",\n        low      = \"#009E73\",\n        high     = \"#4467A3\",\n        na.value = PAGE_BG,\n        guide    = guide_colorbar(barwidth = 0.5, barheight = 8)\n    ) +\n    scale_x_continuous(\n        name   = \"Time (UI)\",\n        breaks = c(0.0, 0.5, 1.0, 1.5, 2.0),\n        expand = c(0.04, 0.0)\n    ) +\n    scale_y_continuous(\n        name   = \"Voltage (V)\",\n        breaks = c(0.0, 0.25, 0.5, 0.75, 1.0),\n        expand = c(0.06, 0.0)\n    ) +\n    coord_cartesian(clip = \"off\") +\n    labs(title = plot_title) +\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.15),\n        panel.grid.minor  = element_blank(),\n        panel.border      = element_rect(fill = NA,          color = INK_SOFT, linewidth = 0.4),\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 = 12, hjust = 0.0),\n        legend.background = element_rect(fill = ELEVATED_BG, color = INK_SOFT, linewidth = 0.3),\n        legend.text       = element_text(color = INK_SOFT,   size = 8),\n        legend.title      = element_text(color = INK,        size = 9),\n        legend.position   = \"right\",\n        plot.margin       = margin(12, 20, 12, 12, \"pt\")\n    )\n\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"}