Skip to content

feat(plotly): implement ternary-density#7377

Merged
MarkusNeusinger merged 5 commits into
mainfrom
implementation/ternary-density/plotly
May 19, 2026
Merged

feat(plotly): implement ternary-density#7377
MarkusNeusinger merged 5 commits into
mainfrom
implementation/ternary-density/plotly

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: ternary-density - python/plotly

Implements the python/plotly version of ternary-density.

File: plots/ternary-density/implementations/python/plotly.py

Parent Issue: #3696


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 19, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): Warm off-white background (#FAF8F1) hosts a ternary triangle filled with viridis-colored density markers (purple = low density → yellow = high density). Three density hotspots are visible, corresponding to sand-dominant (lower-right), silt-dominant (left), and clay-dominant (lower-left) sediment clusters. White contour lines are present but appear jagged and dotted — the angle-sort approach produces scattered point paths rather than smooth isolines. A colorbar labeled "Density" sits to the right (0.5–4.5 range). Axis labels "Sand (%)", "Silt (%)", "Clay (%)" are clearly readable in dark ink. Title is fully visible. All text is readable against the light background.

Dark render (plot-dark.png): Warm near-black background (#1A1A17) with identical viridis data colors — only chrome flips as expected. Title and axis labels render in light ink, clearly legible. Tick labels visible. No dark-on-dark failures. Contour lines now appear as light-colored jagged paths on the dark surface, still noisy. The three density clusters remain clearly identifiable. Colorbar text and borders adapt correctly to the dark theme. Both renders pass the legibility check.

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

Score: 85/100

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

Visual Quality (27/30)

  • VQ-01: Text Legibility (7/8) — All sizes explicitly set; title is 26px (spec recommends 28px), axis labels 22px, ticks 16px — readable in both themes
  • VQ-02: No Overlap (6/6) — No overlapping elements in the ternary layout
  • VQ-03: Element Visibility (5/6) — Density markers (size=6) form an effective mosaic on the grid; viridis makes density differences clear, but slightly small for a 4800×2700 canvas
  • VQ-04: Color Accessibility (2/2) — Viridis is perceptually uniform and CVD-safe
  • VQ-05: Layout & Canvas (3/4) — Triangle fills ~60–70% of canvas; some corner waste is inherent to the triangular geometry
  • VQ-06: Axis Labels & Title (2/2) — All axes labeled with units: Sand (%), Silt (%), Clay (%)
  • VQ-07: Palette Compliance (2/2) — Viridis for continuous density; backgrounds are #FAF8F1/#1A1A17; chrome is theme-adaptive in both renders

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (4/8) — Well-configured with viridis and theme chrome, but contour lines are noisy and jagged (angle-sort approach produces scattered dots rather than smooth isolines), reducing professional polish significantly
  • DE-02: Visual Refinement (4/6) — template='none', explicit margins, styled colorbar; grid opacity is 0.25, slightly above the recommended 10–15%
  • DE-03: Data Storytelling (4/6) — Three distinct geological clusters create visual hierarchy; viridis draws the eye to density hotspots; no cluster annotations but focal points are identifiable

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct ternary density plot using go.Scatterternary with KDE density coloring and contour overlays
  • SC-02: Required Features (4/4) — Viridis colormap, grid lines beneath density layer, vertex labels with units, contour lines at percentile levels — all present
  • SC-03: Data Mapping (3/3) — a=sand, b=silt, c=clay; Cartesian↔ternary KDE conversion is correct
  • SC-04: Title & Legend (3/3) — Title: Sediment Composition Distribution · ternary-density · python · plotly · anyplot.ai matches required format; colorbar labeled correctly

Data Quality (14/15)

  • DQ-01: Feature Coverage (5/6) — Three clusters cover most of the ternary space with good density variation; minor: clusters could be more spread to cover the full range
  • DQ-02: Realistic Context (5/5) — Sediment composition (sand/silt/clay) is a real geological application; cluster labels (beaches/river channels, floodplains/estuaries, deep lake sediments) are realistic and neutral
  • DQ-03: Appropriate Scale (4/4) — Components normalized to sum to 100%; proportions are geologically plausible

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat script: imports → data → KDE → plot → save; no functions or classes
  • CQ-02: Reproducibility (2/2) — np.random.seed(42)
  • CQ-03: Clean Imports (2/2) — All imports used: os, numpy, plotly.graph_objects, scipy.stats.gaussian_kde
  • CQ-04: Code Elegance (2/2) — Clean Pythonic code; manual contour angle-sort is reasonable for ternary space
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html; current Plotly API

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — go.Scatterternary with colorbar, hovertemplate, and update_layout(ternary={...}) is idiomatic graph_objects usage
  • LM-02: Distinctive Features (3/5) — go.Scatterternary is Plotly-specific; interactive HTML export and custom ternary hover tooltips leverage Plotly's strengths, though contour rendering could use Plotly's native approaches more

Score Caps Applied

  • None applied — no cap conditions triggered (DE-01=4 > 2, DE-02=4 > 2)

Strengths

  • Full spec compliance: KDE overlay, contour lines, vertex labels with units, viridis colormap — every required feature present
  • Theme-adaptive chrome correctly implemented for both light and dark renders with no legibility failures
  • Realistic sediment geology scenario with three distinct, geologically-named clusters
  • Clean flat-script structure with seed, explicit font sizes, and both PNG + HTML output
  • go.Scatterternary is the correct idiomatic Plotly trace for ternary visualization

Weaknesses

  • Contour lines are noisy and jagged — angle-sort on scattered grid points produces dotted irregular paths instead of smooth isolines; use scipy.ndimage.gaussian_filter to smooth the density grid before contouring, or extract contours from the 2D grid and project them back to ternary coordinates using skimage.measure.find_contours
  • Title font size is 26px instead of the recommended 28px
  • Grid opacity is 0.25 (25%), slightly above the recommended 10–15% range

Issues Found

  1. DE-01 REDUCED: Contour lines look like scattered white dots/noise rather than smooth isolines
    • Fix: Smooth the density grid with scipy.ndimage.gaussian_filter(density, sigma=2) before extracting contour levels, then use find_contours from skimage.measure to get clean polylines, or use plotly.figure_factory.create_ternary_contour if appropriate
  2. VQ-01 MINOR: Title font 26px vs recommended 28px
    • Fix: Change title font size to 28
  3. DE-02 MINOR: Grid opacity 0.25 slightly high
    • Fix: Change GRID to "rgba(26,26,23,0.12)" / "rgba(240,239,232,0.12)"

AI Feedback for Next Attempt

The primary issue is the contour rendering: smooth the KDE density array before extracting contours (e.g., scipy.ndimage.gaussian_filter), then use a proper contour-following algorithm (skimage.measure.find_contours) to extract clean polylines and convert them back to ternary coordinates — this will replace the scattered-dot contours with smooth isolines. Also fix the title font to 28px and reduce grid opacity to ~0.12. These changes should push DE-01 from 4 to 6+ and VQ-01 to 8/8.

Verdict: REJECTED

@github-actions github-actions Bot added quality:85 Quality score 85/100 ai-rejected Quality not OK, triggers update labels May 19, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels May 19, 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 May 19, 2026

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): The ternary triangle occupies the center of a warm off-white (#FAF8F1) background. The density is rendered as a dense grid of viridis-colored scatter markers (~100×100 evaluation grid), creating a smooth-looking continuous surface inside the triangle. Three distinct high-density clusters are visible: one near the Sand apex (top), one near the Silt corner (bottom-left), and one near the Clay corner (bottom-right), representing the three geological sediment environments. White contour lines at the 25th, 50th, 75th, and 90th percentile density levels are overlaid, clearly tracing the concentration rings around each cluster. A viridis colorbar labeled "Density" sits to the right of the triangle. The title "Sediment Composition Distribution · ternary-density · python · plotly · anyplot.ai" appears above in dark ink. Axis labels Sand (%), Silt (%), Clay (%) and tick labels at 0/20/40/60/80/100 are all readable in dark text against the light background. All text is legible in the light render.

Dark render (plot-dark.png): The same layout on a warm near-black (#1A1A17) background. The three density clusters are even more visually striking against the dark surface — the viridis yellow-green peaks pop dramatically from the surrounding deep-purple low-density regions. The data colors (viridis scale) are identical to the light render; only the chrome flips. The white contour lines are particularly effective in this theme, clearly delineating the three density modes. The title, axis labels, and tick labels all appear in light text (#F0EFE8 / #B8B7B0 range), passing the dark-on-dark check — no readability failures observed. The colorbar fonts are also theme-adapted. Both paragraphs confirm all text is readable in their respective themes.

Score: 91/100

Category Score Max
Visual Quality 28 30
Design Excellence 14 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 9 10
Total 91 100

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All text readable in both themes; tick font 16px is slightly below the recommended 18px for pixel-based libs
  • VQ-02: No Overlap (5/6) — Minor crowding of tick labels on ternary axes at lower values
  • VQ-03: Element Visibility (6/6) — Density surface and contour lines clearly visible in both themes
  • VQ-04: Color Accessibility (2/2) — Viridis is perceptually uniform and colorblind-safe
  • VQ-05: Layout & Canvas (4/4) — 4800×2700 px (1600×900 × scale=3), good proportions, nothing cut off
  • VQ-06: Axis Labels & Title (2/2) — Sand (%), Silt (%), Clay (%) with units; descriptive title
  • VQ-07: Palette Compliance (2/2) — Viridis used for continuous density data (correct); backgrounds #FAF8F1 / #1A1A17 ✓

Design Excellence (14/20)

  • DE-01: Aesthetic Sophistication (6/8) — Viridis density surface + white contour lines at percentile levels + themed colorbar show deliberate design choices; well above generic defaults
  • DE-02: Visual Refinement (4/6) — template="none" removes Plotly defaults; subtle GRID token; styled colorbar with themed fonts, border, and background; ternary background matches page surface
  • DE-03: Data Storytelling (4/6) — Three clusters map to distinct real-world sediment environments (beach, floodplain, deep lake); contour lines guide viewer to concentration peaks; viridis gradient naturally encodes relative density

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct ternary density chart using go.Scatterternary with KDE-colored markers
  • SC-02: Required Features (4/4) — KDE via gaussian_kde, contour lines at 25/50/75/90th percentiles, vertex labels, visible grid lines ✓
  • SC-03: Data Mapping (3/3) — Sand/silt/clay correctly mapped to ternary axes; all values normalized to sum to 100%
  • SC-04: Title & Legend (3/3) — Title matches {Descriptive} · ternary-density · python · plotly · anyplot.ai; colorbar labeled "Density" ✓

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Three geologically distinct clusters demonstrate all aspects: sand-dominant (beaches/channels), silt-dominant (floodplains), clay-dominant (deep lake sediments)
  • DQ-02: Realistic Context (5/5) — Sediment composition is a canonical ternary dataset from geoscience; cluster parameters are geologically plausible
  • DQ-03: Appropriate Scale (4/4) — 500 samples within the 100–5000 recommended range; values 0–100% summing to 100% per constraint

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat script, no functions or classes
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set
  • CQ-03: Clean Imports (2/2) — All imports are used; matplotlib for contour extraction, scipy for KDE and smoothing
  • CQ-04: Code Elegance (2/2) — The matplotlib contour extraction trick (ax_tmp.contour / plt.close) is a legitimate data-extraction pattern, not fake UI
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png (4800×2700) and plot-{THEME}.html

Library Mastery (9/10)

  • LM-01: Idiomatic Usage (5/5) — go.Scatterternary is the correct Plotly trace for ternary coordinates; layout ternary dict is properly configured
  • LM-02: Distinctive Features (4/5) — Colorbar within marker dict, hovertemplate with ternary coordinate formatting, HTML export; slight deduction because contour computation relies on matplotlib rather than a Plotly-native approach

Score Caps Applied

  • None

Strengths

  • Perfect spec compliance: KDE, contour lines at percentile levels, vertex labels, grid, and density colormap all delivered
  • Geologically realistic three-cluster dataset (beach/floodplain/deep-lake) makes excellent use of the sediment composition context
  • Theme-adaptive chrome correctly applied across all elements: title, axis labels, tick fonts, colorbar, backgrounds
  • Flat canvas size (4800×2700) and font sizes within spec
  • Matplotlib used only for data extraction (contour paths), with plt.close() properly called — no fake interactivity

Weaknesses

  • Tick font size is 16px vs recommended 18px for pixel-based libraries — minor readability reduction at full canvas
  • White contour color (rgba(255,255,255,0.85)) in the light theme has variable contrast against the bright viridis regions; a near-black semi-transparent color would maintain contrast across both light and dark themes more robustly
  • Scatter-marker density approach creates a slightly dotted texture rather than a fully smooth continuous heatmap surface; using a triangulated contourf approach (if achievable in Plotly's ternary system) would be more polished

Issues Found

  1. VQ-01 MINOR: Tick font size 16px is below the 18px recommended for pixel-based libraries at 4800×2700
    • Fix: Change "tickfont": {"size": 16, ...} to "size": 18 on all three ternary axes
  2. DE-02 MINOR: White contour lines in light theme have inconsistent contrast across the viridis spectrum
    • Fix: Use "rgba(30,20,40,0.8)" (dark semi-transparent) for light theme contours instead of white; white remains good for dark theme

AI Feedback for Next Attempt

Implementation is strong and spec-compliant. Two targeted improvements: (1) raise tick font from 16px to 18px on all ternary axes; (2) use a dark semi-transparent contour color for the light theme to ensure consistent legibility across the full viridis range. Everything else — KDE, clustering, theming, canvas size, title format — is correct and should be preserved.

Verdict: APPROVED

@github-actions github-actions Bot added quality:91 Quality score 91/100 ai-approved Quality OK, ready for merge and removed quality:85 Quality score 85/100 labels May 19, 2026
@MarkusNeusinger MarkusNeusinger merged commit 7b7203d into main May 19, 2026
@MarkusNeusinger MarkusNeusinger deleted the implementation/ternary-density/plotly branch May 19, 2026 10:49
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:91 Quality score 91/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant