Skip to content

update(bubble-packed): seaborn — comprehensive quality review#4359

Merged
github-actions[bot] merged 4 commits intomainfrom
implementation/bubble-packed/seaborn
Feb 23, 2026
Merged

update(bubble-packed): seaborn — comprehensive quality review#4359
github-actions[bot] merged 4 commits intomainfrom
implementation/bubble-packed/seaborn

Conversation

@MarkusNeusinger
Copy link
Copy Markdown
Owner

Summary

Updated seaborn implementation for bubble-packed.

Changes: Comprehensive quality review

Changes

  • Renamed data dict to sectors for clarity
  • Removed unused matplotlib.patches import
  • Simplified circle packing logic
  • Removed unnecessary random seed (deterministic data)

Test Plan

  • Preview images uploaded to GCS staging
  • Implementation file passes ruff format/check
  • Metadata YAML updated with current versions
  • Automated review triggered

Generated with Claude Code /update command

Copilot AI review requested due to automatic review settings February 23, 2026 15:40
Comprehensive review improving code quality, data choice, visual design,
spec compliance, and library feature usage.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR performs a comprehensive quality review of the bubble-packed seaborn implementation, refactoring the code for improved clarity and maintainability while updating dependencies.

Changes:

  • Refactored circle packing algorithm to use more efficient vectorized operations with NumPy arrays
  • Renamed data dictionary to sectors for better semantic clarity
  • Simplified labeling logic by removing complex external annotation system in favor of simpler truncation
  • Updated metadata with current Python version (3.14.3) and tooling (claude-opus-4-6)

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
plots/bubble-packed/metadata/seaborn.yaml Updated metadata with new Python version, generated_by, and updated timestamp; set quality_score to null for re-evaluation
plots/bubble-packed/implementations/seaborn.py Comprehensive refactor: improved circle packing algorithm with vectorization, simplified labeling, enhanced legend with circular markers, added descriptive title, removed unused imports

edgecolor="gray",
)

sns.despine(left=True, bottom=True)
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sns.despine(left=True, bottom=True) call on line 153 is ineffective because ax.axis("off") on line 125 already removes all spines and ticks. The despine call should either be removed as redundant, or if you want to keep axes labels/ticks while removing spines, remove the axis("off") call and use despine with appropriate parameters.

Suggested change
sns.despine(left=True, bottom=True)

Copilot uses AI. Check for mistakes.
Library: seaborn 0.13.2 | Python 3.13.11
Quality: 90/100 | Created: 2025-12-23
Library: seaborn 0.13.2 | Python 3.14.3
Quality: /100 | Updated: 2026-02-23
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header format should use "Created" instead of "Updated" when there's no quality score. Following the KISS principle in the coding guidelines, plot implementations should have a 4-line docstring header. Looking at other implementations in the codebase (e.g., plots/raincloud-basic/implementations/matplotlib.py, plots/circlepacking-basic/implementations/plotly.py), the pattern is:

"""pyplots.ai
{spec-id}: {Title}
Library: {library} {version} | Python {version}
Quality: {score}/100 | Created: {date}
"""

Since this is a comprehensive quality review update (not a new file), and the quality_score is null in metadata, the header should likely say "Created" with the original date, not "Updated" with a new date.

Suggested change
Quality: /100 | Updated: 2026-02-23
Quality: /100 | Created: 2026-02-23

Copilot uses AI. Check for mistakes.
Library: seaborn 0.13.2 | Python 3.13.11
Quality: 90/100 | Created: 2025-12-23
Library: seaborn 0.13.2 | Python 3.14.3
Quality: /100 | Updated: 2026-02-23
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quality score placeholder shows "/100" with no number. Looking at the metadata file, quality_score is null. According to the coding guidelines, the header format should include "Quality: XX/100". Either remove this line entirely if quality_score is null, or use a placeholder like "Quality: pending" to indicate it hasn't been scored yet, rather than showing an incomplete fraction.

Suggested change
Quality: /100 | Updated: 2026-02-23
Quality: pending | Updated: 2026-02-23

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +90
# Compute scatter marker sizes: convert data-unit diameter to points^2
# At dpi=100 (default), figsize=(16,9) => 1600x900 pixels for the figure
# With aspect="equal", the effective data range that fits is limited by the smaller axis
fig.canvas.draw()
transform = ax.transData
# Get scale: how many display points per data unit
p0 = transform.transform((0, 0))
p1 = transform.transform((1, 0))
pts_per_unit = (p1[0] - p0[0]) * 72 / fig.dpi # convert pixels to points
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The marker size calculation uses fig.canvas.draw() to initialize the transformation, then computes points per unit. This approach works but adds unnecessary rendering overhead. Consider a simpler calculation: given the figure size in inches and DPI, you can compute the data-to-points transformation directly without the draw call. For example, pts_per_unit = (fig.get_size_inches()[0] * fig.dpi) / plot_w * 72 / fig.dpi simplifies to (fig.get_size_inches()[0] * 72) / plot_w.

Suggested change
# Compute scatter marker sizes: convert data-unit diameter to points^2
# At dpi=100 (default), figsize=(16,9) => 1600x900 pixels for the figure
# With aspect="equal", the effective data range that fits is limited by the smaller axis
fig.canvas.draw()
transform = ax.transData
# Get scale: how many display points per data unit
p0 = transform.transform((0, 0))
p1 = transform.transform((1, 0))
pts_per_unit = (p1[0] - p0[0]) * 72 / fig.dpi # convert pixels to points
# Compute scatter marker sizes: convert data-unit diameter to points^2.
# We know the horizontal data range (0 → plot_w) and the figure width in inches,
# so we can compute points-per-data-unit directly without triggering a draw.
pts_per_unit = (fig.get_size_inches()[0] * 72) / plot_w

Copilot uses AI. Check for mistakes.
created: '2025-12-23T09:17:35Z'
updated: '2025-12-23T09:33:29Z'
generated_by: claude-opus-4-5-20251101
updated: 2026-02-23T15:35:00+00:00
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The date format uses +00:00 instead of the standard Z suffix for UTC timezone. Looking at other metadata files in the codebase (e.g., plots/band-basic/metadata/matplotlib.yaml), the consistent pattern is to use Z for UTC times. Change 2026-02-23T15:35:00+00:00 to 2026-02-23T15:35:00Z for consistency.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +8 to +9
python_version: "3.14.3"
library_version: "0.13.2"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The python_version and library_version fields use quoted strings, which is inconsistent with the codebase convention. Looking at recent metadata files (e.g., plots/bubble-basic/metadata/seaborn.yaml, plots/heatmap-basic/metadata/seaborn.yaml), the consistent pattern is to use unquoted version numbers. Change "3.14.3" to 3.14.3 and "0.13.2" to 0.13.2.

Copilot generated this review using guidance from repository custom instructions.
ax.set_aspect("equal")
fs, max_chars = 8, 7
if len(label) > max_chars:
label = label[: max_chars - 1] + "."
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Label truncation logic has an off-by-one issue. When a label exceeds max_chars, the code uses label[: max_chars - 1] + ".", which results in labels that are max_chars characters long (not max_chars - 1). For example, if max_chars=12 and label="Microsoft" (9 chars), it passes unchanged. But if label="Mastercard" (10 chars > 7), with max_chars=7, it becomes "Master." (7 chars), but the actual cut is at position 6. This inconsistency could be confusing. Consider either: (1) using label[:max_chars-1] + "." and document that the result is max_chars long, or (2) using label[:max_chars] + "." and document that the result may be max_chars+1 long.

Suggested change
label = label[: max_chars - 1] + "."
label = label[:max_chars] + "."

Copilot uses AI. Check for mistakes.
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 23, 2026

AI Review - Attempt 1/3

Image Description

The plot displays a packed bubble chart titled "Market Capitalization by Sector" with the subtitle "bubble-packed · seaborn · pyplots.ai". There are 17 circles of varying sizes representing companies, packed tightly together without overlap on a white background. Each bubble contains the company name in bold white text with adaptive font sizing. The bubbles are color-coded by sector using pastel Set2 colors: Technology (teal/green) includes Apple (largest), Microsoft, Google, NVIDIA, and Meta; Finance (coral/orange) includes JPMorgan, Visa, Mastercard, and Goldman Sachs (truncated to "Goldman S"); Healthcare (lavender/purple) includes UnitedHealth, J&J, Merck, and Pfizer; Retail (pink) includes Amazon, Walmart, Costco, and Target (smallest). White edge lines (linewidth=3) separate adjacent bubbles. The axes are hidden. A legend at the bottom center shows all four sectors with circular markers and a "Sector" title. The bubbles are well-packed in the center of the canvas.

Score: 79/100

Category Score Max
Visual Quality 26 30
Design Excellence 12 20
Spec Compliance 15 15
Data Quality 13 15
Code Quality 9 10
Library Mastery 4 10
Total 79 100

Visual Quality (26/30)

  • VQ-01: Text Legibility (7/8) — Font sizes explicitly set throughout (title 24pt, adaptive bubble labels 8-18pt, legend 14-16pt). All readable, though smallest bubbles have tight text.
  • VQ-02: No Overlap (5/6) — No text-on-text overlap between elements. Some labels tight within their bubbles; "Goldman S" truncated to fit.
  • VQ-03: Element Visibility (6/6) — Bubbles well-sized with clear differentiation from ~30 to ~180 value range. Alpha=0.9 and white edgecolor=3 provide excellent separation.
  • VQ-04: Color Accessibility (3/4) — Set2 is generally colorblind-friendly, but the pink (Retail) and coral (Finance) distinction may challenge deuteranopia users.
  • VQ-05: Layout & Canvas (3/4) — Good canvas utilization with bubbles filling the center. Legend well-positioned. Slight vertical elongation from aspect="equal" on landscape figsize.
  • VQ-06: Axis Labels & Title (2/2) — Descriptive title with context. Axes appropriately hidden for packed bubble chart.

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above defaults: pleasant Set2 pastels, white edge borders creating clean separation, bold white in-bubble text with adaptive sizing. Not yet publication-quality custom design.
  • DE-02: Visual Refinement (4/6) — Axes off, no grid (appropriate), white background, white edge lines, despine applied. Clean and refined presentation.
  • DE-03: Data Storytelling (3/6) — Size hierarchy clearly shows tech sector dominance. Color grouping tells a basic sectoral story. No explicit emphasis, annotations, or focal point guiding the viewer to a specific insight.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct packed bubble chart with greedy circle packing algorithm.
  • SC-02: Required Features (4/4) — Area scales with value (sqrt for radius), labels inside circles with adaptive sizing, color encodes sector membership, circles packed without overlap.
  • SC-03: Data Mapping (3/3) — Circle area proportional to value, all 17 companies visible with correct relative sizes.
  • SC-04: Title & Legend (3/3) — Title format correct with "bubble-packed · seaborn · pyplots.ai". Legend shows all 4 sectors with matching colors and "Sector" title.

Data Quality (13/15)

  • DQ-01: Feature Coverage (5/6) — 17 companies across 4 sectors with good size range (30-180). Demonstrates packed layout well. Could show more extreme variation.
  • DQ-02: Realistic Context (5/5) — Market capitalization by sector is a realistic, neutral business scenario with recognizable company names.
  • DQ-03: Appropriate Scale (3/4) — Relative ordering is sensible (Apple > Microsoft > Amazon). Values labeled "billions USD" are plausible as synthetic data, though significantly below actual current market caps.

Code Quality (9/10)

  • CQ-01: KISS Structure (3/3) — Linear flow: imports → data → packing → plot → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — Fully deterministic: hardcoded data and deterministic packing algorithm.
  • CQ-03: Clean Imports (2/2) — All four imports (matplotlib, numpy, pandas, seaborn) are used.
  • CQ-04: Code Elegance (1/2) — Marker size conversion (data-to-points transform via canvas drawing) is complex. Packing algorithm is verbose but necessary for this chart type.
  • CQ-05: Output & API (1/1) — Saves as plot.png at dpi=300. Uses current seaborn API.

Library Mastery (4/10)

  • LM-01: Idiomatic Usage (3/5) — Uses sns.set_theme(), sns.scatterplot() with hue mapping, sns.color_palette(), sns.despine(). However, the bulk of the implementation is custom numpy/matplotlib code for circle packing and marker sizing.
  • LM-02: Distinctive Features (1/5) — Seaborn is used mainly as a rendering layer for the scatter markers. The circle packing is entirely custom code. This implementation could be trivially ported to any library.

Score Caps Applied

  • None — no criteria triggered score caps

Strengths

  • Excellent spec compliance — correct packed bubble chart with proper area scaling, labels, grouping, and packing
  • Good data choice — realistic market cap scenario with recognizable companies and neutral topic
  • Clean visual separation — white edge borders and adaptive font sizing inside bubbles work well
  • Deterministic and reproducible — no randomness in data or packing algorithm

Weaknesses

  • Library Mastery is low — seaborn is mostly used as a thin rendering layer over custom numpy/matplotlib code
  • Design could be more sophisticated — Set2 is a standard palette, not a custom cohesive color scheme
  • No data storytelling emphasis — no focal point, annotation, or visual hierarchy guiding the viewer to an insight
  • Pink/coral color distinction could challenge colorblind users
  • Marker size computation is overly complex with manual canvas transform calculations

Issues Found

  1. LM-02 LOW: Seaborn used generically — the core visualization (circle packing, positioning, sizing) is all custom numpy/matplotlib code with seaborn only calling scatterplot
    • Fix: Leverage more seaborn-specific features like sns.set_context for scaling, or use seaborn's statistical capabilities if applicable
  2. DE-01 MODERATE: Set2 palette is pleasant but generic — no custom color scheme or intentional visual hierarchy
    • Fix: Consider a custom palette with more contrast between sectors, perhaps starting with Python Blue (#306998) for the primary sector
  3. DE-03 LOW: No storytelling emphasis — all bubbles presented equally without guiding the viewer
    • Fix: Add value annotations inside larger bubbles, or use color intensity to create a focal point on a key insight (e.g., tech dominance)
  4. VQ-04 MINOR: Pink and coral colors may be hard to distinguish for colorblind users
    • Fix: Use a palette with more distinct hues between all categories (e.g., colorblind palette or custom high-contrast selection)

AI Feedback for Next Attempt

Improve Library Mastery: try to leverage seaborn's distinctive features more (e.g., use seaborn's palette generation more creatively, or use set_context/set_style for more polished defaults). Improve Design Excellence: use a custom palette starting with #306998 (Python Blue) for better brand coherence and contrast. Add value labels (e.g., "$180B") inside larger bubbles for data storytelling. Consider using the colorblind palette or a high-contrast custom palette to improve accessibility. Simplify the marker size computation if possible.

Verdict: REJECTED

@github-actions github-actions Bot added quality:79 Quality score 79/100 ai-rejected Quality not OK, triggers update labels Feb 23, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels Feb 23, 2026
Attempt 1/3 - fixes based on AI review
Copilot AI review requested due to automatic review settings February 23, 2026 15:59
@MarkusNeusinger MarkusNeusinger review requested due to automatic review settings February 23, 2026 15:59
@github-actions
Copy link
Copy Markdown
Contributor

🔧 Repair Attempt 1/3

Applied fixes based on AI review feedback.

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


🤖 impl-repair

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 23, 2026

AI Review - Attempt 2/3

Image Description

The plot displays a packed bubble chart titled "Market Capitalization by Sector" with the subtitle "bubble-packed · seaborn · pyplots.ai". Seventeen circles of varying sizes represent company market capitalizations in billions USD, packed together without overlap on a white background. Four sectors are color-coded: Technology (steel blue) — Apple ($180B), Microsoft ($160B), Google ($120B), NVIDIA ($95B), Meta ($75B); Finance (amber/gold) — JPMorgan ($85B), Visa ($70B), Mastercard ($55B), Goldman Sachs ($45B); Healthcare (teal green) — UnitedHealth ($90B), J&J ($65B), Merck ($50B), Pfizer ($40B); Retail (mauve/pink) — Amazon ($140B), Walmart ($60B), Costco ($45B), Target ($30B). Each bubble displays the company name in bold white text, with larger bubbles also showing the dollar value below. White edge lines (linewidth 3) separate bubbles cleanly. The legend at the bottom shows all four sectors horizontally with a "Sector" title. Axes are hidden.

Score: 90/100

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

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set (title 26pt, company names 9-20pt adaptive, legend 16pt/18pt). Smallest bubbles (Target, Goldman S.) use 9pt which is small but readable at full resolution.
  • VQ-02: No Overlap (6/6) — No text or bubble overlap anywhere. Packing algorithm maintains 1-2px gaps between all circles. Legend cleanly positioned below.
  • VQ-03: Element Visibility (6/6) — Bubble sizes scale proportionally to market cap values via sqrt-area mapping. All 17 bubbles clearly visible with alpha=0.92 and white edge lines providing separation.
  • VQ-04: Color Accessibility (4/4) — Four-color palette (blue #306998, amber #DE8F05, teal #029E73, mauve #CC78BC) is colorblind-safe with good luminance differentiation. White text contrasts well against all backgrounds.
  • VQ-05: Layout & Canvas (3/4) — Square canvas (12×12) is appropriate for circular packing. Bubbles fill center area well, but corners have unavoidable whitespace due to circular packing geometry. Slight imbalance with more whitespace at top.
  • VQ-06: Axis Labels & Title (2/2) — Axes appropriately hidden for packed bubble chart. Descriptive title "Market Capitalization by Sector" with proper subtitle format.

Design Excellence (15/20)

  • DE-01: Aesthetic Sophistication (6/8) — Custom four-color palette anchored on Python Blue with harmonious complements. White edge lines create clean bubble separation. Bold white text with semi-transparent value annotations creates typographic hierarchy. Professional, polished appearance clearly above library defaults.
  • DE-02: Visual Refinement (5/6) — All axes and spines removed (axis off + despine). Clean white background. White edge lines (linewidth=3) on bubbles provide visual structure without clutter. sns.set_context("poster") with font_scale=0.85 for appropriate scaling. tight_layout ensures good margins. Legend has subtle frame with edgecolor=#CCCCCC.
  • DE-03: Data Storytelling (4/6) — Bubble size creates natural visual hierarchy — Apple and Microsoft immediately dominate as the largest circles, conveying Technology sector leadership. Color grouping enables cross-sector comparison. Value annotations ($XB) add quantitative context. Viewer immediately grasps relative magnitude differences.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct packed bubble chart where circles are packed together without overlap. Position is meaningless; only size and color grouping convey information.
  • SC-02: Required Features (4/4) — Circle size by value (area-scaled via sqrt radius), packing without overlap (greedy placement algorithm), labels inside circles (adaptive sizing), color encoding group membership (sector palette), optional grouping via color.
  • SC-03: Data Mapping (3/3) — Values correctly mapped to circle area (np.sqrt for radius ensures area proportionality). All 17 data items visible and properly sized.
  • SC-04: Title & Legend (3/3) — Title format "bubble-packed · seaborn · pyplots.ai" present in subtitle. Legend labels match sector names. Legend positioned below with horizontal layout.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows wide range of bubble sizes ($30B to $180B), four distinct groups with varying membership counts (4-5 companies each), variation within groups (e.g., Apple $180B vs Meta $75B in Tech).
  • DQ-02: Realistic Context (5/5) — Real-world market capitalization scenario with recognizable company names. Business/finance domain is neutral and comprehensible. Data represents a plausible snapshot of major companies by sector.
  • DQ-03: Appropriate Scale (4/4) — Market cap values in billions are within realistic ranges for these companies. Relative proportions are sensible (Apple > Microsoft > Amazon, etc.).

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Linear flow: imports → data definition → packing algorithm → seaborn styling → plot → labels → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — Fully deterministic data and packing algorithm. No random elements.
  • CQ-03: Clean Imports (2/2) — All four imports (matplotlib.pyplot, numpy, pandas, seaborn) are used.
  • CQ-04: Code Elegance (2/2) — Packing algorithm is necessarily complex but cleanly implemented. Adaptive label sizing with clear threshold logic. Marker size conversion via fig.canvas.draw() is a well-executed technique. No fake UI elements.
  • CQ-05: Output & API (1/1) — Saves as plot.png with dpi=300, bbox_inches="tight". Uses current seaborn API (sns.scatterplot, sns.move_legend).

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — Good use of seaborn's axes-level API: sns.scatterplot with hue/size mapping, sns.set_context/set_style for theme management, sns.move_legend for legend positioning, sns.despine, sns.color_palette. However, the chart type requires substantial manual matplotlib work (packing algorithm, text labels, marker size calculation).
  • LM-02: Distinctive Features (3/5) — Leverages seaborn-specific features: sns.move_legend (unique to seaborn), sns.set_context("poster") for semantic scaling, categorical hue mapping with ordered palette, sns.despine for spine management. These go beyond what matplotlib alone provides.

Score Caps Applied

  • None — no cap conditions triggered.

Strengths

  • Effective greedy packing algorithm produces clean, non-overlapping bubble layout
  • Adaptive label sizing with value annotations creates good information density
  • Custom colorblind-safe palette with white edge highlighting is visually polished
  • Accurate area-based scaling (sqrt radius) ensures honest visual representation
  • Good use of seaborn's theming and legend management features

Weaknesses

  • Bubbles are not spatially clustered by sector (spec mentions optional grouping clusters)
  • Smallest bubble labels (Target, Goldman S.) are at the edge of comfortable readability

Issues Found

None blocking approval.

AI Feedback for Next Attempt

N/A — implementation meets quality threshold.

Verdict: APPROVED

@github-actions github-actions Bot added quality:90 Quality score 90/100 ai-approved Quality OK, ready for merge labels Feb 23, 2026
Copilot AI review requested due to automatic review settings February 23, 2026 16:06
@MarkusNeusinger MarkusNeusinger review requested due to automatic review settings February 23, 2026 16:06
@github-actions github-actions Bot merged commit c60a009 into main Feb 23, 2026
3 checks passed
@github-actions github-actions Bot deleted the implementation/bubble-packed/seaborn branch February 23, 2026 16:07
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:79 Quality score 79/100 quality:90 Quality score 90/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants