{"spec_id":"ecdf-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# ecdf-basic: Basic ECDF Plot\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 88/100 | Created: 2026-06-25\n\nusing CairoMakie\nusing Colors\nusing Random\nusing Statistics\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 IMPRINT_PALETTE = [\n    colorant\"#009E73\",\n    colorant\"#C475FD\",\n    colorant\"#4467A3\",\n    colorant\"#BD8233\",\n    colorant\"#AE3030\",\n    colorant\"#2ABCCD\",\n    colorant\"#954477\",\n    colorant\"#99B314\",\n]\n\n# Data: page load times (seconds) for three server configurations (n=200 each)\nn = 200\ntimes_cached = randn(n) .* 0.20 .+ 0.80\ntimes_cdn    = randn(n) .* 0.30 .+ 1.40\ntimes_legacy = randn(n) .* 0.60 .+ 2.80\n\n# P50 (median) for each group — used for reference lines\np50_c   = median(times_cached)\np50_cdn = median(times_cdn)\np50_l   = median(times_legacy)\n\n# Compute ECDFs: sort data, build cumulative proportions, extend tails for clean drawing\nsorted_c   = sort(times_cached)\next_c      = 0.08 * (sorted_c[end] - sorted_c[1])\nxs_c       = vcat([sorted_c[1] - ext_c], sorted_c, [sorted_c[end] + ext_c])\nys_c       = vcat([0.0], collect(1:n) ./ n, [1.0])\n\nsorted_cdn = sort(times_cdn)\next_cdn    = 0.08 * (sorted_cdn[end] - sorted_cdn[1])\nxs_cdn     = vcat([sorted_cdn[1] - ext_cdn], sorted_cdn, [sorted_cdn[end] + ext_cdn])\nys_cdn     = vcat([0.0], collect(1:n) ./ n, [1.0])\n\nsorted_l   = sort(times_legacy)\next_l      = 0.08 * (sorted_l[end] - sorted_l[1])\nxs_l       = vcat([sorted_l[1] - ext_l], sorted_l, [sorted_l[end] + ext_l])\nys_l       = vcat([0.0], collect(1:n) ./ n, [1.0])\n\n# Plot\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = \"ecdf-basic · julia · makie · anyplot.ai\",\n    titlesize          = 22,\n    titlecolor         = INK,\n    xlabel             = \"Page Load Time (seconds)\",\n    ylabel             = \"Cumulative Proportion\",\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\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    xgridvisible       = false,\n    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    xminorgridvisible  = false,\n    yminorgridvisible  = false,\n    yticks             = 0.0:0.1:1.0,\n)\n\n# Horizontal reference at P50 (y=0.5) — reads off median directly\nhlines!(ax, [0.5];\n    color     = RGBAf(INK_SOFT.r, INK_SOFT.g, INK_SOFT.b, 0.30),\n    linestyle = :dash,\n    linewidth = 1.0,\n)\n\n# Vertical drop lines at each group's P50\nvlines!(ax, [p50_c];\n    color     = RGBAf(IMPRINT_PALETTE[1].r, IMPRINT_PALETTE[1].g, IMPRINT_PALETTE[1].b, 0.45),\n    linestyle = :dash,\n    linewidth = 1.2,\n)\nvlines!(ax, [p50_cdn];\n    color     = RGBAf(IMPRINT_PALETTE[2].r, IMPRINT_PALETTE[2].g, IMPRINT_PALETTE[2].b, 0.45),\n    linestyle = :dash,\n    linewidth = 1.2,\n)\nvlines!(ax, [p50_l];\n    color     = RGBAf(IMPRINT_PALETTE[3].r, IMPRINT_PALETTE[3].g, IMPRINT_PALETTE[3].b, 0.45),\n    linestyle = :dash,\n    linewidth = 1.2,\n)\n\n# ECDF step curves\nstairs!(ax, xs_c, ys_c;\n    step      = :post,\n    color     = IMPRINT_PALETTE[1],\n    linewidth = 2.5,\n    label     = \"Cached Server\",\n)\nstairs!(ax, xs_cdn, ys_cdn;\n    step      = :post,\n    color     = IMPRINT_PALETTE[2],\n    linewidth = 2.5,\n    label     = \"CDN Server\",\n)\nstairs!(ax, xs_l, ys_l;\n    step      = :post,\n    color     = IMPRINT_PALETTE[3],\n    linewidth = 2.5,\n    label     = \"Legacy Server\",\n)\n\n# P50 callout annotations — label each median crossing\ntext!(ax, p50_c,   0.53;\n    text      = \"P50: $(round(p50_c,   digits=2))s\",\n    color     = IMPRINT_PALETTE[1],\n    fontsize  = 10,\n    align     = (:left, :bottom),\n)\ntext!(ax, p50_cdn, 0.53;\n    text      = \"P50: $(round(p50_cdn, digits=2))s\",\n    color     = IMPRINT_PALETTE[2],\n    fontsize  = 10,\n    align     = (:left, :bottom),\n)\ntext!(ax, p50_l,   0.53;\n    text      = \"P50: $(round(p50_l,   digits=2))s\",\n    color     = IMPRINT_PALETTE[3],\n    fontsize  = 10,\n    align     = (:left, :bottom),\n)\n\nylims!(ax, -0.02, 1.05)\n\naxislegend(ax;\n    position        = :lt,\n    backgroundcolor = ELEVATED_BG,\n    labelcolor      = INK_SOFT,\n    framevisible    = false,\n    labelsize       = 12,\n)\n\n# Save\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}