{"spec_id":"surface-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' surface-basic: Basic 3D Surface Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 85/100 | Created: 2026-09-10\n# anyplot.ai\n# surface-basic: Basic 3D Surface Plot\n# Library: ggplot2 | R\n#\n# ggplot2 has no native 3D device (no wireframe/surface geom), so the surface\n# is rendered as a hand-projected mesh: rotate the (x, y, z) grid by a fixed\n# elevation/azimuth, project it onto the 2D canvas, then draw one\n# depth-sorted geom_polygon quad per grid cell (a painter's-algorithm mesh).\n# Height is encoded twice — via the visual elevation of each quad and via its\n# fill color — for redundant, colorblind-safe readability.\n\nlibrary(ggplot2)\nlibrary(dplyr)\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\"\n\n# --- Data: bimodal Gaussian response surface ----------------------------------\n# z = f(x, y) over a 45x45 grid, e.g. a yield surface from two process\n# settings — one dominant optimum plus a smaller secondary optimum.\nn <- 45\nx_vals <- seq(-4, 4, length.out = n)\ny_vals <- seq(-4, 4, length.out = n)\n\nX <- outer(y_vals, x_vals, function(y, x) x)\nY <- outer(y_vals, x_vals, function(y, x) y)\nZ <- exp(-((X - 1.5)^2 + (Y - 1.5)^2) / 4) +\n  0.6 * exp(-((X + 2)^2 + (Y + 2)^2) / 3)\n\n# --- 3D -> 2D isometric projection ---------------------------------------------\nelev <- 30 * pi / 180\nazim <- -35 * pi / 180\nz_scale <- 3 # visually amplify height relative to the x/y spatial extent\n\nX_rot <- X * cos(azim) - Y * sin(azim)\nY_rot <- X * sin(azim) + Y * cos(azim)\nZ_vis <- Z * z_scale\n\nX_proj <- X_rot\nY_proj <- Y_rot * sin(elev) + Z_vis * cos(elev)\n\n# One quad per grid cell: its 4 projected corners, mean height (fill) and\n# mean depth (paint order — farthest cells first so nearer ones draw on top).\nquads <- vector(\"list\", (n - 1) * (n - 1))\nk <- 1\nfor (i in 1:(n - 1)) {\n  for (j in 1:(n - 1)) {\n    quads[[k]] <- list(\n      x = c(X_proj[i, j], X_proj[i, j + 1], X_proj[i + 1, j + 1], X_proj[i + 1, j]),\n      y = c(Y_proj[i, j], Y_proj[i, j + 1], Y_proj[i + 1, j + 1], Y_proj[i + 1, j]),\n      z = mean(c(Z[i, j], Z[i, j + 1], Z[i + 1, j + 1], Z[i + 1, j])),\n      depth = mean(c(Y_rot[i, j], Y_rot[i, j + 1], Y_rot[i + 1, j + 1], Y_rot[i + 1, j]))\n    )\n    k <- k + 1\n  }\n}\nquads <- quads[order(-vapply(quads, function(q) q$depth, numeric(1)))]\n\nmesh_df <- bind_rows(lapply(seq_along(quads), function(g) {\n  q <- quads[[g]]\n  tibble::tibble(x = q$x, y = q$y, z = q$z, group = g)\n}))\n\n# --- Plot ----------------------------------------------------------------------\np <- ggplot(mesh_df, aes(x = x, y = y, group = group, fill = z)) +\n  geom_polygon(color = adjustcolor(INK_SOFT, alpha.f = 0.45), linewidth = 0.07, alpha = 0.95) +\n  scale_fill_gradient(low = \"#009E73\", high = \"#4467A3\", name = \"Height (z)\") +\n  coord_fixed() +\n  labs(\n    title = \"surface-basic · r · ggplot2 · anyplot.ai\",\n    subtitle = \"Isometric projection · elevation 30° · azimuth -35° · vertical axis blends Y-depth and Z-height\",\n    x = \"X (projected)\",\n    y = \"Y-depth + Height (z), projected\"\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 = adjustcolor(INK, alpha.f = 0.2), linewidth = 0.2),\n    panel.grid.minor = element_blank(),\n    axis.ticks = element_blank(),\n    axis.line = 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    plot.subtitle = element_text(color = INK_SOFT, size = 8),\n    legend.background = element_rect(fill = ELEVATED_BG, color = INK_SOFT),\n    legend.text = element_text(color = INK_SOFT, size = 8),\n    legend.title = element_text(color = INK, size = 10)\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"}