Cumulative Histogram — Makie.jl

A cumulative histogram (also known as an ogive or cumulative frequency histogram) displays the running total of observations up to each bin boundary. The y-axis shows cumulative count or proportion, creating a monotonically increasing step function that reaches the total sample size (or 1.0 for normalized).

Cumulative Histogram rendered with Makie.jl

Renders

Julia source (Makie.jl)

# anyplot.ai
# histogram-cumulative: Cumulative Histogram
# Library: makie 0.21.9 | Julia 1.11.9
# Quality: 91/100 | Created: 2026-09-05

using CairoMakie
using Colors
using Random
using Statistics

Random.seed!(42)

# --- Theme tokens ------------------------------------------------------------
const THEME    = get(ENV, "ANYPLOT_THEME", "light")
const PAGE_BG  = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
const INK      = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
const INK_SOFT = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"
const BRAND    = colorant"#009E73"  # Imprint palette position 1 — ALWAYS first series

# --- Data ----------------------------------------------------------------
# Parcel delivery times (hours) for an e-commerce carrier — a right-skewed
# lead-time distribution typical of logistics data.
n_orders = 1400
delivery_hours = exp.(0.45 .* randn(n_orders) .+ log(28.0))

n_bins = 28
edges = range(0.0, quantile(delivery_hours, 0.99), length = n_bins + 1)
counts = zeros(Int, n_bins)
for t in delivery_hours
    # Values past the 99th-percentile edge fall into the last bin, so the
    # tail is still counted while the axis stays focused on the bulk of it.
    idx = clamp(searchsortedlast(edges, t), 1, n_bins)
    counts[idx] += 1
end
cum_proportion = cumsum(counts) ./ n_orders

# Ogive polyline: flat within each bin at its cumulative level, with a
# vertical rise at every bin edge — the standard cumulative-histogram step.
step_x = Float64[edges[1]]
step_y = Float64[0.0]
for i in 1:n_bins
    push!(step_x, edges[i]); push!(step_y, cum_proportion[i])
    push!(step_x, edges[i + 1]); push!(step_y, cum_proportion[i])
end

# --- Plot ----------------------------------------------------------------
fig = Figure(
    size            = (1600, 900),
    fontsize        = 14,
    backgroundcolor = PAGE_BG,
)

ax = Axis(
    fig[1, 1];
    title             = "histogram-cumulative · julia · makie · anyplot.ai",
    titlesize         = 20,
    titlecolor        = INK,
    xlabel            = "Delivery Time (hours)",
    ylabel            = "Cumulative Proportion of Orders",
    xlabelsize        = 14,
    ylabelsize        = 14,
    xlabelcolor       = INK,
    ylabelcolor       = INK,
    xticklabelsize    = 12,
    yticklabelsize    = 12,
    xticklabelcolor   = INK_SOFT,
    yticklabelcolor   = INK_SOFT,
    xtickcolor        = INK_SOFT,
    ytickcolor        = INK_SOFT,
    backgroundcolor   = PAGE_BG,
    topspinevisible   = false,
    rightspinevisible = false,
    leftspinecolor    = INK_SOFT,
    bottomspinecolor  = INK_SOFT,
    xgridvisible      = false,
    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),
    yminorgridvisible = false,
    yticks            = 0:0.25:1.0,
)

band!(ax, step_x, zeros(length(step_x)), step_y; color = (BRAND, 0.12))

# The step LINE itself uses Makie's native `stairs!` recipe (step = :pre)
# rather than a hand-drawn polyline — `:pre` jumps to each bin's cumulative
# level right at its left edge, reproducing the same ogive shape as step_x/
# step_y above while showcasing a Makie-distinctive step-plot primitive.
stairs!(ax, edges, vcat(0.0, cum_proportion); step = :pre, color = BRAND, linewidth = 3.5)

xlims!(ax, edges[1], edges[end])
ylims!(ax, 0.0, 1.02)

# --- Median reference guide ------------------------------------------------
# The spec calls out percentile-reading as a primary application; a dashed
# median guide with an inline label lets the viewer read a concrete value
# off the curve instead of eyeballing the shape alone.
median_hours = quantile(delivery_hours, 0.5)
lines!(ax, [median_hours, median_hours], [0.0, 0.5]; color = INK_SOFT, linestyle = :dash, linewidth = 1.5)
lines!(ax, [edges[1], median_hours], [0.5, 0.5]; color = INK_SOFT, linestyle = :dash, linewidth = 1.5)
text!(
    ax, median_hours, 0.5;
    text = "Median: $(round(median_hours, digits = 1))h",
    align = (:left, :bottom),
    offset = (8, 6),
    color = INK,
    fontsize = 13,
)

# --- Save ----------------------------------------------------------------
save("plot-$(THEME).png", fig; px_per_unit = 2)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/histogram-cumulative/makie/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "histogram-cumulative",
  "language": "julia",
  "library": "makie",
  "page": "https://anyplot.ai/histogram-cumulative/julia/makie",
  "hub": "https://anyplot.ai/histogram-cumulative",
  "code_json": "https://api.anyplot.ai/specs/histogram-cumulative/makie/code",
  "spec_json": "https://api.anyplot.ai/specs/histogram-cumulative",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/histogram-cumulative/julia/makie/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/histogram-cumulative/julia/makie/plot-dark.png",
  "quality_score": 91.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Cumulative Histogram on anyplot.ai.

Other implementations