{"spec_id":"gantt-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# gantt-basic: Basic Gantt Chart\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 91/100 | Created: 2026-09-05\n\nusing CairoMakie\nusing Dates\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens -----------------------------------------------------------\nTHEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nPAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nINK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nINK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nIMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n]\n\n# --- Data ---------------------------------------------------------------------\ntasks = [\n    \"Requirements Gathering\", \"System Design\", \"Database Architecture\",\n    \"Backend Development\", \"Frontend Development\", \"API Integration\",\n    \"Unit Testing\", \"Integration Testing\", \"User Acceptance Testing\",\n    \"Production Deployment\",\n]\n\ncategories = [\n    \"Planning\", \"Planning\", \"Development\",\n    \"Development\", \"Development\", \"Development\",\n    \"Testing\", \"Testing\", \"Testing\",\n    \"Deployment\",\n]\n\nstarts = Date.([\n    \"2026-01-05\", \"2026-01-12\", \"2026-01-26\",\n    \"2026-02-02\", \"2026-02-16\", \"2026-03-02\",\n    \"2026-03-16\", \"2026-03-23\", \"2026-03-30\",\n    \"2026-04-06\",\n])\n\nends = Date.([\n    \"2026-01-16\", \"2026-01-30\", \"2026-02-06\",\n    \"2026-03-06\", \"2026-03-13\", \"2026-03-20\",\n    \"2026-03-27\", \"2026-04-03\", \"2026-04-10\",\n    \"2026-04-17\",\n])\n\nn_tasks = length(tasks)\nstart_nums = Dates.value.(starts)\nend_nums = Dates.value.(ends)\ndurations = end_nums .- start_nums\ny_positions = collect(n_tasks:-1:1)  # earliest task plotted at the top\ntoday_num = Dates.value(Date(2026, 3, 10))\nactive_idx = findfirst(i -> start_nums[i] <= today_num <= end_nums[i], 1:n_tasks)\n\nunique_categories = unique(categories)\ncategory_colors = Dict(zip(unique_categories, IMPRINT_PALETTE[1:length(unique_categories)]))\n\n# --- Plot ---------------------------------------------------------------------\ntitle_str = \"Software Launch Plan · gantt-basic · julia · makie · anyplot.ai\"\ntitle_fontsize = length(title_str) > 67 ? round(Int, 20 * 67 / length(title_str)) : 20\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         = title_fontsize,\n    titlecolor        = INK,\n    xlabel            = \"Project Timeline (2026)\",\n    xlabelsize        = 14,\n    xlabelcolor       = INK,\n    ylabel            = \"Task\",\n    ylabelsize        = 13,\n    ylabelcolor       = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelsize    = 13,\n    xticklabelsize    = 12,\n    backgroundcolor   = PAGE_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xgridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    ygridvisible      = false,\n    yticks            = (1:n_tasks, reverse(tasks)),\n)\n\nmonth_starts = Date(2026, 1, 1):Month(1):Date(2026, 5, 1)\nax.xticks = (Dates.value.(month_starts), Dates.format.(month_starts, \"u\"))\n\nfor cat in unique_categories\n    idx = findall(==(cat), categories)\n    barplot!(\n        ax, y_positions[idx], end_nums[idx];\n        fillto    = start_nums[idx],\n        direction = :x,\n        width     = 0.6,\n        color     = category_colors[cat],\n        label     = cat,\n    )\nend\n\nfor i in 1:n_tasks\n    text!(\n        ax, end_nums[i] + 2, y_positions[i];\n        text = \"$(durations[i])d\", color = INK_SOFT, fontsize = 10, align = (:left, :center),\n    )\nend\n\nif active_idx !== nothing\n    scatter!(\n        ax, [start_nums[active_idx]], [y_positions[active_idx]];\n        marker = :star5, markersize = 16, color = INK, strokewidth = 0,\n    )\n    text!(\n        ax, start_nums[active_idx] - 3, y_positions[active_idx];\n        text = \"In Progress\", color = INK, fontsize = 11, align = (:right, :center),\n    )\nend\n\nvlines!(ax, [today_num]; color = INK_SOFT, linestyle = :dash, linewidth = 2)\ntext!(\n    ax, today_num + 2, n_tasks + 0.75;\n    text = \"Today\", color = INK_SOFT, fontsize = 13, align = (:left, :bottom),\n)\n\nylims!(ax, 0.3, n_tasks + 1.3)\nxlims!(ax, minimum(start_nums) - 8, maximum(end_nums) + 14)\n\nLegend(\n    fig[1, 2], ax, \"Category\";\n    framevisible    = false,\n    backgroundcolor = PAGE_BG,\n    labelcolor      = INK_SOFT,\n    titlecolor      = INK,\n)\n\n# --- Save -----------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}