Skip to content

feat(pygal): implement sankey-basic#5606

Merged
MarkusNeusinger merged 6 commits intomainfrom
implementation/sankey-basic/pygal
Apr 30, 2026
Merged

feat(pygal): implement sankey-basic#5606
MarkusNeusinger merged 6 commits intomainfrom
implementation/sankey-basic/pygal

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: sankey-basic - python/pygal

Implements the python/pygal version of sankey-basic.

File: plots/sankey-basic/implementations/python/pygal.py

Parent Issue: #810


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 30, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): The plot displays a Sankey diagram on a warm off-white #FAF8F1 background. Title reads "Energy Distribution · sankey-basic · pygal · anyplot.ai" in dark ink at the top center. Four source nodes appear on the left (Coal, Natural Gas, Nuclear, Renewables) as colored rectangles using Okabe-Ito colors — Coal in brand green #009E73, Natural Gas in vermillion #D55E00, Nuclear in blue #0072B2, Renewables in reddish-purple #CC79A7. Five target nodes on the right (Residential, Commercial, Industrial, Transportation) use a muted grey. Flow ribbons are semi-transparent (0.40 alpha) bezier curves showing energy distribution. Node labels appear in dark ink with value annotations below (e.g., "38 TWh"). All text is clearly readable against the light background. Legibility verdict: PASS.

Dark render (plot-dark.png): Same layout on a near-black #1A1A17 background. Title and all node labels render in light cream/off-white text — clearly readable against the dark surface. No dark-on-dark text failures observed. Source node rectangle colors are identical to the light render (Coal=#009E73, Gas=#D55E00, Nuclear=#0072B2, Renewables=#CC79A7). The semi-transparent flow ribbons appear visually darker due to compositing over the near-black background, but the underlying hex values are the same. Target node rectangles use the muted grey token. Chrome flips correctly: background, text, and label colors are all theme-adapted. Legibility verdict: PASS.

Both paragraphs are required. A review that only describes one render is invalid.

Score: 80/100

Category Score Max
Visual Quality 30 30
Design Excellence 12 20
Spec Compliance 15 15
Data Quality 14 15
Code Quality 7 10
Library Mastery 2 10
Total 80 100

Visual Quality (30/30)

  • VQ-01: Text Legibility (8/8) — Font sizes explicitly set (title 48px, labels 38px, values 28px); all text readable at full resolution in both themes
  • VQ-02: No Overlap (6/6) — Source labels left-aligned, target labels right-aligned; no collisions
  • VQ-03: Element Visibility (6/6) — Flow ribbons and node rectangles clearly visible; 0.40 alpha appropriate for crossing flows
  • VQ-04: Color Accessibility (2/2) — Okabe-Ito palette; CVD-safe
  • VQ-05: Layout & Canvas (4/4) — Diagram fills most of the 4800×2700 canvas; margins well-balanced
  • VQ-06: Axis Labels & Title (2/2) — Descriptive title; node labels include TWh values
  • VQ-07: Palette Compliance (2/2) — First source uses #009E73; Okabe-Ito order maintained; backgrounds are #FAF8F1/#1A1A17; chrome is theme-adaptive in both renders

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Intentional color hierarchy: colorful sources vs. muted-grey targets is a deliberate design choice that aides orientation. Clean typographic hierarchy. Above defaults but not publication-ready level.
  • DE-02: Visual Refinement (4/6) — No axes, no grid, generous margins, clean node+label placement. Missing deeper polish (e.g., subtle node borders, tighter white-gap lines inside flows).
  • DE-03: Data Storytelling (3/6) — Flow proportions communicate magnitude, but no emphasis highlights dominant pathways (e.g., Coal→Industrial or Gas→Residential). Viewer must hunt for the key story.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct Sankey diagram with proportional flow widths
  • SC-02: Required Features (4/4) — Source/target nodes, labeled with values, proportional ribbons, no circular flows, distinct source colors
  • SC-03: Data Mapping (3/3) — Sources left, targets right; flow widths scale with TWh values
  • SC-04: Title & Legend (3/3) — Title format Energy Distribution · sankey-basic · pygal · anyplot.ai ✓; no legend needed (colors defined by labeled nodes)

Data Quality (14/15)

  • DQ-01: Feature Coverage (5/6) — Shows 4 sources × 5 targets with 14 flows; varied magnitudes. Slightly missing: extreme skew or a near-zero flow to demonstrate boundary behavior.
  • DQ-02: Realistic Context (5/5) — Energy distribution (Coal/Gas/Nuclear/Renewables → Residential/Commercial/Industrial/Transportation) is an exemplary real-world Sankey scenario
  • DQ-03: Appropriate Scale (4/4) — TWh values are plausible; source totals (38+58+30+23=149) equal destination totals (47+42+53+7=149) — mass-balanced ✓

Code Quality (7/10)

  • CQ-01: KISS Structure (1/3) — Defines a hex_to_rgba helper function that is never called (dead code); the conversion is duplicated inline in the flow loop. KISS requires no functions.
  • CQ-02: Reproducibility (2/2) — Fully deterministic; no random data generation
  • CQ-03: Clean Imports (2/2) — All imports are used (os, sys, cairosvg, Style)
  • CQ-04: Code Elegance (1/2) — hex_to_rgba is dead code; the _style Style object is created but its attributes are never accessed (it only serves as documentation); sys.path manipulation adds complexity
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html correctly

Library Mastery (2/10)

  • LM-01: Idiomatic Usage (1/5) — No pygal chart class is ever instantiated. Only from pygal.style import Style is used, and even that Style object's attributes are never read back. The entire diagram is hand-crafted SVG strings converted via cairosvg. This completely bypasses pygal's chart API.
  • LM-02: Distinctive Features (1/5) — No pygal-specific chart features leveraged. The implementation is pure manual SVG; cairosvg is used for rasterization but that is not a pygal feature.

Score Caps Applied

  • None — no score caps triggered

Strengths

  • Visually polished Sankey with correct proportional flows and clear source/target color hierarchy
  • Perfect spec compliance: balanced mass (source totals = target totals), real-world energy domain, all nodes labeled with TWh values
  • Full theme-adaptive chrome: both light and dark renders pass legibility checks

Weaknesses

  • Library Mastery severely undermined: pygal has no Sankey chart class, but the implementation compensates by writing raw SVG instead of using any pygal chart API. Only pygal.style.Style is imported (and not even used idiomatically).
  • Dead code: hex_to_rgba is defined but never called; inline conversion is used instead
  • DE-03 low: No emphasis on dominant flows — the Coal→Industrial and Gas→Residential pathways are the largest but nothing visually highlights them
  • _style object is unused: Created for "palette consistency validation" per the comment but its values are never read; the theme tokens are computed separately above it

Issues Found

  1. LM-01 / LM-02 CRITICAL: pygal chart API not used at all — only Style is imported
    • Fix: Pygal doesn't have a native Sankey, but consider using pygal.Treemap or pygal.StackedBar as a visual approximation, OR document the workaround more clearly and use cairosvg's HTML output as a pygal-style interactive alternative
  2. CQ-01 / CQ-04: Remove dead hex_to_rgba function; replace inline duplication with the function or eliminate one
  3. DE-03 LOW: No visual hierarchy on the dominant flows
    • Fix: Highlight the top 2-3 flows (e.g., increase opacity or add a subtle stroke) to draw the eye to the most significant energy pathways
  4. _style dead object: Either remove it or attach it to a pygal chart

AI Feedback for Next Attempt

The Sankey renders beautifully but the implementation nearly bypasses pygal entirely — only from pygal.style import Style is used, and that object is never queried. Since pygal has no native Sankey, consider using a pygal.StackedBar or pygal.HorizontalStackedBar chart as a legitimate approximation that uses the actual pygal chart API, while still communicating source-to-target distribution. Alternatively, if keeping the raw SVG approach, route the SVG string through pygal.graph.base.BaseGraph's render pipeline. Also: remove the dead hex_to_rgba function, remove the unused _style variable, and add visual emphasis (higher opacity or subtle stroke) to the top 2-3 dominant flows for better data storytelling.

Verdict: REJECTED

@github-actions github-actions Bot added quality:80 Quality score 80/100 ai-rejected Quality not OK, triggers update labels Apr 30, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels Apr 30, 2026
Attempt 1/3 - fixes based on AI review
@github-actions
Copy link
Copy Markdown
Contributor Author

🔧 Repair Attempt 1/4

Applied fixes based on AI review feedback.

Status: Repair completed, re-triggering review...


🤖 impl-repair

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 30, 2026

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): A Sankey diagram on a warm off-white (#FAF8F1) background titled "Energy Distribution · sankey-basic · pygal · anyplot.ai". Four source nodes (Coal, Natural Gas, Nuclear, Renewables) appear on the left column in Okabe-Ito colors — Coal in green (#009E73), Natural Gas in orange-red (#D55E00), Nuclear in blue (#0072B2), Renewables in pink (#CC79A7). Four target nodes (Residential, Commercial, Industrial, Transportation) appear on the right column in a neutral grey (INK_SOFT). Bezier ribbon flows connect sources to targets with proportional widths. Dominant flows (≥20 TWh) render at 0.72 alpha with value annotations ("22 TWh", "25 TWh") centered in the ribbon; smaller flows render at 0.38 alpha as background layer. Node labels show name and total TWh on separate lines with clear typographic hierarchy. All text — title, node names, value subtexts, and flow annotations — is clearly readable against the light background with dark ink. Legibility verdict: PASS.

Dark render (plot-dark.png): The same Sankey structure on a warm near-black (#1A1A17) background. Title and node labels switch to light ink (#F0EFE8) — fully readable against the dark surface. Data colors for the four source nodes are identical to the light render (same green, orange-red, blue, pink for Coal/Gas/Nuclear/Renewables), confirming only chrome flips between themes. The semi-transparent flows create a glowing luminous effect on the dark background, which enhances visual depth. The "22 TWh" and "25 TWh" dominant-flow annotations remain visible in light ink on top of the colored ribbons. Target node bars in INK_SOFT (#B8B7B0) are distinguishable against the near-black background. No dark-on-dark failures observed. Legibility verdict: PASS.

Both paragraphs are required. A review that only describes one render is invalid.

Score: 85/100

Category Score Max
Visual Quality 29 30
Design Excellence 13 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 3 10
Total 85 100

Visual Quality (29/30)

  • VQ-01: Text Legibility (8/8) — All font sizes explicitly set: title 48px, node labels 38px, value subtexts 28px — all above minimum recommendations. Readable at full resolution in both themes.
  • VQ-02: No Overlap (6/6) — Node labels well-spaced on both sides; "22 TWh" and "25 TWh" annotations positioned at ribbon midpoints without collision.
  • VQ-03: Element Visibility (5/6) — Flow ribbons are clearly visible. Minor flows (e.g., Gas→Transportation, 3 TWh) produce thin but distinguishable ribbons; appropriate for the data values.
  • VQ-04: Color Accessibility (2/2) — Okabe-Ito palette is CVD-safe. Differential opacity (0.72 dominant, 0.38 minor) aids distinguishability beyond hue alone.
  • VQ-05: Layout & Canvas (4/4) — Diagram spans ~81% of canvas width with balanced margins (L:400, R:440, T:220, B:130). Nodes span ~75% of canvas height. Canvas utilization is efficient.
  • VQ-06: Axis Labels & Title (2/2) — No traditional axes (appropriate for Sankey). Node labels include TWh totals; title is descriptive and includes required spec/library/site format.
  • VQ-07: Palette Compliance (2/2) — First source (Coal) correctly uses #009E73. Multi-source follows Okabe-Ito order (#D55E00, #0072B2, #CC79A7). Target nodes use neutral INK_SOFT (appropriate — not data categories). Backgrounds are #FAF8F1 light / #1A1A17 dark. Both renders theme-correct.

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Intentional design beyond defaults: differential opacity creates visual hierarchy (dominant flows pop); Okabe-Ito for sources + neutral for targets shows considered color strategy; rounded node rectangles (rx=5) add polish; annotations restricted to dominant flows show editorial restraint. Above "library default" (4/8) but not yet at "strong design" (6/8).
  • DE-02: Visual Refinement (4/6) — No unnecessary chrome (no grid, no axes). Explicit margins. Layer ordering (non-dominant drawn first, dominant on top). Font-weight differentiation (600 title, 500 node names, normal subtexts). Missing: some additional whitespace or node gap tuning could further breathe.
  • DE-03: Data Storytelling (4/6) — Opacity differentiation immediately draws the viewer's eye to Coal→Industrial (25 TWh) and Gas→Residential (22 TWh) as the dominant energy pathways. Annotations provide quantitative grounding for the dominant flows. The story (fossil fuels dominate industry and residential sectors) is visually legible without text explanation.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct Sankey diagram with source nodes, target nodes, proportional-width flow ribbons, and Bezier curves.
  • SC-02: Required Features (4/4) — Node labels with values, proportional flow widths, distinct source colors, link opacity variation, no circular flows, labels positioned without overlapping links.
  • SC-03: Data Mapping (3/3) — All 14 flows correctly mapped from 4 sources to 4 targets with proportional ribbon widths. Node totals balance (149 TWh source = 149 TWh target).
  • SC-04: Title & Legend (3/3) — Title "Energy Distribution · sankey-basic · pygal · anyplot.ai" contains the required format. No legend needed (nodes are self-labeling).

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all Sankey features: multiple sources, multiple targets, full cross-connectivity (14 flows), varying flow magnitudes from 3 TWh (minor) to 25 TWh (dominant), proportional node sizing.
  • DQ-02: Realistic Context (5/5) — Real-world energy distribution scenario: Coal/Gas/Nuclear/Renewables → Residential/Commercial/Industrial/Transportation. Neutral, comprehensible, science domain.
  • DQ-03: Appropriate Scale (4/4) — Values are internally consistent (source totals = target totals = 149 TWh). Proportions are plausible: Natural Gas largest source (58 TWh), Industrial largest consuming sector (53 TWh), Transportation smallest (7 TWh, mostly Gas + Renewables).

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Linear flow: imports → style tokens → data → layout computation → SVG generation → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — All data is hardcoded; completely deterministic.
  • CQ-03: Clean Imports (2/2) — os, sys, cairosvg, pygal.style.Style — all explicitly used.
  • CQ-04: Code Elegance (2/2) — SVG generation is appropriately complex given pygal lacks a native Sankey type. sys.path manipulation is necessary to avoid shadowing the pygal package with this script's filename. No over-engineering or fake UI.
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html correctly.

Library Mastery (3/10)

  • LM-01: Idiomatic Usage (2/5) — Only pygal.style.Style is used from pygal; the actual chart is built as raw SVG strings rendered via cairosvg. This bypasses pygal's entire chart class API. Minimal library usage.
  • LM-02: Distinctive Features (1/5) — pygal's signature features (interactive SVG with embedded JS, hover tooltips, animations, per-point metadata) are not used. The HTML file is an SVG wrapper, not a pygal-generated interactive chart. Generic SVG/cairosvg approach.

Score Caps Applied

  • None — no caps triggered (DE-01=5 and DE-02=4, both above the DE ≤2 threshold).

Strengths

  • Excellent spec and data compliance: all 14 flows correct, balanced node totals, realistic energy domain.
  • Intentional opacity hierarchy (0.72 dominant / 0.38 minor) creates a clear visual narrative.
  • Theme-adaptive chrome is fully correct in both light and dark renders with zero dark-on-dark failures.
  • Editorial annotations (value labels only on dominant flows) show design restraint.
  • All font sizes explicitly set and above minimum for this canvas size.

Weaknesses

  • Library mastery is minimal: pygal is used only as a style-token provider; its chart classes, JS interactivity, and distinctive features (hover tooltips, animations) are completely bypassed.
  • Design Excellence could be pushed further: additional whitespace/node gap tuning and typography refinement would lift DE-02 from 4 to 6.
  • Very thin flows (3–4 TWh, Transportation column) are visible but at the edge of readability — slightly larger NODE_W or higher base alpha for minor flows would help.

Issues Found

  1. LM-01/LM-02 LOW: Implementation uses only pygal.style.Style — pygal's chart API, JS interactivity, hover tooltips, and animations are completely absent.
    • Fix: Where feasible, leverage pygal's distinctive interactive output or at minimum use more of its chart configuration API.
  2. DE-02 PARTIAL: Node gaps and whitespace work but could be more generous; font hierarchy is good but title weight could be stronger.
    • Fix: Increase NODE_GAP slightly, bump title font-weight to 700 for stronger hierarchy.

AI Feedback for Next Attempt

The core implementation is strong (85/100). Primary gap is library mastery — only pygal.style.Style is used, bypassing all of pygal's chart classes and interactive features. If attempting a repair, focus on (1) increasing library engagement (even partial use of pygal's SVG rendering pipeline or config API), and (2) minor visual refinement (title weight 700, slightly more generous node gaps). The visual design, theme handling, data, and spec compliance are all high quality and should be preserved.

Verdict: APPROVED

@github-actions github-actions Bot added quality:85 Quality score 85/100 ai-approved Quality OK, ready for merge labels Apr 30, 2026
@MarkusNeusinger MarkusNeusinger merged commit 1131d84 into main Apr 30, 2026
3 checks passed
@MarkusNeusinger MarkusNeusinger deleted the implementation/sankey-basic/pygal branch April 30, 2026 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-approved Quality OK, ready for merge ai-attempt-1 First repair attempt quality:80 Quality score 80/100 quality:85 Quality score 85/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant