{"spec_id":"scatter-hr-diagram","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' scatter-hr-diagram: Hertzsprung-Russell Diagram\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 86/100 | Created: 2026-06-02\n\nlibrary(ggplot2)\nlibrary(scales)\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\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\n\n# Spectral type colors — semantic exception: conventional stellar color sequence\n# O/B are blue, A is pale lavender (white-ish), F/G are warm yellow-ochre,\n# K is rose (nearest Imprint to orange), M is matte red — all Imprint palette\nSPECTRAL_COLORS <- c(\n    \"O\" = \"#4467A3\",  # blue — O stars are intensely blue-hot\n    \"B\" = \"#2ABCCD\",  # cyan — B stars are blue-white\n    \"A\" = \"#C475FD\",  # lavender — A stars are white/pale blue-white\n    \"F\" = \"#99B314\",  # lime — F stars are yellow-white\n    \"G\" = \"#BD8233\",  # ochre — G stars are yellow (Sun-like)\n    \"K\" = \"#954477\",  # rose — K stars are orange-red\n    \"M\" = \"#AE3030\"   # matte red — M stars are red\n)\n\n# Assign spectral type based on effective temperature (Harvard classification)\nspectral_class <- function(temp) {\n    ifelse(temp >= 30000, \"O\",\n    ifelse(temp >= 10000, \"B\",\n    ifelse(temp >= 7500,  \"A\",\n    ifelse(temp >= 6000,  \"F\",\n    ifelse(temp >= 5200,  \"G\",\n    ifelse(temp >= 3700,  \"K\", \"M\"))))))\n}\n\n# --- Data -------------------------------------------------------------------\n# Main sequence: luminosity ~ T^4 (Stefan-Boltzmann), log-linear with scatter\nn_ms    <- 280\nms_temp <- 10^runif(n_ms, log10(3100), log10(38000))\nms_lum  <- 10^(4.0 * (log10(ms_temp) - log10(5778)) + rnorm(n_ms, sd = 0.25))\n\n# Red giants: evolved stars — cool, moderately luminous\nn_rg    <- 70\nrg_temp <- runif(n_rg, 3400, 5400)\nrg_lum  <- 10^(runif(n_rg, 1.2, 2.9) + rnorm(n_rg, sd = 0.12))\n\n# Supergiants: extremely luminous across wide temperature range\nn_sg    <- 22\nsg_temp <- c(runif(11, 3500, 7000), runif(11, 8000, 28000))\nsg_lum  <- 10^(runif(n_sg, 4.3, 5.8) + rnorm(n_sg, sd = 0.18))\n\n# White dwarfs: hot but very dim — compact degenerate remnants\nn_wd    <- 45\nwd_temp <- runif(n_wd, 9000, 38000)\nwd_lum  <- 10^(runif(n_wd, -3.8, -1.6) + rnorm(n_wd, sd = 0.18))\n\n# Combined stellar dataset with spectral type and region classification\nall_temp <- c(ms_temp, rg_temp, sg_temp, wd_temp)\nall_lum  <- c(ms_lum,  rg_lum,  sg_lum,  wd_lum)\nall_reg  <- c(rep(\"Main Sequence\", n_ms), rep(\"Red Giants\", n_rg),\n              rep(\"Supergiants\",   n_sg), rep(\"White Dwarfs\", n_wd))\n\ndf <- data.frame(\n    temperature   = all_temp,\n    luminosity    = all_lum,\n    region        = factor(all_reg, levels = c(\"Main Sequence\", \"Red Giants\",\n                                               \"Supergiants\", \"White Dwarfs\")),\n    spectral_type = factor(spectral_class(all_temp),\n                           levels = c(\"O\", \"B\", \"A\", \"F\", \"G\", \"K\", \"M\"))\n)\n\n# Sun: reference star — 5,778 K, 1.0 L_sun, G2V spectral type\nsun <- data.frame(temperature = 5778, luminosity = 1.0)\n\n# Notable named stars (star_name data dimension — DQ-01)\nnamed_stars <- data.frame(\n    temperature = c(3500,   9940,  12000),\n    luminosity  = c(1.26e5, 25.4,  1.3e5),\n    star_name   = c(\"Betelgeuse\", \"Sirius\", \"Rigel\")\n)\n\n# --- Plot -------------------------------------------------------------------\ntitle_str <- \"scatter-hr-diagram · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(df, aes(x = temperature, y = luminosity, color = spectral_type)) +\n    geom_point(size = 1.8, alpha = 0.72) +\n    # Sun: amber filled diamond — distinct reference marker\n    geom_point(\n        data        = sun,\n        aes(x = temperature, y = luminosity),\n        color       = INK,\n        fill        = \"#DDCC77\",\n        size        = 5.5,\n        shape       = 23,\n        stroke      = 0.8,\n        inherit.aes = FALSE\n    ) +\n    # Named star markers (filled triangles to distinguish from scatter)\n    geom_point(\n        data        = named_stars,\n        aes(x = temperature, y = luminosity),\n        color       = INK,\n        fill        = INK_SOFT,\n        size        = 3.5,\n        shape       = 24,\n        stroke      = 0.6,\n        inherit.aes = FALSE\n    ) +\n    # Named star labels\n    geom_text(\n        data        = named_stars,\n        aes(x = temperature, y = luminosity, label = star_name),\n        color       = INK_SOFT,\n        size        = 2.5,\n        fontface    = \"italic\",\n        hjust       = c(1.1, -0.15, -0.15),\n        vjust       = -0.4,\n        inherit.aes = FALSE\n    ) +\n    # Stellar region annotations guide the viewer through populations\n    annotate(\"text\",\n        x = 12000, y = 9e5,\n        label = \"SUPERGIANTS\", color = INK_MUTED,\n        size = 3.0, fontface = \"italic\"\n    ) +\n    annotate(\"text\",\n        x = 5400, y = 300,\n        label = \"RED GIANTS\", color = INK_MUTED,\n        size = 3.0, fontface = \"italic\", hjust = 1\n    ) +\n    annotate(\"text\",\n        x = 9500, y = 24,\n        label = \"MAIN SEQUENCE\", color = INK_MUTED,\n        size = 3.0, fontface = \"italic\", angle = -20\n    ) +\n    annotate(\"text\",\n        x = 26000, y = 0.0065,\n        label = \"WHITE DWARFS\", color = INK_MUTED,\n        size = 3.0, fontface = \"italic\"\n    ) +\n    # Sun label (amber matches the diamond marker fill)\n    annotate(\"text\",\n        x = 4750, y = 0.60,\n        label = \"Sun\", color = \"#DDCC77\",\n        size = 3.0, fontface = \"bold\"\n    ) +\n    # Reversed x-axis (astrophysical convention: hot on left, cool on right)\n    # Fewer breaks at cool end to avoid label crowding\n    scale_x_reverse(\n        name     = \"Surface Temperature (K)\",\n        breaks   = c(30000, 20000, 10000, 5000, 3500),\n        labels   = scales::label_comma(),\n        limits   = c(42000, 2700),\n        expand   = c(0.01, 0),\n        sec.axis = sec_axis(\n            transform = ~ .,\n            breaks    = c(35000, 20000, 8750, 6750, 5600, 4450, 3350),\n            labels    = c(\"O\", \"B\", \"A\", \"F\", \"G\", \"K\", \"M\"),\n            name      = \"Spectral Class\"\n        )\n    ) +\n    # Log-scale luminosity axis with scientific notation tick labels\n    scale_y_log10(\n        name   = \"Luminosity (solar units)\",\n        breaks = 10^c(-4, -2, 0, 2, 4, 6),\n        labels = scales::trans_format(\"log10\", scales::math_format(10^.x)),\n        limits = c(5e-5, 5e6),\n        expand = c(0.01, 0)\n    ) +\n    scale_color_manual(values = SPECTRAL_COLORS, name = \"Spectral Type\") +\n    labs(title = title_str) +\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 = INK_MUTED,  linewidth = 0.18),\n        panel.grid.minor  = element_line(color = INK_MUTED,  linewidth = 0.09),\n        panel.border      = element_rect(color = INK_SOFT,   fill = NA,\n                                         linewidth = 0.4),\n        axis.title        = element_text(color = INK,        size = 10),\n        axis.text         = element_text(color = INK_SOFT,   size = 8),\n        axis.title.x.top  = element_text(color = INK,        size = 10,\n                                         margin = margin(b = 4)),\n        axis.text.x.top   = element_text(color = INK_SOFT,   size = 9),\n        plot.title        = element_text(color = INK,        size = 12,\n                                         hjust = 0.5,\n                                         margin = margin(b = 10)),\n        legend.background = element_rect(fill = ELEVATED_BG, color = INK_SOFT,\n                                         linewidth = 0.3),\n        legend.text       = element_text(color = INK_SOFT,   size = 8),\n        legend.title      = element_text(color = INK_SOFT,   size = 9),\n        legend.key        = element_rect(fill = PAGE_BG,     color = NA),\n        legend.position   = \"right\",\n        plot.margin       = margin(12, 15, 12, 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"}