{"spec_id":"venn-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' venn-basic: Venn Diagram\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-09-09\n\nlibrary(ggplot2)\nlibrary(dplyr)\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_PALETTE <- c(\n  \"#009E73\", # 1 - Python\n  \"#C475FD\", # 2 - SQL\n  \"#4467A3\"  # 3 - R\n)\n\n# --- Data: skill overlap across job candidates -------------------------------\npython_total <- 120\nsql_total    <- 95\nr_total      <- 70\npython_sql   <- 40\npython_r     <- 25\nsql_r        <- 30\nall_three    <- 12\n\npython_only     <- python_total - python_sql - python_r + all_three\nsql_only        <- sql_total - python_sql - sql_r + all_three\nr_only          <- r_total - python_r - sql_r + all_three\npython_sql_only <- python_sql - all_three\npython_r_only   <- python_r - all_three\nsql_r_only      <- sql_r - all_three\n\ncircle_points <- function(cx, cy, radius, n = 200) {\n  theta <- seq(0, 2 * pi, length.out = n)\n  tibble::tibble(x = cx + radius * cos(theta), y = cy + radius * sin(theta))\n}\n\n# Radii scaled by sqrt(set_size) relative to the largest set, so circle area\n# is proportional to set size while the three-circle triangular layout stays intact.\nradius_python <- 2.2\nradius_sql    <- radius_python * sqrt(sql_total / python_total)\nradius_r      <- radius_python * sqrt(r_total / python_total)\n\ncenter_python <- c(0, 1.27)\ncenter_sql    <- c(-1.10, -0.635)\ncenter_r      <- c(1.10, -0.635)\n\ncircles <- bind_rows(\n  circle_points(center_python[1], center_python[2], radius_python) |> mutate(set = \"Python\"),\n  circle_points(center_sql[1], center_sql[2], radius_sql) |> mutate(set = \"SQL\"),\n  circle_points(center_r[1], center_r[2], radius_r) |> mutate(set = \"R\")\n) |> mutate(set = factor(set, levels = c(\"Python\", \"SQL\", \"R\")))\n\ntotal_n <- python_only + sql_only + r_only + python_sql_only + python_r_only + sql_r_only + all_three\n\nregion_counts <- tibble::tibble(\n  x = c(0, -1.81, 1.71, -0.88, 0.86, 0, 0),\n  y = c(2.0, -1.27, -1.18, 0.87, 0.83, -1.06, 0.04),\n  count = c(python_only, sql_only, r_only, python_sql_only, python_r_only, sql_r_only, all_three),\n  focal = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE)\n) |> mutate(pct_label = paste0(round(100 * count / total_n), \"%\"))\n\nset_name_labels <- tibble::tibble(\n  x = c(0, -1.81, 1.71),\n  y = c(3.15, -1.85, -1.90),\n  label = c(\n    paste0(\"Python (n=\", python_total, \")\"),\n    paste0(\"SQL (n=\", sql_total, \")\"),\n    paste0(\"R (n=\", r_total, \")\")\n  )\n)\n\n# --- Plot ---------------------------------------------------------------------\np <- ggplot() +\n  geom_polygon(\n    data = circles, aes(x = x, y = y, fill = set, group = set),\n    alpha = 0.5, color = INK_SOFT, linewidth = 0.6\n  ) +\n  geom_text(\n    data = set_name_labels, aes(x = x, y = y, label = label),\n    color = INK, size = 4.6, fontface = \"bold\"\n  ) +\n  geom_text(\n    data = filter(region_counts, !focal), aes(x = x, y = y, label = count),\n    color = INK, size = 5.6, fontface = \"bold\"\n  ) +\n  geom_text(\n    data = filter(region_counts, focal), aes(x = x, y = y, label = count),\n    color = INK, size = 7.0, fontface = \"bold\"\n  ) +\n  geom_text(\n    data = region_counts, aes(x = x, y = y - 0.34, label = pct_label),\n    color = INK_SOFT, size = 3.2, fontface = \"plain\"\n  ) +\n  scale_fill_manual(values = IMPRINT_PALETTE) +\n  coord_fixed(xlim = c(-3.6, 3.6), ylim = c(-3.6, 3.6), expand = FALSE) +\n  labs(title = \"venn-basic · r · ggplot2 · anyplot.ai\") +\n  theme_void(base_size = 8) +\n  theme(\n    plot.background = element_rect(fill = PAGE_BG, color = PAGE_BG),\n    plot.title = element_text(\n      color = INK, size = 12, hjust = 0.5, margin = margin(b = 16)\n    ),\n    legend.position = \"none\",\n    plot.margin = margin(24, 24, 24, 24)\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"}