{"spec_id":"scatter-ashby-material","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' scatter-ashby-material: Ashby Material Selection Chart\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 90/100 | Created: 2026-06-03\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\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\n\n# Imprint palette — canonical order, one color per material family\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 — brand green   (Metals)\n  \"#C475FD\",  # 2 — lavender      (Ceramics)\n  \"#4467A3\",  # 3 — blue          (Polymers)\n  \"#BD8233\",  # 4 — ochre         (Composites)\n  \"#AE3030\",  # 5 — matte red     (Elastomers)\n  \"#2ABCCD\"   # 6 — cyan          (Foams)\n)\n\n# Data: density (kg/m^3) vs Young's Modulus (GPa) — classic Ashby chart\nmaterials <- data.frame(\n  material = c(\n    \"Aluminum alloy\", \"Mild steel\", \"Stainless steel\", \"Titanium alloy\",\n    \"Copper alloy\", \"Magnesium alloy\", \"Nickel alloy\", \"Tungsten\",\n    \"Brass\", \"Zinc alloy\",\n    \"Soda glass\", \"Borosilicate glass\", \"Alumina\", \"Silicon carbide\",\n    \"Silicon nitride\", \"Zirconia\", \"Silica glass\", \"Dense graphite\",\n    \"HDPE\", \"Polypropylene\", \"PMMA\", \"Nylon 66\", \"Epoxy resin\",\n    \"Polystyrene\", \"PVC\", \"Polycarbonate\",\n    \"CFRP (UD)\", \"GFRP\", \"Kevlar/epoxy\", \"Al/SiC composite\",\n    \"Oak (parallel grain)\", \"Bamboo\",\n    \"Natural rubber\", \"Silicone rubber\", \"Neoprene\", \"Polyurethane (soft)\",\n    \"PS foam\", \"Rigid PU foam\", \"Aluminum foam\", \"Cork\"\n  ),\n  family = factor(c(\n    rep(\"Metals\", 10),\n    rep(\"Ceramics\", 8),\n    rep(\"Polymers\", 8),\n    rep(\"Composites\", 6),\n    rep(\"Elastomers\", 4),\n    rep(\"Foams\", 4)\n  ), levels = c(\"Metals\", \"Ceramics\", \"Polymers\", \"Composites\", \"Elastomers\", \"Foams\")),\n  density = c(\n    2700, 7850, 7900, 4500, 8900, 1770, 8900, 19300, 8500, 6600,\n    2500, 2230, 3900, 3200, 3200, 5700, 2200, 1800,\n    960, 900, 1200, 1140, 1250, 1050, 1400, 1200,\n    1600, 2000, 1400, 2900, 600, 800,\n    920, 1200, 1230, 1100,\n    50, 100, 400, 120\n  ),\n  modulus = c(\n    70, 210, 200, 116, 120, 45, 214, 411, 100, 83,\n    70, 64, 380, 420, 310, 200, 73, 27,\n    0.9, 1.5, 3.2, 2.8, 3.5, 3.2, 3.0, 2.4,\n    150, 35, 80, 180, 12, 20,\n    0.05, 0.007, 0.004, 0.02,\n    0.007, 0.003, 0.5, 0.02\n  )\n)\n\n# Convex hulls computed on log-scale for accurate enclosure\nhull_data <- materials %>%\n  group_by(family) %>%\n  slice(chull(log10(density), log10(modulus))) %>%\n  ungroup()\n\n# Label positions — geometric mean per family\nlabel_data <- materials %>%\n  group_by(family) %>%\n  summarise(\n    label_x = 10^mean(log10(density)),\n    label_y = 10^mean(log10(modulus)),\n    .groups = \"drop\"\n  )\n\n# Guide line: E/rho = constant (slope 1 on log-log) — lightweight stiffness direction\nguide_df <- data.frame(\n  density = c(70, 22000),\n  modulus = c(70, 22000) * 3e-5\n)\n\n# Plot title\nplot_title <- \"scatter-ashby-material · r · ggplot2 · anyplot.ai\"\n\n# Build Ashby chart\np <- ggplot(materials, aes(x = density, y = modulus)) +\n  # Guide line (drawn first, behind all data)\n  geom_line(\n    data        = guide_df,\n    aes(x = density, y = modulus),\n    color       = INK_MUTED,\n    linewidth   = 0.45,\n    linetype    = \"dashed\",\n    alpha       = 0.55,\n    inherit.aes = FALSE\n  ) +\n  annotate(\n    \"text\",\n    x = 13000, y = 0.6,\n    label  = \"E/ρ = const\",\n    color  = INK_MUTED,\n    size   = 2.8,\n    hjust  = 0,\n    angle  = 0\n  ) +\n  # Filled convex hull regions\n  geom_polygon(\n    data  = hull_data,\n    aes(fill = family, group = family),\n    alpha = 0.22,\n    color = NA\n  ) +\n  # Hull border outlines\n  geom_polygon(\n    data      = hull_data,\n    aes(color = family, group = family),\n    fill      = NA,\n    linewidth = 0.55,\n    alpha     = 0.75\n  ) +\n  # Individual data points\n  geom_point(\n    aes(color = family),\n    size  = 2.1,\n    alpha = 0.88\n  ) +\n  # Family labels inside regions\n  geom_label(\n    data          = label_data,\n    aes(x = label_x, y = label_y, label = family, color = family),\n    fill          = ELEVATED_BG,\n    size          = 3.1,\n    fontface      = \"bold\",\n    label.size    = 0.2,\n    label.padding = unit(0.15, \"lines\"),\n    show.legend   = FALSE\n  ) +\n  scale_x_log10(\n    breaks = c(100, 1000, 10000),\n    labels = c(\"100\", \"1,000\", \"10,000\"),\n    expand = expansion(mult = c(0.08, 0.12))\n  ) +\n  scale_y_log10(\n    breaks = c(0.001, 0.01, 0.1, 1, 10, 100, 1000),\n    labels = c(\"0.001\", \"0.01\", \"0.1\", \"1\", \"10\", \"100\", \"1,000\"),\n    expand = expansion(mult = c(0.08, 0.12))\n  ) +\n  scale_color_manual(values = setNames(IMPRINT_PALETTE, levels(materials$family))) +\n  scale_fill_manual(values  = setNames(IMPRINT_PALETTE, levels(materials$family))) +\n  labs(\n    x     = \"Density  (kg/m³)\",\n    y     = \"Young's Modulus  (GPa)\",\n    title = plot_title\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_line(color = INK_SOFT, linewidth = 0.18),\n    panel.grid.minor = element_blank(),\n    panel.border     = element_blank(),\n    axis.title       = element_text(color = INK,      size = 10),\n    axis.text        = element_text(color = INK_SOFT, size = 8),\n    axis.line        = element_line(color = INK_SOFT, linewidth = 0.4),\n    axis.ticks       = element_line(color = INK_SOFT, linewidth = 0.3),\n    plot.title       = element_text(color = INK, size = 12,\n                                    margin = margin(b = 10, unit = \"pt\")),\n    legend.position  = \"none\",\n    plot.margin      = margin(t = 20, r = 35, b = 15, l = 20, unit = \"pt\")\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"}