{"spec_id":"heatmap-periodic-table","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' heatmap-periodic-table: Periodic Table Property Heatmap\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 88/100 | Created: 2026-06-15\n\nlibrary(ggplot2)\nlibrary(ragg)\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\"\nTILE_EMPTY  <- if (THEME == \"light\") \"#CCC9C1\" else \"#3A3A37\"\n\n# Imprint sequential colormap: low EN (alkali metals) → high EN (halogens/O)\nCOL_LOW  <- \"#009E73\"  # Imprint position 1 — brand green\nCOL_HIGH <- \"#4467A3\"  # Imprint position 3 — blue\n\n# --- Element data -----------------------------------------------------------\n# 118 elements: atomic number, symbol, period, group, Pauling electronegativity\n# f-block (La-Lu, Ac-Lr) listed with period/group matching canonical placement;\n# display coordinates will reposition them below the main grid.\n\nelements <- data.frame(\n  an = c(\n    # Period 1\n    1L, 2L,\n    # Period 2\n    3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L,\n    # Period 3\n    11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,\n    # Period 4\n    19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L,\n    31L, 32L, 33L, 34L, 35L, 36L,\n    # Period 5\n    37L, 38L, 39L, 40L, 41L, 42L, 43L, 44L, 45L, 46L, 47L, 48L,\n    49L, 50L, 51L, 52L, 53L, 54L,\n    # Period 6 main — Cs,Ba then Hf-Rn (La pulled to f-block row)\n    55L, 56L, 72L, 73L, 74L, 75L, 76L, 77L, 78L, 79L, 80L,\n    81L, 82L, 83L, 84L, 85L, 86L,\n    # Period 7 main — Fr,Ra then Rf-Og (Ac pulled to f-block row)\n    87L, 88L, 104L, 105L, 106L, 107L, 108L, 109L, 110L, 111L, 112L,\n    113L, 114L, 115L, 116L, 117L, 118L,\n    # Lanthanides (La-Lu, 57-71)\n    57L, 58L, 59L, 60L, 61L, 62L, 63L, 64L, 65L, 66L, 67L, 68L, 69L, 70L, 71L,\n    # Actinides (Ac-Lr, 89-103)\n    89L, 90L, 91L, 92L, 93L, 94L, 95L, 96L, 97L, 98L, 99L, 100L, 101L, 102L, 103L\n  ),\n  symbol = c(\n    \"H\", \"He\",\n    \"Li\", \"Be\", \"B\", \"C\", \"N\", \"O\", \"F\", \"Ne\",\n    \"Na\", \"Mg\", \"Al\", \"Si\", \"P\", \"S\", \"Cl\", \"Ar\",\n    \"K\", \"Ca\", \"Sc\", \"Ti\", \"V\", \"Cr\", \"Mn\", \"Fe\", \"Co\", \"Ni\", \"Cu\", \"Zn\",\n    \"Ga\", \"Ge\", \"As\", \"Se\", \"Br\", \"Kr\",\n    \"Rb\", \"Sr\", \"Y\", \"Zr\", \"Nb\", \"Mo\", \"Tc\", \"Ru\", \"Rh\", \"Pd\", \"Ag\", \"Cd\",\n    \"In\", \"Sn\", \"Sb\", \"Te\", \"I\", \"Xe\",\n    \"Cs\", \"Ba\", \"Hf\", \"Ta\", \"W\", \"Re\", \"Os\", \"Ir\", \"Pt\", \"Au\", \"Hg\",\n    \"Tl\", \"Pb\", \"Bi\", \"Po\", \"At\", \"Rn\",\n    \"Fr\", \"Ra\", \"Rf\", \"Db\", \"Sg\", \"Bh\", \"Hs\", \"Mt\", \"Ds\", \"Rg\", \"Cn\",\n    \"Nh\", \"Fl\", \"Mc\", \"Lv\", \"Ts\", \"Og\",\n    \"La\", \"Ce\", \"Pr\", \"Nd\", \"Pm\", \"Sm\", \"Eu\", \"Gd\", \"Tb\", \"Dy\", \"Ho\", \"Er\", \"Tm\", \"Yb\", \"Lu\",\n    \"Ac\", \"Th\", \"Pa\", \"U\", \"Np\", \"Pu\", \"Am\", \"Cm\", \"Bk\", \"Cf\", \"Es\", \"Fm\", \"Md\", \"No\", \"Lr\"\n  ),\n  period = c(\n    1L, 1L,\n    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,\n    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L,\n    4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L,\n    5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L,\n    6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,\n    7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L,\n    6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,\n    7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L\n  ),\n  grp = c(\n    1L, 18L,\n    1L, 2L, 13L, 14L, 15L, 16L, 17L, 18L,\n    1L, 2L, 13L, 14L, 15L, 16L, 17L, 18L,\n    1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,\n    1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,\n    1L, 2L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,\n    1L, 2L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,\n    3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L,\n    3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L\n  ),\n  en = c(\n    # Period 1\n    2.20, NA_real_,\n    # Period 2\n    0.98, 1.57, 2.04, 2.55, 3.04, 3.44, 3.98, NA_real_,\n    # Period 3\n    0.93, 1.31, 1.61, 1.90, 2.19, 2.58, 3.16, NA_real_,\n    # Period 4\n    0.82, 1.00, 1.36, 1.54, 1.63, 1.66, 1.55, 1.83, 1.88, 1.91, 1.90, 1.65,\n    1.81, 2.01, 2.18, 2.55, 2.96, 3.00,\n    # Period 5\n    0.82, 0.95, 1.22, 1.33, 1.60, 2.16, 1.90, 2.20, 2.28, 2.20, 1.93, 1.69,\n    1.78, 1.96, 2.05, 2.10, 2.66, 2.60,\n    # Period 6 main (Cs,Ba,Hf-Rn)\n    0.79, 0.89, 1.30, 1.50, 2.36, 1.90, 2.20, 2.20, 2.28, 2.54, 2.00,\n    1.62, 2.33, 2.02, 2.00, 2.20, NA_real_,\n    # Period 7 main (Fr,Ra,Rf-Og — most unknown)\n    0.70, 0.90, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_,\n    NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_,\n    NA_real_, NA_real_,\n    # Lanthanides (La-Lu)\n    1.10, 1.12, 1.13, 1.14, NA_real_, 1.17, NA_real_, 1.20, NA_real_,\n    1.22, 1.23, 1.24, 1.25, NA_real_, 1.27,\n    # Actinides (Ac-Lr)\n    1.10, 1.30, 1.50, 1.38, 1.36, 1.28, 1.13, 1.28, 1.30, 1.30, 1.30,\n    1.30, 1.30, 1.30, NA_real_\n  ),\n  stringsAsFactors = FALSE\n)\n\n# --- Display coordinates ----------------------------------------------------\n# y = -period so period 1 appears at top; f-block rows pushed below with gap\nelements$dx <- as.numeric(elements$grp)\nelements$dy <- -as.numeric(elements$period)\n\n# Reposition lanthanides (57-71) to y = -8.5\nelements$dy[elements$an >= 57L & elements$an <= 71L] <- -8.5\n# Reposition actinides (89-103) to y = -9.5\nelements$dy[elements$an >= 89L & elements$an <= 103L] <- -9.5\n\n# Placeholder tiles at (period 6, group 3) and (period 7, group 3) for La*/Ac*\nplaceholders <- data.frame(\n  an = NA_integer_, symbol = c(\"†\", \"‡\"),\n  period = c(6L, 7L), grp = c(3L, 3L), en = NA_real_,\n  dx = c(3, 3), dy = c(-6, -7),\n  stringsAsFactors = FALSE\n)\nelements <- rbind(elements, placeholders)\n\n# Text color: near-white on gradient tiles, muted on empty/unknown tiles\nelements$txt_col <- ifelse(is.na(elements$en), INK_MUTED, \"#F0EFE8\")\n\n# --- Plot -------------------------------------------------------------------\ntitle_str <- \"heatmap-periodic-table · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(elements, aes(x = dx, y = dy)) +\n\n  # Element family block regions (s / d / p / f) — subtle tinted backgrounds\n  # that group related elements and showcase ggplot2 layer composition\n  annotate(\"rect\", xmin = 0.5, xmax = 2.5, ymin = -7.5, ymax = -0.5,\n           fill = \"#BD8233\", alpha = 0.10, color = NA) +\n  annotate(\"rect\", xmin = 2.5, xmax = 12.5, ymin = -7.5, ymax = -3.5,\n           fill = \"#2ABCCD\", alpha = 0.08, color = NA) +\n  annotate(\"rect\", xmin = 12.5, xmax = 18.5, ymin = -7.5, ymax = -0.5,\n           fill = \"#C475FD\", alpha = 0.08, color = NA) +\n  annotate(\"rect\", xmin = 2.5, xmax = 17.5, ymin = -9.0, ymax = -8.0,\n           fill = \"#C475FD\", alpha = 0.10, color = NA) +\n  annotate(\"rect\", xmin = 2.5, xmax = 17.5, ymin = -10.0, ymax = -9.0,\n           fill = \"#C475FD\", alpha = 0.10, color = NA) +\n\n  # Base tiles (NA values get TILE_EMPTY fill via na.value)\n  geom_tile(aes(fill = en), width = 0.90, height = 0.90,\n            color = PAGE_BG, linewidth = 0.4) +\n\n  # Element symbols — centered in tile\n  geom_text(aes(label = symbol, color = txt_col),\n            size = 2.2, fontface = \"bold\", vjust = 0.4) +\n\n  # Atomic numbers — top-left corner of tile (skip placeholders with NA an)\n  geom_text(\n    data = subset(elements, !is.na(an)),\n    aes(x = dx - 0.37, y = dy + 0.30, label = an, color = txt_col),\n    size = 1.2, hjust = 0, vjust = 1\n  ) +\n\n  # EN value label — bottom of tile (only for elements with known values)\n  geom_text(\n    data = subset(elements, !is.na(en)),\n    aes(x = dx, y = dy - 0.27, label = sprintf(\"%.2f\", en)),\n    color = \"#F0EFE8\", size = 1.0, vjust = 0\n  ) +\n\n  # Imprint sequential colormap for continuous EN data\n  scale_fill_gradient(\n    low      = COL_LOW,\n    high     = COL_HIGH,\n    na.value = TILE_EMPTY,\n    name     = \"Electronegativity (Pauling scale)\",\n    limits   = c(0.7, 4.0),\n    breaks   = c(1, 2, 3, 4),\n    labels   = c(\"1.0\", \"2.0\", \"3.0\", \"4.0\"),\n    guide    = guide_colorbar(\n      title.position = \"top\",\n      barwidth       = unit(10, \"cm\"),\n      barheight      = unit(0.35, \"cm\"),\n      label.theme    = element_text(size = 7, color = INK_SOFT),\n      title.theme    = element_text(size = 8, color = INK)\n    )\n  ) +\n\n  scale_color_identity() +\n\n  scale_x_continuous(\n    name   = \"Group\",\n    breaks = 1:18,\n    labels = as.character(1:18),\n    expand = c(0.015, 0.015)\n  ) +\n  scale_y_continuous(\n    name   = \"Period\",\n    breaks = c(-1, -2, -3, -4, -5, -6, -7, -8.5, -9.5),\n    labels = c(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"Ln\", \"An\"),\n    expand = c(0.04, 0.04)\n  ) +\n\n  labs(title = title_str) +\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_blank(),\n    panel.grid.minor  = element_blank(),\n    panel.border      = element_blank(),\n    axis.title.x      = element_text(color = INK, size = 9),\n    axis.title.y      = element_text(color = INK, size = 9),\n    axis.text.x       = element_text(color = INK_SOFT, size = 7),\n    axis.text.y       = element_text(color = INK_SOFT, size = 7),\n    axis.ticks        = element_blank(),\n    plot.title        = element_text(color = INK, size = 12, face = \"bold\",\n                                     margin = margin(b = 8)),\n    plot.margin       = margin(t = 10, r = 10, b = 10, l = 10),\n    legend.background = element_rect(fill = ELEVATED_BG, color = NA),\n    legend.text       = element_text(color = INK_SOFT, size = 7),\n    legend.title      = element_text(color = INK, size = 8),\n    legend.position   = \"bottom\",\n    legend.direction  = \"horizontal\",\n    legend.margin     = margin(t = 4)\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"}