{"spec_id":"line-load-duration","library":"makie","language":"julia","code":"# anyplot.ai\n# line-load-duration: Load Duration Curve for Energy Systems\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-06-10\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 ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\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\n    colorant\"#C475FD\",  # 2 — lavender\n    colorant\"#4467A3\",  # 3 — blue\n    colorant\"#BD8233\",  # 4 — ochre\n    colorant\"#AE3030\",  # 5 — matte red\n    colorant\"#2ABCCD\",  # 6 — cyan\n    colorant\"#954477\",  # 7 — rose\n    colorant\"#99B314\",  # 8 — lime\n]\n\n# Data — synthetic annual hourly load profile for a mid-sized utility\nn_hours = 8760\n\n# Build a realistic load duration curve:\n# base component + daily/seasonal variation\nbase_load = 420.0\ndaily_variation = 150.0 * (0.5 .+ 0.5 .* sin.(range(0, 2π * 365, length=n_hours)))\nintraday_variation = 80.0 .* (0.5 .+ 0.5 .* sin.(range(0, 2π * n_hours, length=n_hours)))\nnoise = 40.0 .* randn(n_hours)\n\nraw_loads = base_load .+ daily_variation .+ intraday_variation .+ noise\n\n# Clamp and sort descending (load duration curve definition)\nraw_loads = clamp.(raw_loads, 380.0, 1250.0)\nload_mw = sort(raw_loads, rev=true)\nhours = 0:(n_hours - 1)\n\n# Capacity tier boundaries (hours)\npeak_end      = 876    # top 10% of hours\nintermediate_end = 4380  # top 50% of hours\n\n# Corresponding load levels at tier boundaries\npeak_capacity_mw        = load_mw[peak_end + 1]\nintermediate_capacity_mw = load_mw[intermediate_end + 1]\nbase_capacity_mw        = minimum(load_mw) + 20.0\n\n# Total energy (area under curve) in GWh\ntotal_energy_gwh = sum(load_mw) / 1000.0\n\n# Plot\nconst TITLE = \"line-load-duration · julia · makie · anyplot.ai\"\nn_title = length(TITLE)\ntitle_fontsize = n_title > 67 ? round(Int, 20 * 67 / n_title) : 20\n\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = TITLE,\n    titlesize          = title_fontsize,\n    titlecolor         = INK,\n    xlabel             = \"Duration (hours per year)\",\n    ylabel             = \"Load (MW)\",\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xlabelcolor        = INK,\n    ylabelcolor        = INK,\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\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    xgridvisible       = false,\n    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.12),\n    yminorgridvisible  = false,\n    xminorgridvisible  = false,\n    limits             = (0, n_hours, 0, maximum(load_mw) * 1.08),\n)\n\n# Fill the three load regions under the curve\npeak_hours   = 0:peak_end\ninter_hours  = peak_end:(intermediate_end)\nbase_hours   = intermediate_end:(n_hours - 1)\n\n# Peak region (leftmost, brief spikes) — matte red with low alpha\nband!(ax,\n    collect(peak_hours),\n    zeros(length(peak_hours)),\n    load_mw[peak_hours .+ 1];\n    color = RGBAf(IMPRINT_PALETTE[5].r, IMPRINT_PALETTE[5].g, IMPRINT_PALETTE[5].b, 0.18),\n)\n\n# Intermediate region — ochre\nband!(ax,\n    collect(inter_hours),\n    zeros(length(inter_hours)),\n    load_mw[inter_hours .+ 1];\n    color = RGBAf(IMPRINT_PALETTE[4].r, IMPRINT_PALETTE[4].g, IMPRINT_PALETTE[4].b, 0.28),\n)\n\n# Base load region (rightmost, always-on) — brand green\nband!(ax,\n    collect(base_hours),\n    zeros(length(base_hours)),\n    load_mw[base_hours .+ 1];\n    color = RGBAf(IMPRINT_PALETTE[1].r, IMPRINT_PALETTE[1].g, IMPRINT_PALETTE[1].b, 0.22),\n)\n\n# Main load duration curve\nlines!(ax, collect(hours), load_mw;\n    color     = IMPRINT_PALETTE[1],\n    linewidth = 2.5,\n)\n\n# Horizontal dashed capacity tier lines\nhlines!(ax, [peak_capacity_mw, intermediate_capacity_mw, base_capacity_mw];\n    color     = [IMPRINT_PALETTE[5], IMPRINT_PALETTE[4], IMPRINT_PALETTE[1]],\n    linestyle = :dash,\n    linewidth = 1.5,\n)\n\n# Vertical boundary lines between regions\nvlines!(ax, [peak_end, intermediate_end];\n    color     = RGBAf(INK_MUTED.r, INK_MUTED.g, INK_MUTED.b, 0.5),\n    linestyle = :dot,\n    linewidth = 1.2,\n)\n\n# Region labels\ntext!(ax, peak_end / 2, maximum(load_mw) * 0.92;\n    text      = \"Peak\\nLoad\",\n    align     = (:center, :top),\n    fontsize  = 13,\n    color     = IMPRINT_PALETTE[5],\n    font      = :bold,\n)\n\ntext!(ax, (peak_end + intermediate_end) / 2, maximum(load_mw) * 0.92;\n    text      = \"Intermediate\\nLoad\",\n    align     = (:center, :top),\n    fontsize  = 13,\n    color     = IMPRINT_PALETTE[4],\n    font      = :bold,\n)\n\ntext!(ax, (intermediate_end + n_hours) / 2, maximum(load_mw) * 0.92;\n    text      = \"Base\\nLoad\",\n    align     = (:center, :top),\n    fontsize  = 13,\n    color     = IMPRINT_PALETTE[1],\n    font      = :bold,\n)\n\n# Capacity tier labels on right margin\nlabel_x = n_hours * 0.94\ntext!(ax, label_x, peak_capacity_mw + 12;\n    text     = \"Peak cap. $(round(Int, peak_capacity_mw)) MW\",\n    align    = (:right, :bottom),\n    fontsize = 11,\n    color    = IMPRINT_PALETTE[5],\n)\n\ntext!(ax, label_x, intermediate_capacity_mw + 12;\n    text     = \"Interm. cap. $(round(Int, intermediate_capacity_mw)) MW\",\n    align    = (:right, :bottom),\n    fontsize = 11,\n    color    = IMPRINT_PALETTE[4],\n)\n\ntext!(ax, label_x, base_capacity_mw + 12;\n    text     = \"Base cap. $(round(Int, base_capacity_mw)) MW\",\n    align    = (:right, :bottom),\n    fontsize = 11,\n    color    = IMPRINT_PALETTE[1],\n)\n\n# Total energy annotation (area under curve)\nenergy_label = \"Total annual energy: $(round(Int, total_energy_gwh)) GWh\"\ntext!(ax, n_hours * 0.50, maximum(load_mw) * 0.44;\n    text     = energy_label,\n    align    = (:center, :center),\n    fontsize = 13,\n    color    = INK_SOFT,\n)\n\n# Save\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}