{"spec_id":"scatter-text","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' scatter-text: Scatter Plot with Text Labels Instead of Points\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 84/100 | Created: 2026-05-17\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\"\nIMPRINT   <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                 \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# --- Data: Product positioning in competitive landscape ---------------------\n# Scenario: Tech products positioned by price (x) vs quality rating (y)\nproducts <- data.frame(\n  name = c(\"TechPro\", \"QuickStart\", \"Premium+\", \"BudgetKit\", \"FlyMax\",\n           \"DataHub\", \"CloudNine\", \"SparkEdge\", \"NextGen\", \"ProStudio\",\n           \"SmartFlow\", \"EcoTools\", \"VisionAI\", \"FastLane\", \"EliteCore\",\n           \"SwiftPay\", \"ZenMode\", \"NexusHub\", \"SkyScan\", \"HumanAI\"),\n  price = c(799, 199, 1299, 49, 599,\n            899, 699, 399, 1099, 1399,\n            299, 149, 949, 499, 1199,\n            349, 249, 749, 429, 999),\n  quality = c(92, 78, 96, 62, 88,\n              89, 91, 84, 94, 97,\n              81, 72, 93, 85, 95,\n              79, 76, 87, 83, 90)\n)\n\n# Normalize to 0-100 for better visual distribution\nproducts$x <- (products$price - min(products$price)) / (max(products$price) - min(products$price)) * 100\nproducts$y <- products$quality\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot(products, aes(x = x, y = y, label = name)) +\n  geom_text(\n    color = IMPRINT[1],\n    size = 5.5,\n    alpha = 0.85,\n    fontface = \"plain\"\n  ) +\n  labs(\n    title = \"scatter-text · R · ggplot2 · anyplot.ai\",\n    x = \"Price (normalized)\",\n    y = \"Quality Rating\"\n  ) +\n  scale_x_continuous(limits = c(-5, 105), breaks = seq(0, 100, by = 25)) +\n  scale_y_continuous(limits = c(55, 105), breaks = seq(60, 100, by = 10)) +\n  theme_minimal(base_size = 14) +\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_SOFT, linewidth = 0.25),\n    panel.grid.minor  = element_blank(),\n    panel.border      = element_rect(color = INK_SOFT, fill = NA, linewidth = 0.4),\n    axis.title        = element_text(color = INK, size = 20, face = \"plain\"),\n    axis.text         = element_text(color = INK_SOFT, size = 16),\n    axis.ticks        = element_line(color = INK_SOFT, linewidth = 0.3),\n    axis.ticks.length = unit(0.15, \"cm\"),\n    plot.title        = element_text(color = INK, size = 24, face = \"plain\", margin = margin(b = 20))\n  )\n\n# --- Save -------------------------------------------------------------------\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 16,\n  height   = 9,\n  units    = \"in\",\n  dpi      = 300\n)\n"}