diff --git a/plots/bar-stacked-labeled/implementations/julia/makie.jl b/plots/bar-stacked-labeled/implementations/julia/makie.jl new file mode 100644 index 0000000000..7399bae452 --- /dev/null +++ b/plots/bar-stacked-labeled/implementations/julia/makie.jl @@ -0,0 +1,117 @@ +# anyplot.ai +# bar-stacked-labeled: Stacked Bar Chart with Total Labels +# Library: makie 0.21.9 | Julia 1.11.9 +# Quality: 90/100 | Created: 2026-08-26 + +using CairoMakie +using Colors + +# --- Theme tokens ----------------------------------------------------------- +const THEME = get(ENV, "ANYPLOT_THEME", "light") +const PAGE_BG = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17" +const INK = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8" +const INK_SOFT = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0" + +const IMPRINT_PALETTE = [ + colorant"#009E73", colorant"#C475FD", colorant"#4467A3", colorant"#BD8233", + colorant"#AE3030", colorant"#2ABCCD", colorant"#954477", colorant"#99B314", +] + +# --- Data ------------------------------------------------------------------- +# Quarterly SaaS revenue split by product line ($M, illustrative). +quarters = ["Q1", "Q2", "Q3", "Q4"] +product_lines = ["Subscriptions", "Services", "Hardware", "Support"] + +revenue = [ + 5.2 2.1 0.9 0.5 + 5.8 2.3 0.8 0.5 + 6.5 2.6 0.9 0.6 + 7.3 3.0 0.9 0.7 +] + +n_quarter = length(quarters) +n_product = length(product_lines) + +x = repeat(1:n_quarter, inner = n_product) +stack = repeat(1:n_product, outer = n_quarter) +height = vec(permutedims(revenue)) + +totals = vec(sum(revenue, dims = 2)) + +# --- Plot --------------------------------------------------------------- +fig = Figure( + size = (1600, 900), + fontsize = 14, + backgroundcolor = PAGE_BG, +) + +ax = Axis( + fig[1, 1]; + title = "bar-stacked-labeled · julia · makie · anyplot.ai", + titlesize = 20, + titlecolor = INK, + xlabel = "Quarter", + ylabel = "Revenue (\$M)", + xlabelsize = 14, + ylabelsize = 14, + xlabelcolor = INK, + ylabelcolor = INK, + xticklabelsize = 13, + yticklabelsize = 12, + xticklabelcolor = INK_SOFT, + yticklabelcolor = INK_SOFT, + xtickcolor = INK_SOFT, + ytickcolor = INK_SOFT, + backgroundcolor = PAGE_BG, + topspinevisible = false, + rightspinevisible = false, + leftspinecolor = INK_SOFT, + bottomspinecolor = INK_SOFT, + xgridvisible = false, + ygridvisible = true, + ygridcolor = RGBAf(INK.r, INK.g, INK.b, 0.12), + yminorgridvisible = false, +) + +barplot!( + ax, x, height; + stack = stack, + color = stack, + colormap = IMPRINT_PALETTE[1:n_product], + width = 0.6, + strokewidth = 0, +) + +ax.xticks = (1:n_quarter, quarters) + +# --- Total labels: genuinely bold and larger than any other text, directly +# above the tallest segment of each stack. `rich()` mixes weight/size within +# one label -- the dollar figure is bold and oversized, the trailing "M" +# unit is smaller and softer, echoing typographic hierarchy from financial +# dashboards. +for (i, total) in enumerate(totals) + text!( + ax, Point2f(i, total); + text = rich( + rich("\$$(round(total, digits = 1))"; font = :bold, fontsize = 19, color = INK), + rich("M"; fontsize = 14, color = INK_SOFT), + ), + offset = (0, 8), + align = (:center, :bottom), + ) +end + +Legend( + fig[1, 2], [PolyElement(color = c) for c in IMPRINT_PALETTE[1:n_product]], product_lines; + labelcolor = INK_SOFT, + labelsize = 13, + framevisible = false, + backgroundcolor = PAGE_BG, +) + +# Fix the y-range last so the label headroom above the tallest bar survives +# any autolimits reset triggered by the legend/text calls above. +ylims!(ax, 0, maximum(totals) * 1.16) + +# --- Save --------------------------------------------------------------- +save("plot-$(THEME).png", fig; px_per_unit = 2) diff --git a/plots/bar-stacked-labeled/metadata/julia/makie.yaml b/plots/bar-stacked-labeled/metadata/julia/makie.yaml new file mode 100644 index 0000000000..2366f95834 --- /dev/null +++ b/plots/bar-stacked-labeled/metadata/julia/makie.yaml @@ -0,0 +1,238 @@ +library: makie +language: julia +specification_id: bar-stacked-labeled +created: '2026-08-26T18:59:57Z' +updated: '2026-08-26T19:37:54Z' +generated_by: claude-sonnet +workflow_run: 33002350165 +issue: 3504 +language_version: 1.11.9 +library_version: 0.21.9 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/bar-stacked-labeled/julia/makie/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/bar-stacked-labeled/julia/makie/plot-dark.png +preview_html_light: null +preview_html_dark: null +quality_score: 90 +review: + strengths: + - 'Pixel-verified: canvas is exactly 3200x1800, and data colors are identical between + light and dark renders — only chrome flips, as required' + - Total labels use genuine typographic hierarchy (rich() bold-oversized value + + smaller/softer unit) rather than uniform text, directly serving the spec's 'eliminate + mental arithmetic' goal + - Clean, idiomatic use of Makie's native stack= keyword on barplot! rather than + manually cumsum-ing segment heights + - ylims! is set last with explicit headroom (max(totals) * 1.16) specifically to + protect label space from being clobbered by autolimits + weaknesses: + - 'Title is disproportionately small: measured at only ~30% of the plot/axis width + (849px / 2814px) against the style guide''s ~50-70% target for this canvas size. + Increase titlesize from 20 toward ~26-28 so the mandated title carries appropriate + visual weight on the 3200x1800 landscape canvas.' + - Y-axis has only two gridlines (5 and 10) across a 0-~13.8 range — slightly sparse + for reading intermediate values off the chart. + image_description: |- + Light render (plot-light.png): + Background: Warm off-white, matches #FAF8F1 target — not pure white, not dark. + Chrome: Title "bar-stacked-labeled · julia · makie · anyplot.ai" centered in dark ink, clearly readable but measured at only ~30% of the plot width (undersized relative to the ~50-70% target). Axis labels ("Quarter" / "Revenue ($M)") and tick labels are dark/soft-ink and legible. Legend at right (Subscriptions/Services/Hardware/Support) is frameless, blends with background, text legible. Total labels ($8.7M, $9.4M, $10.6M, $11.9M) bold and clearly visible above each stack. + Data: Four stacked segments per bar — Subscriptions #009E73 (bottom), Services #C475FD, Hardware #4467A3, Support #BD8233 (top). First series confirmed #009E73. + Legibility verdict: PASS (title is legible but proportionally small — flagged as a VQ-05 weakness, not a legibility failure) + + Dark render (plot-dark.png): + Background: Warm near-black, matches #1A1A17 target — not pure black, not light. + Chrome: Title, axis labels, tick labels, legend text, and total labels all flip to light ink (#F0EFE8 / #B8B7B0) and are clearly visible against the dark background. No dark-on-dark failures observed anywhere. + Data: Same four segment colors as the light render, pixel-consistent — only chrome (background/text/grid/legend) changed between themes as required. + Legibility verdict: PASS + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: All chrome and total labels legible in both themes; title is legible + but noticeably undersized + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: No collisions between total labels, gridlines, legend, or bars + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: Bar segments and colors clearly distinguishable at this data density + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Imprint palette provides adequate hue separation, no red-green-only + encoding + - id: VQ-05 + name: Layout & Canvas + score: 3 + max: 4 + passed: true + comment: Title spans only ~30% of plot width vs ~50-70% target; nothing clipped, + canvas exactly 3200x1800 + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Revenue ($M) includes units, Quarter is descriptive + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, canonical Imprint order, correct theme backgrounds, + identical data colors across themes' + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Typographic hierarchy in total labels via rich(), custom palette; + undercut by undersized title + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: Spines removed, y-only subtle grid, generous whitespace, frameless + legend + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Bold total labels create a clear focal point showing the quarter-over-quarter + growth trend + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Correct stacked bar chart + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Total labels above stacks, consistent format, adequate headroom via + ylims! + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X=quarter, Y=stacked revenue by component, all data visible + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches required format; legend labels match and are ordered + to match stack + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: Categories, stacked components, and computed totals all shown + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Quarterly SaaS revenue by product line, plausible and neutral + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: $0.5M-$7.3M segments, $8.7M-$11.9M totals with believable growth + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Flat script, no functions/classes + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Fully deterministic hardcoded data + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: Only CairoMakie and Colors, both used + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Appropriately concise, no fake UI + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-$(THEME).png via current save API + library_mastery: + score: 9 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: Native barplot! stack=/color=/colormap= keywords, high-level Axis/Legend + grammar + - id: LM-02 + name: Distinctive Features + score: 4 + max: 5 + passed: false + comment: rich() mixed-weight text is Makie-specific; no other distinctive + capability exercised + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - annotations + - custom-legend + patterns: + - matrix-construction + - iteration-over-groups + dataprep: [] + styling: + - grid-styling + - publication-ready