{"spec_id":"scatter-ashby-material","library":"makie","language":"julia","code":"# anyplot.ai\n# scatter-ashby-material: Ashby Material Selection Chart\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 86/100 | Created: 2026-06-03\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens -----------------------------------------------------------\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst INK_MUTED   = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\n\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",  # 1 — brand green (Metals)\n    colorant\"#C475FD\",  # 2 — lavender (Polymers)\n    colorant\"#4467A3\",  # 3 — blue (Ceramics)\n    colorant\"#BD8233\",  # 4 — ochre (Composites)\n    colorant\"#AE3030\",  # 5 — matte red (Elastomers)\n    colorant\"#2ABCCD\",  # 6 — cyan (Foams)\n    colorant\"#954477\",  # 7 — rose (Natural Mat.)\n]\n\n# --- Data -------------------------------------------------------------------\n# Classic density (kg/m³) vs Young's modulus (GPa) Ashby chart\n# Ellipse centroid and radii defined in log10 space for accurate log-log shape\nconst family_names = [\"Metals\", \"Polymers\", \"Ceramics\", \"Composites\", \"Elastomers\", \"Foams\", \"Natural Mat.\"]\nconst fam_cx = Float64[3.65,  3.08,  3.42,  3.20,  3.05,  1.80,  2.55]\nconst fam_cy = Float64[2.10,  0.30,  2.40,  1.85, -1.80, -1.50,  0.90]\nconst fam_rx = Float64[0.48,  0.18,  0.25,  0.16,  0.12,  0.45,  0.35]\nconst fam_ry = Float64[0.42,  0.55,  0.45,  0.78,  0.65,  0.80,  0.50]\nconst fam_n  = Int[25, 20, 20, 15, 15, 15, 15]\nconst n_fam  = length(family_names)\n\n# Scatter points — generated with Gaussian noise in log space, returned in data space\nall_xs = Vector{Vector{Float64}}(undef, n_fam)\nall_ys = Vector{Vector{Float64}}(undef, n_fam)\nfor i in 1:n_fam\n    all_xs[i] = 10.0 .^ (fam_cx[i] .+ randn(fam_n[i]) .* (fam_rx[i] * 0.55))\n    all_ys[i] = 10.0 .^ (fam_cy[i] .+ randn(fam_n[i]) .* (fam_ry[i] * 0.55))\nend\n\n# Ellipse angle parameter (closed polygon for poly!)\nconst θ_pts = LinRange(0.0, 2π, 81)\n\n# Performance index guide lines (straight lines in log-log = data-space curves)\nconst ρ_range  = 10.0 .^ LinRange(log10(8.0), log10(26000.0), 300)\nconst E_guide1 = 1.0e-3 .* ρ_range           # E/ρ = C  (slope 1, lightweight ties)\nconst E_guide2 = 1.1e-6 .* ρ_range .^ 2     # E^½/ρ = C (slope 2, lightweight plates)\n\n# --- Plot -------------------------------------------------------------------\nconst title_str  = \"Stiffness vs Weight · scatter-ashby-material · julia · makie · anyplot.ai\"\nconst title_size = max(13, round(Int, 20 * 67 / length(title_str)))\n\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 13,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = title_str,\n    titlesize          = title_size,\n    titlecolor         = INK,\n    xlabel             = \"Density  (kg/m³)\",\n    ylabel             = \"Young's Modulus  (GPa)\",\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xticklabelsize     = 11,\n    yticklabelsize     = 11,\n    xlabelcolor        = INK,\n    ylabelcolor        = INK,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    backgroundcolor    = PAGE_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinecolor     = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    xgridcolor         = RGBAf(Float32(red(INK)), Float32(green(INK)), Float32(blue(INK)), 0.12f0),\n    ygridcolor         = RGBAf(Float32(red(INK)), Float32(green(INK)), Float32(blue(INK)), 0.12f0),\n    xminorgridvisible  = false,\n    yminorgridvisible  = false,\n    xscale             = log10,\n    yscale             = log10,\n)\n\nxlims!(ax, 8.0, 26000.0)\nylims!(ax, 2.0e-4, 1500.0)\n\n# Performance index guide lines with labels\nlines!(ax, ρ_range, E_guide1;\n    color     = INK_MUTED,\n    linewidth = 1.2,\n    linestyle = :dash,\n)\nlines!(ax, ρ_range, E_guide2;\n    color     = INK_MUTED,\n    linewidth = 1.2,\n    linestyle = :dash,\n)\ntext!(ax, 23500.0, 24.0;\n    text     = \"E/ρ = c\",\n    fontsize = 9,\n    color    = INK_MUTED,\n    align    = (:right, :bottom),\n)\ntext!(ax, 22000.0, 560.0;\n    text     = \"E^½/ρ = c\",\n    fontsize = 9,\n    color    = INK_MUTED,\n    align    = (:right, :bottom),\n)\n\n# Material family regions, scatter points, and labels\nfor i in 1:n_fam\n    clr = IMPRINT_PALETTE[i]\n\n    # Ellipse polygon — defined in log space, converted to data space so Makie's\n    # log10 axis transformation renders it as an ellipse in log-log view\n    ell = [Point2f(10.0^(fam_cx[i] + fam_rx[i] * cos(a)),\n                   10.0^(fam_cy[i] + fam_ry[i] * sin(a))) for a in θ_pts]\n    poly!(ax, ell;\n        color       = RGBAf(Float32(red(clr)), Float32(green(clr)), Float32(blue(clr)), 0.30f0),\n        strokecolor = RGBAf(Float32(red(clr)), Float32(green(clr)), Float32(blue(clr)), 0.72f0),\n        strokewidth = 1.5,\n    )\n\n    # Individual material data points\n    scatter!(ax, all_xs[i], all_ys[i];\n        color       = clr,\n        markersize  = 12,\n        strokecolor = PAGE_BG,\n        strokewidth = 0.8,\n    )\n\n    # Family label offset above ellipse centroid to avoid scatter-point overlap\n    text!(ax, 10.0^fam_cx[i], 10.0^(fam_cy[i] + fam_ry[i] * 0.55);\n        text     = family_names[i],\n        fontsize = 11,\n        color    = INK,\n        align    = (:center, :bottom),\n    )\nend\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}