{"spec_id":"smith-chart-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' smith-chart-basic: Smith Chart for RF/Impedance\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-05-20\n\nlibrary(ggplot2)\nlibrary(ragg)\n\n# --- Theme tokens -----------------------------------------------------------\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nIMPRINT   <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                 \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# --- Smith chart grid -------------------------------------------------------\ntheta <- seq(0, 2 * pi, length.out = 361)\n\n# Outer unit circle (|Gamma| = 1 boundary)\nouter_circle <- data.frame(x = cos(theta), y = sin(theta))\n\n# Constant resistance circles: r/(1+r) center, 1/(1+r) radius\nr_vals <- c(0, 0.2, 0.5, 1, 2, 5)\nr_circles <- do.call(rbind, lapply(r_vals, function(r) {\n  cx  <- r / (1 + r)\n  rad <- 1 / (1 + r)\n  data.frame(\n    x   = cx + rad * cos(theta),\n    y   = rad * sin(theta),\n    grp = paste0(\"r\", r)\n  )\n}))\n\n# Constant reactance arcs: center (1, 1/x), radius 1/|x|, clipped to unit disc\nx_vals <- c(0.2, 0.5, 1, 2, 5)\nx_arcs <- do.call(rbind, lapply(c(x_vals, -x_vals), function(x) {\n  cy  <- 1 / x\n  rad <- abs(1 / x)\n  pts_x <- 1 + rad * cos(theta)\n  pts_y <- cy  + rad * sin(theta)\n  inside <- (pts_x^2 + pts_y^2) <= 1.001\n  if (sum(inside) < 3) return(NULL)\n  data.frame(x = pts_x[inside], y = pts_y[inside], grp = paste0(\"x\", x))\n}))\n\n# VSWR = 2 reference circle (|Gamma| = 1/3)\nvswr_circle <- data.frame(\n  x = (1 / 3) * cos(theta),\n  y = (1 / 3) * sin(theta)\n)\n\n# --- Impedance locus: RLC antenna resonant near 2 GHz ----------------------\nset.seed(42)\nZ0        <- 50\nfreqs_ghz <- seq(1, 3, length.out = 80)\nomega     <- 2 * pi * freqs_ghz * 1e9\n\nR_ant <- 45\nL_ant <- 5e-9\nC_ant <- 1 / ((2 * pi * 2e9)^2 * L_ant)   # resonance exactly at 2 GHz\n\nzr <- R_ant / Z0\nzx <- (omega * L_ant - 1 / (omega * C_ant)) / Z0\n\n# Reflection coefficient Gamma = (z - 1) / (z + 1)\ndenom    <- (zr + 1)^2 + zx^2\ngamma_re <- ((zr - 1) * (zr + 1) + zx^2) / denom\ngamma_im <- 2 * zx / denom\n\nlocus <- data.frame(gre = gamma_re, gim = gamma_im, freq = freqs_ghz)\n\n# Labels at 1 GHz, 2 GHz, 3 GHz\nlabel_freqs <- c(1, 2, 3)\nlabel_idx   <- sapply(label_freqs, function(f) which.min(abs(locus$freq - f)))\nlabel_pts   <- locus[label_idx, ]\nlabel_pts$lbl <- c(\"1 GHz\", \"2 GHz\\n(res.)\", \"3 GHz\")\n\n# Directional arrow at 3 GHz end to show sweep direction\nn_loc <- nrow(locus)\ndx    <- locus$gre[n_loc] - locus$gre[n_loc - 5]\ndy    <- locus$gim[n_loc] - locus$gim[n_loc - 5]\nnorm  <- sqrt(dx^2 + dy^2)\narr_len <- 0.055\narr_x0  <- locus$gre[n_loc] - (dx / norm) * arr_len\narr_y0  <- locus$gim[n_loc] - (dy / norm) * arr_len\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot() +\n  # Grid: outer circle\n  geom_path(data = outer_circle, aes(x = x, y = y),\n            color = INK_SOFT, linewidth = 0.7) +\n  # Grid: constant-r circles\n  geom_path(data = r_circles, aes(x = x, y = y, group = grp),\n            color = INK_SOFT, linewidth = 0.22, alpha = 0.65) +\n  # Grid: constant-x arcs\n  geom_path(data = x_arcs, aes(x = x, y = y, group = grp),\n            color = INK_SOFT, linewidth = 0.22, alpha = 0.65) +\n  # Real axis\n  geom_segment(aes(x = -1, xend = 1, y = 0, yend = 0),\n               color = INK_SOFT, linewidth = 0.3) +\n  # VSWR = 2 reference circle\n  geom_path(data = vswr_circle, aes(x = x, y = y),\n            color = IMPRINT[3], linewidth = 0.5, linetype = \"dashed\") +\n  annotate(\"text\", x = -0.38, y = 0.06,\n           label = \"VSWR = 2\", size = 3.0, color = IMPRINT[3]) +\n  # Matched-load centre marker\n  geom_point(aes(x = 0, y = 0),\n             color = INK_SOFT, size = 1.8, shape = 3) +\n  # Impedance locus\n  geom_path(data = locus, aes(x = gre, y = gim),\n            color = IMPRINT[1], linewidth = 1.4) +\n  # Directional arrow at 3 GHz end showing sweep direction\n  annotate(\"segment\",\n           x = arr_x0, xend = locus$gre[n_loc],\n           y = arr_y0, yend = locus$gim[n_loc],\n           color = IMPRINT[1], linewidth = 1.4,\n           arrow = arrow(length = unit(0.1, \"inches\"), type = \"closed\")) +\n  # Start (1 GHz) and end (3 GHz) markers\n  geom_point(data = locus[1, ], aes(x = gre, y = gim),\n             color = IMPRINT[1], size = 3.5, shape = 16) +\n  geom_point(data = locus[nrow(locus), ], aes(x = gre, y = gim),\n             color = IMPRINT[2], size = 3.5, shape = 17) +\n  # Frequency labels\n  geom_text(data = label_pts, aes(x = gre, y = gim, label = lbl),\n            color = INK, size = 3.2, hjust = -0.15, lineheight = 0.9) +\n  # Resistance value labels along real axis\n  annotate(\"text\",\n           x = (r_vals - 1) / (r_vals + 1),\n           y = -0.06,\n           label = as.character(r_vals),\n           size = 3.0, color = INK_SOFT, vjust = 1) +\n  coord_fixed(xlim = c(-1.15, 1.35), ylim = c(-1.15, 1.15)) +\n  labs(\n    title = \"smith-chart-basic · r · ggplot2 · anyplot.ai\",\n    x     = \"Re(Γ)\",\n    y     = \"Im(Γ)\"\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_blank(),\n    panel.grid.minor = element_blank(),\n    panel.border     = 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 = 12),\n    axis.line        = element_blank()\n  )\n\n# --- Save -------------------------------------------------------------------\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 6,\n  height   = 6,\n  units    = \"in\",\n  dpi      = 400\n)\n"}