{"spec_id":"box-horizontal","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' box-horizontal: Horizontal Box Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-09-02\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\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\nBRAND <- IMPRINT_PALETTE[1]\n\n# --- Data: annual salary (in thousands USD) by job title ----------------\njob_titles <- c(\n  \"Data Scientist\", \"Software Engineer\", \"Product Manager\",\n  \"UX Designer\", \"Marketing Specialist\", \"Customer Support Rep\",\n  \"Sales Associate\"\n)\njob_params <- tibble::tibble(\n  job_title = job_titles,\n  mean_salary = c(128, 122, 118, 96, 78, 58, 62),\n  sd_salary   = c(18, 20, 16, 14, 12, 8, 15),\n  n           = c(22, 30, 18, 20, 24, 26, 28)\n)\n\ndf <- job_params %>%\n  rowwise() %>%\n  reframe(\n    job_title = job_title,\n    salary_k  = pmax(rnorm(n, mean_salary, sd_salary), 30)\n  )\n\n# Sort categories by median salary for easier comparison\nordered_titles <- df %>%\n  group_by(job_title) %>%\n  summarise(median_salary = median(salary_k)) %>%\n  arrange(median_salary) %>%\n  pull(job_title)\ndf$job_title <- factor(df$job_title, levels = ordered_titles)\n\n# --- Plot -----------------------------------------------------------------\ntitle_text <- \"box-horizontal · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(df, aes(x = salary_k, y = job_title)) +\n  geom_boxplot(\n    fill = BRAND, color = INK, alpha = 0.75,\n    outlier.color = BRAND, outlier.alpha = 0.85, outlier.size = 2.6,\n    linewidth = 0.5, width = 0.6\n  ) +\n  stat_summary(\n    fun = mean, geom = \"point\", orientation = \"y\",\n    shape = 23, size = 3.2, stroke = 1.1,\n    fill = PAGE_BG, color = INK\n  ) +\n  labs(\n    title = title_text,\n    x = \"Annual Salary (thousands USD)\",\n    y = NULL,\n    caption = \"◆ marks the mean; box marks the median and interquartile range\"\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.y = element_blank(),\n    panel.grid.minor.y = element_blank(),\n    panel.grid.major.x = element_line(color = INK, linewidth = 0.25),\n    panel.grid.minor.x = element_blank(),\n    axis.title.x      = element_text(color = INK, size = 10, margin = margin(t = 10)),\n    axis.text.x       = element_text(color = INK_SOFT, size = 8),\n    axis.text.y       = element_text(color = INK_SOFT, size = 9),\n    axis.ticks        = element_blank(),\n    plot.title        = element_text(color = INK, size = 12, margin = margin(b = 12)),\n    plot.caption      = element_text(color = INK_SOFT, size = 7, margin = margin(t = 10)),\n    plot.margin       = margin(t = 16, r = 24, b = 40, l = 12)\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"}