{"spec_id":"bar-diverging-likert","library":"makie","language":"julia","code":"# anyplot.ai\n# bar-diverging-likert: Likert Scale Diverging Bar Chart\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 88/100 | Created: 2026-06-01\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\"\n\n# Imprint palette — semantic mapping: positive→green, negative→red\nconst COL_SA = colorant\"#009E73\"  # Strongly Agree: Imprint brand green (positive)\nconst COL_A  = colorant\"#4467A3\"  # Agree: Imprint blue\nconst COL_D  = colorant\"#BD8233\"  # Disagree: Imprint ochre\nconst COL_SD = colorant\"#AE3030\"  # Strongly Disagree: Imprint matte red (negative)\n\n# Data — employee engagement survey (10 items, 5-point Likert scale)\nconst questions_raw = [\n    \"Work-Life Balance\",\n    \"Team Collaboration\",\n    \"Management Support\",\n    \"Career Development\",\n    \"Compensation & Benefits\",\n    \"Learning Opportunities\",\n    \"Job Security\",\n    \"Company Culture\",\n    \"Tools & Resources\",\n    \"Internal Communication\",\n]\n\n# Rows: [SD, D, N, A, SA] as percentages (each row sums to 100)\nconst resp_matrix = Float64[\n     5  12  18  42  23;\n     3   8  12  45  32;\n     8  15  20  38  19;\n    10  18  22  32  18;\n    12  20  25  28  15;\n     4  10  16  48  22;\n     6  11  19  40  24;\n     5   9  14  44  28;\n     9  16  21  35  19;\n     7  13  17  40  23;\n]\n\nn_q  = length(questions_raw)\nsd_v = resp_matrix[:, 1]\nd_v  = resp_matrix[:, 2]\nn_v  = resp_matrix[:, 3]\na_v  = resp_matrix[:, 4]\nsa_v = resp_matrix[:, 5]\n\n# Sort ascending by net agreement (SA + A − SD − D): most negative at bottom\nnet_score = sa_v .+ a_v .- sd_v .- d_v\norder     = sortperm(net_score)\n\nquestions = questions_raw[order]\nsd = sd_v[order]; d = d_v[order]; n = n_v[order]\na  = a_v[order];  sa = sa_v[order]\n\ny_pos  = collect(1.0:Float64(n_q))\nn_half = n ./ 2.0\n\n# Segment x-offsets for percentage label placement\nsd_off = -(sd .+ d .+ n_half)\nd_off  = -(d .+ n_half)\na_off  =  n_half\nsa_off =  n_half .+ a\n\n# Title with length-aware fontsize\ntitle_str = \"Employee Engagement Survey · bar-diverging-likert · julia · makie · anyplot.ai\"\ntitle_fs  = length(title_str) > 67 ? round(Int, 20 * 67 / length(title_str)) : 20\n\n# Figure\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = title_str,\n    titlesize          = title_fs,\n    titlecolor         = INK,\n    xlabel             = \"← Disagree        Response Share (%)        Agree →\",\n    xlabelcolor        = INK,\n    xlabelsize         = 13,\n    xticklabelcolor    = INK_SOFT,\n    xticklabelsize     = 11,\n    yticklabelcolor    = INK_SOFT,\n    yticklabelsize     = 12,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = :transparent,\n    backgroundcolor    = PAGE_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinevisible   = false,\n    bottomspinecolor   = INK_SOFT,\n    xgridvisible       = true,\n    ygridvisible       = false,\n    xgridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.12f0),\n    yticks             = (y_pos, questions),\n)\n\nax.xtickformat = vs -> [\"$(abs(round(Int, v)))%\" for v in vs]\n\n# Stacked horizontal bars using barplot! with direction=:x — idiomatic Makie approach.\n# Left side: N/2 (innermost, stack=1), D (stack=2), SD (stack=3) — negative widths stack leftward.\nbarplot!(ax,\n    vcat(y_pos, y_pos, y_pos),\n    vcat(-n_half, -d, -sd);\n    direction   = :x,\n    stack       = vcat(fill(1, n_q), fill(2, n_q), fill(3, n_q)),\n    color       = vcat(fill(INK_MUTED, n_q), fill(COL_D, n_q), fill(COL_SD, n_q)),\n    gap         = 0.26,\n    strokewidth = 0,\n)\n\n# Right side: N/2 (innermost, stack=1), A (stack=2), SA (stack=3) — positive widths stack rightward.\nbarplot!(ax,\n    vcat(y_pos, y_pos, y_pos),\n    vcat(n_half, a, sa);\n    direction   = :x,\n    stack       = vcat(fill(1, n_q), fill(2, n_q), fill(3, n_q)),\n    color       = vcat(fill(INK_MUTED, n_q), fill(COL_A, n_q), fill(COL_SA, n_q)),\n    gap         = 0.26,\n    strokewidth = 0,\n)\n\n# Center reference line\nvlines!(ax, [0.0]; color = INK_SOFT, linewidth = 2.0, linestyle = :solid)\n\n# Percentage labels inside segments ≥ 8%\nlabel_fs = 10\n\nfor i in 1:n_q\n    yi = y_pos[i]\n    for (x0, w) in [\n        (sd_off[i], sd[i]),\n        (d_off[i],  d[i]),\n        (a_off[i],  a[i]),\n        (sa_off[i], sa[i]),\n    ]\n        if w >= 8.0\n            text!(ax, x0 + w / 2, yi;\n                  text     = \"$(round(Int, w))%\",\n                  align    = (:center, :center),\n                  color    = colorant\"#FFFFFF\",\n                  fontsize = label_fs)\n        end\n    end\nend\n\n# x-axis padding to avoid tight right/left margins\nmax_right = maximum(n_half .+ a .+ sa)\nmax_left  = maximum(sd .+ d .+ n_half)\nxlims!(ax, -(max_left + 8), max_right + 8)\n\n# Legend (horizontal, frameless)\nLegend(\n    fig[2, 1],\n    [\n        PolyElement(color = COL_SD,    strokecolor = :transparent),\n        PolyElement(color = COL_D,     strokecolor = :transparent),\n        PolyElement(color = INK_MUTED, strokecolor = :transparent),\n        PolyElement(color = COL_A,     strokecolor = :transparent),\n        PolyElement(color = COL_SA,    strokecolor = :transparent),\n    ],\n    [\"Strongly Disagree\", \"Disagree\", \"Neutral\", \"Agree\", \"Strongly Agree\"];\n    orientation     = :horizontal,\n    framevisible    = false,\n    backgroundcolor = ELEVATED_BG,\n    labelcolor      = INK_SOFT,\n    labelsize       = 12,\n    patchsize       = (24, 14),\n    tellwidth       = false,\n    tellheight      = true,\n)\n\nrowsize!(fig.layout, 2, Fixed(60))\n\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}