{"spec_id":"network-hierarchical","library":"makie","language":"julia","code":"# anyplot.ai\n# network-hierarchical: Hierarchical Network Graph with Tree Layout\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-09-02\n\nusing CairoMakie\nusing Colors\nusing Statistics\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\"\n\n# Imprint palette — one hue per organizational level (level 0 = root)\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",  # level 0 — CEO (brand green)\n    colorant\"#C475FD\",  # level 1 — VPs (lavender)\n    colorant\"#4467A3\",  # level 2 — Directors (blue)\n    colorant\"#BD8233\",  # level 3 — Managers / ICs (ochre)\n]\n\n# --- Data: a 4-level organizational chart, 24 employees ----------------------\nnodes = [\n    (id = \"ceo\", label = \"CEO\", level = 0, parent = \"\"),\n    (id = \"vp_eng\", label = \"VP Engineering\", level = 1, parent = \"ceo\"),\n    (id = \"vp_sales\", label = \"VP Sales\", level = 1, parent = \"ceo\"),\n    (id = \"vp_ops\", label = \"VP Operations\", level = 1, parent = \"ceo\"),\n    (id = \"dir_fe\", label = \"Dir. Frontend\", level = 2, parent = \"vp_eng\"),\n    (id = \"dir_be\", label = \"Dir. Backend\", level = 2, parent = \"vp_eng\"),\n    (id = \"dir_qa\", label = \"Dir. QA\", level = 2, parent = \"vp_eng\"),\n    (id = \"dir_ent\", label = \"Dir. Enterprise\", level = 2, parent = \"vp_sales\"),\n    (id = \"dir_smb\", label = \"Dir. SMB\", level = 2, parent = \"vp_sales\"),\n    (id = \"dir_hr\", label = \"Dir. HR\", level = 2, parent = \"vp_ops\"),\n    (id = \"dir_fin\", label = \"Dir. Finance\", level = 2, parent = \"vp_ops\"),\n    (id = \"dir_log\", label = \"Dir. Logistics\", level = 2, parent = \"vp_ops\"),\n    (id = \"mgr_fe_a\", label = \"Eng Mgr A\", level = 3, parent = \"dir_fe\"),\n    (id = \"mgr_fe_b\", label = \"Eng Mgr B\", level = 3, parent = \"dir_fe\"),\n    (id = \"mgr_be_a\", label = \"Eng Mgr C\", level = 3, parent = \"dir_be\"),\n    (id = \"mgr_be_b\", label = \"Eng Mgr D\", level = 3, parent = \"dir_be\"),\n    (id = \"lead_qa\", label = \"QA Lead\", level = 3, parent = \"dir_qa\"),\n    (id = \"mgr_sales_a\", label = \"Sales Mgr A\", level = 3, parent = \"dir_ent\"),\n    (id = \"mgr_sales_b\", label = \"Sales Mgr B\", level = 3, parent = \"dir_ent\"),\n    (id = \"mgr_sales_c\", label = \"Sales Mgr C\", level = 3, parent = \"dir_smb\"),\n    (id = \"mgr_hr\", label = \"HR Manager\", level = 3, parent = \"dir_hr\"),\n    (id = \"mgr_fin\", label = \"Finance Mgr\", level = 3, parent = \"dir_fin\"),\n    (id = \"analyst_fin\", label = \"Finance Analyst\", level = 3, parent = \"dir_fin\"),\n    (id = \"mgr_log\", label = \"Logistics Mgr\", level = 3, parent = \"dir_log\"),\n]\n\nchildren = Dict(n.id => String[] for n in nodes)\nfor n in nodes\n    n.parent != \"\" && push!(children[n.parent], n.id)\nend\n\n# --- Tree layout: leaves get sequential x, parents average their children ----\nconst LEAF_SPACING  = 1.0\nconst LEVEL_SPACING = 1.6\n\nx_pos = Dict{String,Float64}()\nleaf_nodes = [n for n in nodes if n.level == 3]\nfor (i, n) in enumerate(leaf_nodes)\n    x_pos[n.id] = i * LEAF_SPACING\nend\nfor lvl in (2, 1, 0)\n    for n in nodes\n        n.level == lvl && (x_pos[n.id] = mean(x_pos[k] for k in children[n.id]))\n    end\nend\ny_pos = Dict(n.id => -n.level * LEVEL_SPACING for n in nodes)\n\nconst BOX_W = 0.87 * LEAF_SPACING\nconst BOX_H = 0.42 * LEVEL_SPACING\n\n# Level-coded emphasis: thicker borders at senior levels reinforce the\n# hierarchy beyond color alone (CEO thickest, Manager/IC thinnest)\nconst STROKE_WIDTHS = [3.2, 2.8, 2.4, 2.0]\n\n# --- Figure --------------------------------------------------------------\ntitle_str = \"network-hierarchical · 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       = 20,\n    titlecolor      = INK,\n    backgroundcolor = PAGE_BG,\n)\nhidedecorations!(ax)\nhidespines!(ax)\n\n# Edges — straight lines from parent box bottom to child box top, drawn first.\n# Thinner + more transparent where a parent has many children, so dense\n# fan-outs (e.g. a VP with 3 directors) read less cluttered than single-child\n# edges.\nfor n in nodes\n    n.parent == \"\" && continue\n    px, py = x_pos[n.parent], y_pos[n.parent]\n    cx, cy = x_pos[n.id], y_pos[n.id]\n    nsiblings  = length(children[n.parent])\n    edge_alpha = clamp(0.6 - 0.04 * (nsiblings - 1), 0.35, 0.6)\n    edge_width = clamp(1.8 - 0.15 * (nsiblings - 1), 1.1, 1.8)\n    lines!(\n        ax, [px, cx], [py - BOX_H / 2, cy + BOX_H / 2];\n        color = (INK_SOFT, edge_alpha), linewidth = edge_width,\n    )\nend\n\n# Nodes — box per employee, border colored by organizational level, with\n# stroke width tapering from CEO (thickest) to Manager/IC (thinnest)\nfor n in nodes\n    x, y = x_pos[n.id], y_pos[n.id]\n    poly!(\n        ax, Rect2f(x - BOX_W / 2, y - BOX_H / 2, BOX_W, BOX_H);\n        color       = ELEVATED_BG,\n        strokecolor = IMPRINT_PALETTE[n.level + 1],\n        strokewidth = STROKE_WIDTHS[n.level + 1],\n    )\n    text!(\n        ax, x, y; text = n.label,\n        color = INK, fontsize = 12,\n        align = (:center, :center),\n    )\nend\n\nxs, ys = collect(values(x_pos)), collect(values(y_pos))\nxlims!(ax, minimum(xs) - BOX_W / 2 - 0.6, maximum(xs) + BOX_W / 2 + 0.6)\nylims!(ax, minimum(ys) - BOX_H / 2 - 0.2, maximum(ys) + BOX_H / 2 + 0.35)\n\n# Legend — organizational level key\nlevel_labels = [\"CEO\", \"VP\", \"Director\", \"Manager / IC\"]\nlegend_elems = [\n    PolyElement(color = ELEVATED_BG, strokecolor = IMPRINT_PALETTE[i], strokewidth = STROKE_WIDTHS[i])\n    for i in 1:4\n]\nLegend(\n    fig[1, 2], legend_elems, level_labels, \"Level\";\n    framevisible = false,\n    labelcolor   = INK,\n    titlecolor   = INK,\n    labelsize    = 13,\n    titlesize    = 14,\n    patchsize    = (18, 18),\n)\ncolsize!(fig.layout, 1, Relative(0.87))\n\n# --- Save ------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}