{"spec_id":"timeline-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# timeline-basic: Event Timeline\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 88/100 | Created: 2026-09-09\n\nusing CairoMakie\nusing Dates\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 IMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n    colorant\"#2ABCCD\",\n]\n\n# --- Data ---------------------------------------------------------------\nmilestones = [\n    (Date(2024, 1, 15), \"Kickoff & Planning\", \"Planning\"),\n    (Date(2024, 2, 20), \"Requirements Signed Off\", \"Planning\"),\n    (Date(2024, 3, 10), \"Architecture Design\", \"Design\"),\n    (Date(2024, 4, 5), \"UI Prototype Approved\", \"Design\"),\n    (Date(2024, 5, 18), \"Core API Complete\", \"Build\"),\n    (Date(2024, 6, 22), \"Database Migration\", \"Build\"),\n    (Date(2024, 7, 30), \"Feature Freeze\", \"Build\"),\n    (Date(2024, 9, 2), \"Beta Release\", \"Testing\"),\n    (Date(2024, 10, 14), \"Security Audit Passed\", \"Testing\"),\n    (Date(2024, 11, 25), \"General Availability\", \"Launch\"),\n]\n\ncategories = [\"Planning\", \"Design\", \"Build\", \"Testing\", \"Launch\"]\ncategory_colors = Dict(\n    \"Planning\" => IMPRINT_PALETTE[1],\n    \"Design\"   => IMPRINT_PALETTE[2],\n    \"Build\"    => IMPRINT_PALETTE[3],\n    \"Testing\"  => IMPRINT_PALETTE[4],\n    \"Launch\"   => IMPRINT_PALETTE[5],\n)\n\ndates       = [m[1] for m in milestones]\nevent_names = [m[2] for m in milestones]\nevent_cats  = [m[3] for m in milestones]\nday_numbers = Float64.(Dates.value.(dates .- dates[1]))\nevent_colors = [category_colors[c] for c in event_cats]\n\n# --- Plot -----------------------------------------------------------------\ntitle_str = \"timeline-basic · julia · makie · anyplot.ai\"\n\nfig = Figure(\n    resolution      = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = title_str,\n    titlesize          = 27,\n    titlecolor         = INK,\n    backgroundcolor    = PAGE_BG,\n    xlabel             = \"2024\",\n    xlabelsize         = 14,\n    xlabelcolor        = INK,\n    xticksvisible      = false,\n    xticklabelsvisible = false,\n    leftspinevisible   = false,\n    rightspinevisible  = false,\n    topspinevisible    = false,\n    bottomspinecolor   = INK_SOFT,\n    yticksvisible      = false,\n    yticklabelsvisible = false,\n    xgridvisible       = false,\n    ygridvisible       = false,\n)\n\nhidespines!(ax, :l, :r, :t)\nylims!(ax, -1.6, 1.6)\n\n# Baseline axis\nhlines!(ax, [0]; color = INK_SOFT, linewidth = 2)\n\n# Stems + alternating labels above/below to prevent overlap\nfor (i, day) in enumerate(day_numbers)\n    above = isodd(i)\n    stem_top = above ? 0.9 : -0.9\n    label_y = above ? 1.1 : -1.1\n\n    lines!(ax, [day, day], [0.0, stem_top]; color = event_colors[i], linewidth = 2)\n\n    label = event_names[i] * \"\\n\" * Dates.format(dates[i], \"u d\")\n    text!(\n        ax, day, label_y;\n        text  = label,\n        color = INK,\n        fontsize = 13,\n        align = (:center, above ? :bottom : :top),\n        lineheight = 1.3,\n    )\nend\n\nscatter!(\n    ax, day_numbers, zeros(length(day_numbers));\n    color = event_colors, markersize = 20, strokewidth = 2, strokecolor = PAGE_BG,\n)\n\n# Legend for categories\nlegend_elements = [\n    MarkerElement(color = category_colors[c], marker = :circle, markersize = 16)\n    for c in categories\n]\nLegend(\n    fig[2, 1], legend_elements, categories;\n    orientation = :horizontal,\n    framevisible = false,\n    labelcolor = INK_SOFT,\n    labelsize = 12,\n    tellwidth = false,\n    tellheight = true,\n)\nrowsize!(fig.layout, 2, Relative(0.08))\n\nhideydecorations!(ax)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}