{"spec_id":"gantt-dependencies","library":"makie","language":"julia","code":"# anyplot.ai\n# gantt-dependencies: Gantt Chart with Dependencies\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 91/100 | Created: 2026-06-02\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\"\nconst AMBER       = colorant\"#DDCC77\"  # critical-path highlight\n\n# Imprint palette — positions 1,2,3,4,6 for 5 neutral phases\n# (slot 5 matte red is a semantic anchor for bad/loss/error; skipped here)\nconst PHASE_COLORS = [\n    colorant\"#009E73\",\n    colorant\"#C475FD\",\n    colorant\"#4467A3\",\n    colorant\"#BD8233\",\n    colorant\"#2ABCCD\",\n]\nconst PHASE_NAMES = [\"Foundation\", \"Structure\", \"Systems\", \"Finishing\", \"Completion\"]\n\n# Home construction project: 80-day schedule with 5 phases and 14 tasks\n# Y rows: group header rows use UPPERCASE, task rows use two-space indent\nconst TASK_LABELS = [\n    \"FOUNDATION\",\n    \"  Site Preparation\",\n    \"  Excavation\",\n    \"  Foundation Pour\",\n    \"STRUCTURE\",\n    \"  Framing\",\n    \"  Roofing\",\n    \"  Exterior Walls\",\n    \"SYSTEMS\",\n    \"  Plumbing\",\n    \"  Electrical\",\n    \"  HVAC\",\n    \"FINISHING\",\n    \"  Insulation\",\n    \"  Drywall\",\n    \"  Painting\",\n    \"COMPLETION\",\n    \"  Flooring\",\n    \"  Final Inspection\",\n]\n\nconst TASK_STARTS = [0,  0,  6, 12, 18, 18, 26, 26, 34, 34, 34, 44, 52, 52, 57, 64, 71, 71, 77]\nconst TASK_ENDS   = [17, 5, 11, 17, 33, 25, 32, 33, 51, 42, 43, 51, 70, 56, 63, 70, 80, 76, 80]\nconst IS_GROUP    = [true, false, false, false, true, false, false, false,\n                     true, false, false, false, true, false, false, false,\n                     true, false, false]\nconst PHASE_IDX   = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5]\n\n# Dependencies: (predecessor_row, successor_row) — finish-to-start\nconst DEPS = [\n    (2, 3),   # Site Preparation → Excavation\n    (3, 4),   # Excavation → Foundation Pour\n    (4, 6),   # Foundation Pour → Framing\n    (6, 7),   # Framing → Roofing\n    (6, 8),   # Framing → Exterior Walls\n    (7, 11),  # Roofing → Electrical\n    (8, 10),  # Exterior Walls → Plumbing\n    (8, 11),  # Exterior Walls → Electrical\n    (10, 12), # Plumbing → HVAC\n    (11, 12), # Electrical → HVAC\n    (12, 14), # HVAC → Insulation\n    (14, 15), # Insulation → Drywall\n    (15, 16), # Drywall → Painting\n    (16, 18), # Painting → Flooring\n    (18, 19), # Flooring → Final Inspection\n]\n\n# Critical path: longest dependency chain (any delay delays project finish)\nconst CRITICAL_DEPS = Set([(2, 3), (3, 4), (4, 6), (6, 7), (7, 11),\n                            (11, 12), (12, 14), (14, 15), (15, 16), (16, 18), (18, 19)])\n\nn_rows = length(TASK_LABELS)\n\n# Figure — landscape 3200×1800 px (size 1600×900 × px_per_unit 2)\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    backgroundcolor    = PAGE_BG,\n    title              = \"Home Construction · gantt-dependencies · julia · makie · anyplot.ai\",\n    titlesize          = 20,\n    titlecolor         = INK,\n    xlabel             = \"Project Day\",\n    xlabelsize         = 14,\n    xlabelcolor        = INK,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    leftspinecolor     = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    xgridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.12),\n    ygridvisible       = false,\n    xminorgridvisible  = false,\n    yminorgridvisible  = false,\n    yticks             = (collect(1:n_rows), TASK_LABELS),\n    xticks             = 0:10:80,\n)\n\nxlims!(ax, -2.0, 83.0)\nylims!(ax, Float64(n_rows) + 0.7, 0.3)  # inverted: row 1 at top, row 19 at bottom\n\n# Phase background bands — very light tint to group rows by phase\nfor g in 1:5\n    rows_g = filter(i -> PHASE_IDX[i] == g, 1:n_rows)\n    y_lo = Float64(minimum(rows_g)) - 0.5\n    y_hi = Float64(maximum(rows_g)) + 0.5\n    col  = PHASE_COLORS[g]\n    poly!(ax, Rect2f(-2.0, y_lo, 85.0, y_hi - y_lo);\n          color = RGBAf(col.r, col.g, col.b, 0.06f0), strokewidth = 0)\nend\n\n# Task and group header bars\nbar_h   = 0.50\ngroup_h = 0.26\n\nfor i in 1:n_rows\n    y   = Float64(i)\n    x0  = Float64(TASK_STARTS[i])\n    w   = Float64(TASK_ENDS[i] - TASK_STARTS[i])\n    col = PHASE_COLORS[PHASE_IDX[i]]\n    if IS_GROUP[i]\n        # Group aggregate bar: thicker stroke + diamond end-caps (classic Gantt summary bar)\n        poly!(ax, Rect2f(x0, y - group_h / 2, w, group_h);\n              color       = RGBAf(col.r, col.g, col.b, 0.35f0),\n              strokecolor = col,\n              strokewidth = 2.0)\n        scatter!(ax, [x0, x0 + w], [y, y];\n                 marker = :diamond, markersize = 11,\n                 color = col, strokewidth = 0)\n    else\n        poly!(ax, Rect2f(x0, y - bar_h / 2, w, bar_h);\n              color       = RGBAf(col.r, col.g, col.b, 0.85f0),\n              strokewidth = 0)\n    end\nend\n\n# Dependency connectors: L-shaped path from right edge of predecessor to left edge of successor\n# Critical-path connectors drawn in amber; off-path connectors in INK_MUTED\nfor dep in DEPS\n    r1, r2  = dep\n    x1      = Float64(TASK_ENDS[r1])\n    y1      = Float64(r1)\n    x2      = Float64(TASK_STARTS[r2])\n    y2      = Float64(r2)\n    x_bend  = x1 + 0.8\n    is_crit = dep in CRITICAL_DEPS\n    line_col  = is_crit ? AMBER     : INK_MUTED\n    line_w    = is_crit ? 1.8f0     : 1.2f0\n    arrow_col = is_crit ? AMBER     : INK_MUTED\n    lines!(ax, [x1, x_bend, x_bend, x2], [y1, y1, y2, y2];\n           color = line_col, linewidth = line_w)\n    scatter!(ax, [x2], [y2];\n             marker = :rtriangle, markersize = 11,\n             color = arrow_col, strokewidth = 0)\nend\n\n# Phase legend + critical path indicator\nphase_elements  = [PolyElement(color = PHASE_COLORS[i], strokewidth = 0) for i in 1:5]\ncrit_element    = LineElement(color = AMBER, linewidth = 2.0)\nall_elements    = vcat(phase_elements, [crit_element])\nall_labels      = vcat(PHASE_NAMES,   [\"Critical Path\"])\n\nLegend(\n    fig[2, 1],\n    all_elements,\n    all_labels;\n    orientation  = :horizontal,\n    framevisible = false,\n    labelcolor   = INK_SOFT,\n    padding      = (10f0, 10f0, 4f0, 4f0),\n)\nrowsize!(fig.layout, 2, Fixed(28))\n\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}