{"spec_id":"bar-3d-categorical","library":"makie","language":"julia","code":"# anyplot.ai\n# bar-3d-categorical: 3D Bar Chart for Categorical Comparison\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 84/100 | Created: 2026-09-04\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# Theme tokens (see prompts/default-style-guide.md \"Background\" + \"Theme-adaptive Chrome\")\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\"\n\n# Imprint continuous colormap — single-polarity (revenue magnitude has no natural midpoint)\nIMPRINT_SEQ = [colorant\"#009E73\", colorant\"#4467A3\"]\n\n# Data — quarterly revenue by product category and sales region\nproduct_categories = [\"Electronics\", \"Apparel\", \"Home & Garden\", \"Sports\", \"Books\"]\nregions = [\"North\", \"South\", \"East\", \"West\"]\nn_products = length(product_categories)\nn_regions = length(regions)\n\nbase_revenue = [82.0, 61.0, 48.0, 55.0, 39.0]\nregion_factor = [1.15, 0.85, 1.00, 0.95]\n\nrevenue = Array{Float64}(undef, n_products, n_regions)\nfor i in 1:n_products, j in 1:n_regions\n    revenue[i, j] = base_revenue[i] * region_factor[j] + randn() * 4\nend\n\n# Plot — see default-style-guide.md \"Visual Sizing Defaults\" for the canvas + sizing values\nfig = Figure(size = (1600, 900), fontsize = 14, backgroundcolor = PAGE_BG)\n\nax = Axis3(\n    fig[1, 1];\n    title = \"bar-3d-categorical · julia · makie · anyplot.ai\",\n    titlesize = 20,\n    titlecolor = INK,\n    xlabel = \"Product Category\",\n    ylabel = \"Region\",\n    zlabel = \"Revenue (\\$k)\",\n    xlabelsize = 14,\n    ylabelsize = 14,\n    zlabelsize = 14,\n    xlabelcolor = INK,\n    ylabelcolor = INK,\n    zlabelcolor = INK,\n    xticklabelsize = 12,\n    yticklabelsize = 12,\n    zticklabelsize = 12,\n    xticklabelcolor = INK_SOFT,\n    yticklabelcolor = INK_SOFT,\n    zticklabelcolor = INK_SOFT,\n    xticks = (1:n_products, product_categories),\n    yticks = (1:n_regions, regions),\n    azimuth = deg2rad(225),   # spec calls for ~45°; 225° keeps the tallest bars in front, unoccluded\n    elevation = deg2rad(30),\n    backgroundcolor = PAGE_BG,\n    xypanelcolor = PAGE_BG,\n    xzpanelcolor = PAGE_BG,\n    yzpanelcolor = PAGE_BG,\n    xgridcolor = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    ygridcolor = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    zgridcolor = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    xspinecolor_1 = INK_SOFT, xspinecolor_2 = INK_SOFT, xspinecolor_3 = INK_SOFT,\n    yspinecolor_1 = INK_SOFT, yspinecolor_2 = INK_SOFT, yspinecolor_3 = INK_SOFT,\n    zspinecolor_1 = INK_SOFT, zspinecolor_2 = INK_SOFT, zspinecolor_3 = INK_SOFT,\n    protrusions = 70,\n)\n\n# Bar bases sit on a unit grid; markersize < 1 in x/y leaves a gap between neighbors for depth cues\nbar_gap = 0.2\nbar_positions = Point3f[]\nbar_sizes = Vec3f[]\nbar_values = Float64[]\nfor i in 1:n_products, j in 1:n_regions\n    push!(bar_positions, Point3f(i - (1 - bar_gap) / 2, j - (1 - bar_gap) / 2, 0))\n    push!(bar_sizes, Vec3f(1 - bar_gap, 1 - bar_gap, revenue[i, j]))\n    push!(bar_values, revenue[i, j])\nend\n\nmeshscatter!(\n    ax, bar_positions;\n    marker = Rect3(Point3f(0, 0, 0), Vec3f(1, 1, 1)),\n    markersize = bar_sizes,\n    color = bar_values,\n    colormap = IMPRINT_SEQ,\n    colorrange = extrema(bar_values),\n    # Directional lighting on adjacent instanced Rect3 faces causes a\n    # visible z-fight crease on tall bars near the axis corner; flat\n    # per-value color reads more accurately against the Colorbar anyway.\n    shading = NoShading,\n)\n\nColorbar(\n    fig[1, 2];\n    limits = extrema(bar_values),\n    colormap = IMPRINT_SEQ,\n    label = \"Revenue (\\$k)\",\n    labelcolor = INK,\n    ticklabelcolor = INK_SOFT,\n    tickcolor = INK_SOFT,\n)\ncolsize!(fig.layout, 1, Relative(0.85))\n\n# Save\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}