From 28cafa06b869e4f3deb5147cd795cb066742fb3b Mon Sep 17 00:00:00 2001 From: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:41:26 +0100 Subject: [PATCH 1/8] =?UTF-8?q?update(bubble-packed):=20plotly=20=E2=80=94?= =?UTF-8?q?=20comprehensive=20quality=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprehensive review improving code quality, data choice, visual design, spec compliance, and library feature usage. --- plots/bubble-packed/implementations/plotly.py | 141 +++++++++++------- plots/bubble-packed/metadata/plotly.yaml | 10 +- 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index 8e413b79f5..ce4728865b 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,7 +1,7 @@ -""" pyplots.ai +"""pyplots.ai bubble-packed: Basic Packed Bubble Chart -Library: plotly 6.5.0 | Python 3.13.11 -Quality: 93/100 | Created: 2025-12-23 +Library: plotly 6.5.2 | Python 3.14.3 +Quality: /100 | Updated: 2026-02-23 """ import numpy as np @@ -9,8 +9,7 @@ # Data - department budget allocation -np.random.seed(42) -data = { +budgets = { "Marketing": 2800000, "Engineering": 4500000, "Sales": 3200000, @@ -28,33 +27,28 @@ "Admin": 450000, } -labels = list(data.keys()) -values = list(data.values()) - -# Circle packing simulation using force-directed approach +labels = list(budgets.keys()) +values = np.array(list(budgets.values())) n = len(labels) + # Scale radii by area (sqrt) for accurate visual perception -radii_scale = np.sqrt(np.array(values)) / np.sqrt(max(values)) * 100 +radii = np.sqrt(values / values.max()) * 110 -# Initial positions - spread in a circle +# Circle packing via force simulation +np.random.seed(42) angles = np.linspace(0, 2 * np.pi, n, endpoint=False) -x_pos = np.cos(angles) * 200 + np.random.randn(n) * 50 -y_pos = np.sin(angles) * 200 + np.random.randn(n) * 50 +x_pos = np.cos(angles) * 150 + np.random.randn(n) * 30 +y_pos = np.sin(angles) * 150 + np.random.randn(n) * 30 -# Force simulation for circle packing -for _ in range(500): +for _ in range(600): for i in range(n): - fx, fy = 0, 0 - # Centering force - fx -= x_pos[i] * 0.01 - fy -= y_pos[i] * 0.01 - # Repulsion between circles + fx, fy = -x_pos[i] * 0.01, -y_pos[i] * 0.01 for j in range(n): if i != j: dx = x_pos[i] - x_pos[j] dy = y_pos[i] - y_pos[j] dist = np.sqrt(dx**2 + dy**2) + 0.1 - min_dist = radii_scale[i] + radii_scale[j] + 5 + min_dist = radii[i] + radii[j] + 4 if dist < min_dist: force = (min_dist - dist) * 0.3 fx += (dx / dist) * force @@ -64,8 +58,8 @@ # Color palette - Python colors first, then colorblind-safe colors = [ - "#306998", # Python Blue - "#FFD43B", # Python Yellow + "#306998", + "#FFD43B", "#4E79A7", "#F28E2B", "#E15759", @@ -81,63 +75,100 @@ "#85B6B2", ] -# Format values for display (inline) -formatted_values = [f"${v / 1000000:.1f}M" if v >= 1000000 else f"${v / 1000:.0f}K" for v in values] +# Format values for display +formatted = [f"${v / 1e6:.1f}M" if v >= 1e6 else f"${v / 1e3:.0f}K" for v in values] +total = f"${values.sum() / 1e6:.1f}M" -# Create bubble chart +# Build figure with shapes for precise circles fig = go.Figure() -# Add markers +# Draw circles as layout shapes for crisp rendering +shapes = [] +for i in range(n): + shapes.append( + { + "type": "circle", + "x0": x_pos[i] - radii[i], + "y0": y_pos[i] - radii[i], + "x1": x_pos[i] + radii[i], + "y1": y_pos[i] + radii[i], + "fillcolor": colors[i], + "opacity": 0.88, + "line": {"color": "white", "width": 2.5}, + } + ) + +# Invisible scatter for hover interactivity fig.add_trace( go.Scatter( x=x_pos, y=y_pos, mode="markers", - marker=dict(size=radii_scale * 2, color=colors[:n], line=dict(color="white", width=2), opacity=0.85), - hovertemplate=[ - f"{lbl}
{fval}" for lbl, fval in zip(labels, formatted_values, strict=True) - ], + marker={"size": radii * 2, "color": "rgba(0,0,0,0)"}, + hovertemplate=[f"{lbl}
{fval}" for lbl, fval in zip(labels, formatted, strict=True)], + showlegend=False, ) ) -# Add text annotations with size based on bubble radius +# Add text labels — only inside bubbles that are large enough for i in range(n): - font_size = max(10, min(18, int(radii_scale[i] * 0.2))) + font_size = max(9, min(18, int(radii[i] * 0.18))) + if radii[i] > 35: + text = f"{labels[i]}
{formatted[i]}" + else: + text = f"{labels[i]}" fig.add_annotation( x=x_pos[i], y=y_pos[i], - text=f"{labels[i]}
{formatted_values[i]}", + text=text, showarrow=False, - font=dict(size=font_size, color="white", family="Arial"), + font={"size": font_size, "color": "white", "family": "Arial"}, ) # Layout +pad = 140 fig.update_layout( - title=dict( - text="Department Budget Allocation · bubble-packed · plotly · pyplots.ai", - font=dict(size=32, color="#333"), - x=0.5, - xanchor="center", - ), - xaxis=dict( - showgrid=False, zeroline=False, showticklabels=False, title="", range=[min(x_pos) - 150, max(x_pos) + 150] - ), - yaxis=dict( - showgrid=False, - zeroline=False, - showticklabels=False, - title="", - scaleanchor="x", - scaleratio=1, - range=[min(y_pos) - 150, max(y_pos) + 150], - ), + title={ + "text": "Department Budget Allocation · bubble-packed · plotly · pyplots.ai", + "font": {"size": 32, "color": "#333"}, + "x": 0.5, + "xanchor": "center", + }, + xaxis={ + "showgrid": False, + "zeroline": False, + "showticklabels": False, + "title": "", + "range": [x_pos.min() - pad, x_pos.max() + pad], + }, + yaxis={ + "showgrid": False, + "zeroline": False, + "showticklabels": False, + "title": "", + "scaleanchor": "x", + "scaleratio": 1, + "range": [y_pos.min() - pad, y_pos.max() + pad], + }, + shapes=shapes, template="plotly_white", showlegend=False, - margin=dict(l=50, r=50, t=100, b=50), + margin={"l": 50, "r": 50, "t": 100, "b": 60}, paper_bgcolor="white", plot_bgcolor="white", ) -# Save outputs +# Add total budget annotation at bottom +fig.add_annotation( + text=f"Total: {total}", + xref="paper", + yref="paper", + x=0.5, + y=-0.02, + showarrow=False, + font={"size": 18, "color": "#666", "family": "Arial"}, +) + +# Save fig.write_image("plot.png", width=1600, height=900, scale=3) fig.write_html("plot.html", include_plotlyjs=True, full_html=True) diff --git a/plots/bubble-packed/metadata/plotly.yaml b/plots/bubble-packed/metadata/plotly.yaml index 1d33520167..35be63b050 100644 --- a/plots/bubble-packed/metadata/plotly.yaml +++ b/plots/bubble-packed/metadata/plotly.yaml @@ -1,16 +1,16 @@ library: plotly specification_id: bubble-packed created: '2025-12-23T09:16:37Z' -updated: '2025-12-23T09:19:10Z' -generated_by: claude-opus-4-5-20251101 +updated: 2026-02-23T15:35:00+00:00 +generated_by: claude-opus-4-6 workflow_run: 20456557994 issue: 0 -python_version: 3.13.11 -library_version: 6.5.0 +python_version: "3.14.3" +library_version: "6.5.2" preview_url: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.html -quality_score: 93 +quality_score: null impl_tags: dependencies: [] techniques: From e054a03ab1f7213345f99230122f323ecd625660 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 15:47:59 +0000 Subject: [PATCH 2/8] chore(plotly): update quality score 88 and review feedback for bubble-packed --- plots/bubble-packed/implementations/plotly.py | 4 +- plots/bubble-packed/metadata/plotly.yaml | 275 ++++++++++-------- 2 files changed, 151 insertions(+), 128 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index ce4728865b..0d81707139 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,7 +1,7 @@ -"""pyplots.ai +""" pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 -Quality: /100 | Updated: 2026-02-23 +Quality: 88/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/bubble-packed/metadata/plotly.yaml b/plots/bubble-packed/metadata/plotly.yaml index 35be63b050..1aa902df4a 100644 --- a/plots/bubble-packed/metadata/plotly.yaml +++ b/plots/bubble-packed/metadata/plotly.yaml @@ -1,16 +1,16 @@ library: plotly specification_id: bubble-packed created: '2025-12-23T09:16:37Z' -updated: 2026-02-23T15:35:00+00:00 +updated: '2026-02-23T15:47:58Z' generated_by: claude-opus-4-6 workflow_run: 20456557994 issue: 0 -python_version: "3.14.3" -library_version: "6.5.2" +python_version: 3.14.3 +library_version: 6.5.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.html -quality_score: null +quality_score: 88 impl_tags: dependencies: [] techniques: @@ -19,157 +19,173 @@ impl_tags: - html-export patterns: - data-generation - dataprep: [] + - iteration-over-groups + dataprep: + - normalization styling: + - minimal-chrome - alpha-blending + - edge-highlighting review: strengths: - - Excellent force-directed circle packing algorithm implementation that correctly - avoids overlap - - Proper area scaling (sqrt) for accurate visual perception as specified - - Clean, readable labels positioned inside bubbles with dynamic font sizing - - Rich hover templates with formatted budget values - - Good color palette starting with Python colors - - Both PNG and interactive HTML outputs provided - - Realistic department budget data with appropriate value range + - Custom force simulation for circle packing works well with no overlaps and good + visual spacing + - Smart label strategy with larger bubbles showing name plus dollar value and smaller + ones showing just name + - Good use of plotly-specific features including hover tooltips via hovertemplate, + HTML export, and layout shapes for crisp circles + - Realistic department budget data with appropriate scale and good 10x value range + - Clean visual design with custom color palette, white borders, and subtle opacity weaknesses: - - No legend showing total budget or providing a size reference scale - - Text in smallest bubbles (Admin, Legal, Design) appears slightly cramped - - Optional grouping feature from spec not demonstrated (though marked optional) - image_description: The plot displays a packed bubble chart with 15 circles representing - department budget allocations. Each circle is labeled with the department name - (bold) and budget value (in $M or $K format). The circles are packed tightly together - without overlap, with the largest circles being Engineering ($4.5M), R&D ($3.8M), - Sales ($3.2M), and Marketing ($2.8M). Smaller departments like Admin ($450K), - Legal ($650K), and Design ($720K) appear as smaller circles. The color palette - is diverse - Python blue for R&D, yellow for Engineering, various other colors - including pink, orange, teal, brown, and purple. The title "Department Budget - Allocation · bubble-packed · plotly · pyplots.ai" appears at the top center in - dark gray text. The background is clean white with no grid lines or axes shown. + - Text in smallest bubbles (Admin, Design, Legal) is borderline small — minimum + font size of 9pt could be increased + - Bubble cluster is slightly off-center with empty canvas space in the lower-right + area + - Some similar hues in the palette (two blues, teal vs green) may cause colorblind + accessibility issues + - Could push design further to reach publication quality + image_description: 'The plot displays a packed bubble chart titled "Department Budget + Allocation · bubble-packed · plotly · pyplots.ai". It shows 15 colored circles + of varying sizes packed together without overlap, representing department budgets. + The largest circle is Engineering ($4.5M) in bright yellow, followed by R&D ($3.8M) + in green, Sales ($3.2M) in steel blue, and Marketing ($2.8M) in dark teal. Mid-sized + bubbles include IT ($2.1M) in pink, Operations ($1.8M) in orange, Data Science + ($1.6M) in slate, and Product ($1.5M) in brown. Smaller bubbles include Finance + ($1.2M), Support ($1.1M), HR ($950K) in coral, QA ($880K) in beige, Design ($720K) + in olive, Legal ($650K) in purple, and Admin ($450K) in pale green (showing only + the name, no value). Each bubble has a white border (2.5px) and slight transparency + (0.88 opacity). White text labels appear inside each bubble. The background is + clean white with no axes or gridlines. A "Total: $27.3M" annotation appears at + the bottom center. The bubble cluster sits slightly left of center with some unused + canvas space below and to the right.' criteria_checklist: visual_quality: - score: 37 - max: 40 + score: 26 + max: 30 items: - id: VQ-01 name: Text Legibility - score: 10 - max: 10 + score: 6 + max: 8 passed: true - comment: All text is clearly readable. Title is large and prominent. Department - names and values are legible inside each bubble with white text that contrasts - well against the colored backgrounds. + comment: Font sizes explicitly set (title=32, labels=9-18 dynamic, total=18). + Smallest labels borderline small on Admin/Design/Legal bubbles. - id: VQ-02 name: No Overlap - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: Circles are properly packed without overlapping. Text is contained - within each bubble. + comment: Force simulation prevents all bubble overlaps. All text labels within + circles. - id: VQ-03 name: Element Visibility - score: 7 - max: 8 + score: 6 + max: 6 passed: true - comment: 'Bubble sizes are well-proportioned to show the data differences. - The force simulation effectively packed the circles. Minor: some smaller - bubbles (Admin, Legal) have slightly cramped text.' + comment: All 15 bubbles clearly visible and distinguishable. White borders + separate adjacent bubbles. - id: VQ-04 name: Color Accessibility - score: 5 - max: 5 + score: 3 + max: 4 passed: true - comment: Uses a colorblind-safe palette with sufficient variation. Python - blue and yellow featured prominently, other colors well-differentiated. + comment: Custom palette generally colorblind-friendly but includes similar + hues (two blues, teal vs green). - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 + name: Layout & Canvas + score: 3 + max: 4 passed: true - comment: Good proportions with circles centered in the plot area. White space - around the packed bubbles is balanced. + comment: Bubble cluster slightly left-of-center with empty space in lower-right + region. - id: VQ-06 - name: Axis Labels + name: Axis Labels & Title score: 2 max: 2 passed: true - comment: N/A for packed bubble chart - correctly hidden as position has no - meaning. - - id: VQ-07 - name: Grid & Legend - score: 0 - max: 2 + comment: No axis labels needed for packed bubble chart. Title is descriptive + with domain context. + design_excellence: + score: 15 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + passed: true + comment: Custom color palette, white borders, opacity, dynamic labels. Clearly + above defaults with intentional design choices. + - id: DE-02 + name: Visual Refinement + score: 5 + max: 6 passed: true - comment: No legend shown. While a legend isn't strictly necessary since labels - are on bubbles, a small legend or group indicator could enhance understanding. + comment: Axes/grid/ticks hidden. White background, circle borders, plotly_white + template. Very clean minimal chrome. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Size encoding creates natural visual hierarchy. Dollar values and + total annotation provide clear context. spec_compliance: - score: 25 - max: 25 + score: 15 + max: 15 items: - id: SC-01 name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct packed bubble chart where position has no meaning, only size - matters. - - id: SC-02 - name: Data Mapping score: 5 max: 5 passed: true - comment: Size correctly represents budget value, scaled by area (sqrt) as - spec requires. - - id: SC-03 + comment: Correct packed bubble chart with physics-based packing and area-proportional + sizing. + - id: SC-02 name: Required Features - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Labels inside circles, force simulation for packing, color encoding - categories. - - id: SC-04 - name: Data Range + comment: Area scaling, force simulation, conditional labels, color encoding, + hover tooltips all present. + - id: SC-03 + name: Data Mapping score: 3 max: 3 passed: true - comment: All 15 departments visible with appropriate size range. - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: Labels directly on bubbles, no separate legend needed. - - id: SC-06 - name: Title Format - score: 2 - max: 2 + comment: Values correctly mapped to circle area via sqrt scaling. 15 items + in recommended range. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 passed: true - comment: Correctly uses "{description} · bubble-packed · plotly · pyplots.ai" - format. + comment: Title follows exact format. No legend needed with inline labels and + per-category colors. data_quality: - score: 18 - max: 20 + score: 14 + max: 15 items: - id: DQ-01 name: Feature Coverage - score: 6 - max: 8 + score: 5 + max: 6 passed: true - comment: Shows good variation in circle sizes from $450K to $4.5M (10x range). - However, the spec mentions optional grouping which isn't demonstrated. + comment: Good value range (10x), 15 items, adaptive labels. Optional grouping + not demonstrated. - id: DQ-02 name: Realistic Context - score: 7 - max: 7 + score: 5 + max: 5 passed: true - comment: Department budget allocation is a perfect, real-world scenario for - packed bubble charts. + comment: Department budget allocation is realistic, neutral, and relatable. - id: DQ-03 name: Appropriate Scale - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Budget values are realistic for a medium-to-large company. + comment: Budget values ($450K-$4.5M, total $27.3M) realistic for mid-to-large + company. code_quality: score: 10 max: 10 @@ -179,42 +195,49 @@ review: score: 3 max: 3 passed: true - comment: 'Simple linear flow: imports → data → simulation → plot → save.' + comment: 'Clean linear flow: imports, data, scaling, simulation, figure, save. + No functions or classes.' - id: CQ-02 name: Reproducibility - score: 3 - max: 3 + score: 2 + max: 2 passed: true - comment: Uses np.random.seed(42). + comment: np.random.seed(42) set before random operations. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: Only numpy and plotly.graph_objects used. + comment: Only numpy and plotly.graph_objects imported, both used. - id: CQ-04 - name: No Deprecated API - score: 1 - max: 1 + name: Code Elegance + score: 2 + max: 2 passed: true - comment: Uses current plotly API. + comment: Force simulation appropriately complex. Dynamic font sizing and conditional + labels are clean. - id: CQ-05 - name: Output Correct + name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png and plot.html. - library_features: - score: 3 - max: 5 + comment: Saves plot.png at 4800x2700 and plot.html. Uses current plotly API. + library_mastery: + score: 8 + max: 10 items: - - id: LF-01 - name: Uses distinctive library features - score: 3 + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: 'Correctly builds from plotly primitives: layout shapes, invisible + scatter for hover, annotations for labels, scaleanchor for aspect ratio.' + - id: LM-02 + name: Distinctive Features + score: 4 max: 5 passed: true - comment: Uses go.Scatter with annotations for labels and hover templates for - interactivity. The HTML export enables Plotly's interactive features. Could - leverage Plotly's animation capabilities for the force simulation or use - custom shapes. - verdict: APPROVED + comment: Leverages hovertemplate, write_html(), layout shapes, and scaleanchor + — distinctively plotly features. + verdict: REJECTED From 7c0a28bace77449548b00f838dbc7d26ae229082 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 15:56:27 +0000 Subject: [PATCH 3/8] fix(plotly): address review feedback for bubble-packed Attempt 1/3 - fixes based on AI review --- plots/bubble-packed/implementations/plotly.py | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index 0d81707139..39ac3d51e3 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,4 +1,4 @@ -""" pyplots.ai +"""pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 Quality: 88/100 | Updated: 2026-02-23 @@ -56,11 +56,17 @@ x_pos[i] += fx y_pos[i] += fy +# Center the bubble cluster on canvas +x_center = (x_pos.min() + x_pos.max()) / 2 +y_center = (y_pos.min() + y_pos.max()) / 2 +x_pos -= x_center +y_pos -= y_center + # Color palette - Python colors first, then colorblind-safe colors = [ "#306998", "#FFD43B", - "#4E79A7", + "#CE6DBD", "#F28E2B", "#E15759", "#76B7B2", @@ -70,9 +76,15 @@ "#FF9DA7", "#9C755F", "#BAB0AC", - "#5778A4", - "#E49444", - "#85B6B2", + "#8CD17D", + "#A0CBE8", + "#DECBE4", +] + +# Adaptive text color: dark on light backgrounds, white on dark +text_colors = [ + "#333" if (int(c[1:3], 16) * 299 + int(c[3:5], 16) * 587 + int(c[5:7], 16) * 114) > 153000 else "white" + for c in colors ] # Format values for display @@ -112,7 +124,7 @@ # Add text labels — only inside bubbles that are large enough for i in range(n): - font_size = max(9, min(18, int(radii[i] * 0.18))) + font_size = max(12, min(20, int(radii[i] * 0.20))) if radii[i] > 35: text = f"{labels[i]}
{formatted[i]}" else: @@ -122,11 +134,12 @@ y=y_pos[i], text=text, showarrow=False, - font={"size": font_size, "color": "white", "family": "Arial"}, + font={"size": font_size, "color": text_colors[i], "family": "Arial"}, ) -# Layout -pad = 140 +# Layout — symmetric ranges for balanced centering +x_ext = max(abs((x_pos - radii).min()), abs((x_pos + radii).max())) + 30 +y_ext = max(abs((y_pos - radii).min()), abs((y_pos + radii).max())) + 30 fig.update_layout( title={ "text": "Department Budget Allocation · bubble-packed · plotly · pyplots.ai", @@ -134,13 +147,7 @@ "x": 0.5, "xanchor": "center", }, - xaxis={ - "showgrid": False, - "zeroline": False, - "showticklabels": False, - "title": "", - "range": [x_pos.min() - pad, x_pos.max() + pad], - }, + xaxis={"showgrid": False, "zeroline": False, "showticklabels": False, "title": "", "range": [-x_ext, x_ext]}, yaxis={ "showgrid": False, "zeroline": False, @@ -148,7 +155,7 @@ "title": "", "scaleanchor": "x", "scaleratio": 1, - "range": [y_pos.min() - pad, y_pos.max() + pad], + "range": [-y_ext, y_ext], }, shapes=shapes, template="plotly_white", @@ -158,13 +165,11 @@ plot_bgcolor="white", ) -# Add total budget annotation at bottom +# Add total budget annotation just below the cluster fig.add_annotation( text=f"Total: {total}", - xref="paper", - yref="paper", - x=0.5, - y=-0.02, + x=0, + y=(y_pos - radii).min() - 25, showarrow=False, font={"size": 18, "color": "#666", "family": "Arial"}, ) From c2163b5301d71167ad961afb6541b9420d0709fc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 16:03:23 +0000 Subject: [PATCH 4/8] chore(plotly): update quality score 85 and review feedback for bubble-packed --- plots/bubble-packed/implementations/plotly.py | 4 +- plots/bubble-packed/metadata/plotly.yaml | 158 +++++++++--------- 2 files changed, 80 insertions(+), 82 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index 39ac3d51e3..4452019246 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,7 +1,7 @@ -"""pyplots.ai +""" pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 -Quality: 88/100 | Updated: 2026-02-23 +Quality: 85/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/bubble-packed/metadata/plotly.yaml b/plots/bubble-packed/metadata/plotly.yaml index 1aa902df4a..9727cbfc26 100644 --- a/plots/bubble-packed/metadata/plotly.yaml +++ b/plots/bubble-packed/metadata/plotly.yaml @@ -1,7 +1,7 @@ library: plotly specification_id: bubble-packed created: '2025-12-23T09:16:37Z' -updated: '2026-02-23T15:47:58Z' +updated: '2026-02-23T16:03:22Z' generated_by: claude-opus-4-6 workflow_run: 20456557994 issue: 0 @@ -10,13 +10,14 @@ library_version: 6.5.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.html -quality_score: 88 +quality_score: 85 impl_tags: dependencies: [] techniques: - annotations - hover-tooltips - html-export + - patches patterns: - data-generation - iteration-over-groups @@ -24,112 +25,108 @@ impl_tags: - normalization styling: - minimal-chrome - - alpha-blending - edge-highlighting + - alpha-blending review: strengths: - - Custom force simulation for circle packing works well with no overlaps and good - visual spacing - - Smart label strategy with larger bubbles showing name plus dollar value and smaller - ones showing just name - - Good use of plotly-specific features including hover tooltips via hovertemplate, - HTML export, and layout shapes for crisp circles - - Realistic department budget data with appropriate scale and good 10x value range - - Clean visual design with custom color palette, white borders, and subtle opacity + - Perfect spec compliance — all required features implemented correctly + - Realistic, neutral department budget data with excellent value range + - Clever invisible scatter + shapes pattern for hover interactivity + - Adaptive text color using luminance calculation ensures readability on all bubble + colors + - Clean, well-structured code with proper seeding weaknesses: - - Text in smallest bubbles (Admin, Design, Legal) is borderline small — minimum - font size of 9pt could be increased - - Bubble cluster is slightly off-center with empty canvas space in the lower-right - area - - Some similar hues in the palette (two blues, teal vs green) may cause colorblind - accessibility issues - - Could push design further to reach publication quality + - 15-color palette is diverse but not harmonious — looks colorful rather than cohesive + - Canvas utilization is slightly asymmetric due to packing algorithm + - Library mastery limited by the manual nature of circle packing image_description: 'The plot displays a packed bubble chart titled "Department Budget - Allocation · bubble-packed · plotly · pyplots.ai". It shows 15 colored circles - of varying sizes packed together without overlap, representing department budgets. - The largest circle is Engineering ($4.5M) in bright yellow, followed by R&D ($3.8M) - in green, Sales ($3.2M) in steel blue, and Marketing ($2.8M) in dark teal. Mid-sized - bubbles include IT ($2.1M) in pink, Operations ($1.8M) in orange, Data Science - ($1.6M) in slate, and Product ($1.5M) in brown. Smaller bubbles include Finance - ($1.2M), Support ($1.1M), HR ($950K) in coral, QA ($880K) in beige, Design ($720K) - in olive, Legal ($650K) in purple, and Admin ($450K) in pale green (showing only - the name, no value). Each bubble has a white border (2.5px) and slight transparency - (0.88 opacity). White text labels appear inside each bubble. The background is - clean white with no axes or gridlines. A "Total: $27.3M" annotation appears at - the bottom center. The bubble cluster sits slightly left of center with some unused - canvas space below and to the right.' + Allocation · bubble-packed · plotly · pyplots.ai". Fifteen circles of varying + sizes are packed together in a roughly central cluster on a white background. + Each circle represents a department: Engineering ($4.5M, largest, yellow), R&D + ($3.8M, dark teal-green), Sales ($3.2M, magenta/pink), Marketing ($2.8M, dark + steel blue), IT ($2.1M, salmon/coral), Operations ($1.8M, orange), Data Science + ($1.6M, green), Product ($1.5M, brown), Finance ($1.2M, light yellow), Support + ($1.1M, peach), HR ($950K, muted red), QA ($880K, tan/beige), Design ($720K, blue-purple), + Legal ($650K, teal), and Admin ($450K, smallest, lavender). Each circle has a + white border and contains its department name in bold plus the budget amount (for + larger circles). Text color adapts — white on dark backgrounds, dark gray on light + backgrounds. Below the cluster is "Total: $27.3M" in gray. Axes are hidden (no + grid, no ticks).' criteria_checklist: visual_quality: - score: 26 + score: 27 max: 30 items: - id: VQ-01 name: Text Legibility - score: 6 + score: 7 max: 8 passed: true - comment: Font sizes explicitly set (title=32, labels=9-18 dynamic, total=18). - Smallest labels borderline small on Admin/Design/Legal bubbles. + comment: Title at 32pt, annotations 12-20pt dynamically sized, total at 18pt. + All fonts explicitly set with Arial family. Smallest bubbles have slightly + compact text but still legible. - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: Force simulation prevents all bubble overlaps. All text labels within - circles. + comment: Force simulation with padding ensures no circle overlap. All labels + contained within their bubbles. - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: All 15 bubbles clearly visible and distinguishable. White borders - separate adjacent bubbles. + comment: Circles clearly visible with good size differentiation (10:1 ratio). + White borders at 2.5px separate adjacent circles. Opacity 0.88 provides + solid fills. - id: VQ-04 name: Color Accessibility score: 3 max: 4 passed: true - comment: Custom palette generally colorblind-friendly but includes similar - hues (two blues, teal vs green). + comment: 15 distinct colors with good variety in hue and lightness. Adaptive + text color ensures readability. However, some green pairs could be confusing + for colorblind users. - id: VQ-05 name: Layout & Canvas score: 3 max: 4 passed: true - comment: Bubble cluster slightly left-of-center with empty space in lower-right - region. + comment: Cluster reasonably well-centered, fills approximately 55% of canvas. + Slight asymmetry from packing algorithm. - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: No axis labels needed for packed bubble chart. Title is descriptive - with domain context. + comment: Axes correctly hidden for packed bubble chart. Descriptive title + with proper format. design_excellence: - score: 15 + score: 13 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 6 + score: 5 max: 8 passed: true - comment: Custom color palette, white borders, opacity, dynamic labels. Clearly - above defaults with intentional design choices. + comment: Custom 15-color palette with adaptive text colors and white borders. + Professional but 15 colors creates visual variety rather than harmony. - id: DE-02 name: Visual Refinement - score: 5 + score: 4 max: 6 passed: true - comment: Axes/grid/ticks hidden. White background, circle borders, plotly_white - template. Very clean minimal chrome. + comment: Grid and axes properly hidden. plotly_white template. White borders + on circles add polish. Total annotation provides context. - id: DE-03 name: Data Storytelling score: 4 max: 6 passed: true - comment: Size encoding creates natural visual hierarchy. Dollar values and - total annotation provide clear context. + comment: Size variation creates natural visual hierarchy — Engineering dominates. + Dollar formatting aids comparison. Total budget annotation provides context. spec_compliance: score: 15 max: 15 @@ -139,29 +136,28 @@ review: score: 5 max: 5 passed: true - comment: Correct packed bubble chart with physics-based packing and area-proportional - sizing. + comment: Correct packed bubble chart with force simulation packing. - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Area scaling, force simulation, conditional labels, color encoding, - hover tooltips all present. + comment: Area-proportional sizing, force simulation packing, labels inside + large circles, color per category, hover tooltips. - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: Values correctly mapped to circle area via sqrt scaling. 15 items - in recommended range. + comment: Values correctly mapped to circle area via sqrt scaling. All 15 items + visible. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title follows exact format. No legend needed with inline labels and - per-category colors. + comment: Title follows required format. No legend needed as labels are inside + circles. data_quality: score: 14 max: 15 @@ -171,20 +167,20 @@ review: score: 5 max: 6 passed: true - comment: Good value range (10x), 15 items, adaptive labels. Optional grouping - not demonstrated. + comment: 15 departments with 10:1 value range. Good variety in sizes. Optional + grouping not demonstrated. - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Department budget allocation is realistic, neutral, and relatable. + comment: Corporate department budgets — realistic, neutral, comprehensible. - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Budget values ($450K-$4.5M, total $27.3M) realistic for mid-to-large + comment: Budget values ($450K–$4.5M, total $27.3M) realistic for a mid-to-large company. code_quality: score: 10 @@ -195,8 +191,8 @@ review: score: 3 max: 3 passed: true - comment: 'Clean linear flow: imports, data, scaling, simulation, figure, save. - No functions or classes.' + comment: 'Linear flow: data, scale, pack, color, figure, save. No functions + or classes.' - id: CQ-02 name: Reproducibility score: 2 @@ -214,30 +210,32 @@ review: score: 2 max: 2 passed: true - comment: Force simulation appropriately complex. Dynamic font sizing and conditional - labels are clean. + comment: Clean, readable code. Force simulation well-commented. Adaptive text + color is elegant. - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot.png at 4800x2700 and plot.html. Uses current plotly API. + comment: Saves as plot.png (4800x2700) and plot.html. Current Plotly API. library_mastery: - score: 8 + score: 6 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 4 + score: 3 max: 5 - passed: true - comment: 'Correctly builds from plotly primitives: layout shapes, invisible - scatter for hover, annotations for labels, scaleanchor for aspect ratio.' + passed: false + comment: Uses go.Figure, go.Scatter, layout shapes, add_annotation, scaleanchor + correctly. But core visualization is custom code, not Plotly's plotting + functions. - id: LM-02 name: Distinctive Features - score: 4 + score: 3 max: 5 - passed: true - comment: Leverages hovertemplate, write_html(), layout shapes, and scaleanchor - — distinctively plotly features. + passed: false + comment: Invisible scatter with hovertemplate for hover interactivity, HTML + export, scaleanchor for 1:1 ratio are Plotly-specific. But core packing + algorithm is library-agnostic. verdict: REJECTED From 5d16d843160bd74ed319f04cc2de679c830442aa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 16:25:07 +0000 Subject: [PATCH 5/8] fix(plotly): address review feedback for bubble-packed Attempt 2/3 - fixes based on AI review --- plots/bubble-packed/implementations/plotly.py | 114 ++++++++---------- 1 file changed, 49 insertions(+), 65 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index 4452019246..129d4bb0f7 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,7 +1,6 @@ -""" pyplots.ai +"""pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 -Quality: 85/100 | Updated: 2026-02-23 """ import numpy as np @@ -56,90 +55,76 @@ x_pos[i] += fx y_pos[i] += fy -# Center the bubble cluster on canvas -x_center = (x_pos.min() + x_pos.max()) / 2 -y_center = (y_pos.min() + y_pos.max()) / 2 -x_pos -= x_center -y_pos -= y_center - -# Color palette - Python colors first, then colorblind-safe -colors = [ - "#306998", - "#FFD43B", - "#CE6DBD", - "#F28E2B", - "#E15759", - "#76B7B2", - "#59A14F", - "#EDC948", - "#B07AA1", - "#FF9DA7", - "#9C755F", - "#BAB0AC", - "#8CD17D", - "#A0CBE8", - "#DECBE4", -] - -# Adaptive text color: dark on light backgrounds, white on dark -text_colors = [ - "#333" if (int(c[1:3], 16) * 299 + int(c[3:5], 16) * 587 + int(c[5:7], 16) * 114) > 153000 else "white" - for c in colors -] +# Weight-based centering for better visual balance (larger bubbles pull center) +area_weights = radii**2 +x_pos -= np.average(x_pos, weights=area_weights) +y_pos -= np.average(y_pos, weights=area_weights) + +# Axis ranges — symmetric with generous padding for balanced layout +x_ext = max(abs((x_pos - radii).min()), abs((x_pos + radii).max())) + 50 +y_ext = max(abs((y_pos - radii).min()), abs((y_pos + radii).max())) + 50 + +# Convert data-coordinate radii to pixel marker diameters +# With scaleanchor y=x, the smaller dimension constrains the scale +fig_w, fig_h = 1600, 900 +m_l, m_r, m_t, m_b = 50, 50, 100, 60 +plot_w, plot_h = fig_w - m_l - m_r, fig_h - m_t - m_b +px_per_unit = min(plot_w / (2 * x_ext), plot_h / (2 * y_ext)) +marker_diameters = 2 * radii * px_per_unit + +# Sequential blue palette — adaptive text color for readability +norm_vals = (values - values.min()) / (values.max() - values.min()) +text_colors = ["white" if nv > 0.3 else "#333" for nv in norm_vals] # Format values for display formatted = [f"${v / 1e6:.1f}M" if v >= 1e6 else f"${v / 1e3:.0f}K" for v in values] +shares = [f"{v / values.sum() * 100:.1f}" for v in values] total = f"${values.sum() / 1e6:.1f}M" -# Build figure with shapes for precise circles +# Build figure — go.Scatter with sized markers as primary visualization fig = go.Figure() -# Draw circles as layout shapes for crisp rendering -shapes = [] -for i in range(n): - shapes.append( - { - "type": "circle", - "x0": x_pos[i] - radii[i], - "y0": y_pos[i] - radii[i], - "x1": x_pos[i] + radii[i], - "y1": y_pos[i] + radii[i], - "fillcolor": colors[i], - "opacity": 0.88, - "line": {"color": "white", "width": 2.5}, - } - ) - -# Invisible scatter for hover interactivity fig.add_trace( go.Scatter( x=x_pos, y=y_pos, mode="markers", - marker={"size": radii * 2, "color": "rgba(0,0,0,0)"}, - hovertemplate=[f"{lbl}
{fval}" for lbl, fval in zip(labels, formatted, strict=True)], + marker={ + "size": marker_diameters, + "sizemode": "diameter", + "color": values, + "colorscale": [ + [0, "#C6DBEF"], + [0.2, "#9ECAE1"], + [0.4, "#6BAED6"], + [0.6, "#3182BD"], + [0.8, "#1565A0"], + [1, "#08306B"], + ], + "showscale": False, + "opacity": 0.9, + "line": {"color": "white", "width": 2.5}, + }, + text=labels, + customdata=np.column_stack([formatted, shares]), + hovertemplate="%{text}
Budget: %{customdata[0]}
Share: %{customdata[1]}%", showlegend=False, ) ) -# Add text labels — only inside bubbles that are large enough +# Text labels inside bubbles for i in range(n): font_size = max(12, min(20, int(radii[i] * 0.20))) - if radii[i] > 35: - text = f"{labels[i]}
{formatted[i]}" - else: - text = f"{labels[i]}" + label_text = f"{labels[i]}
{formatted[i]}" if radii[i] > 35 else f"{labels[i]}" fig.add_annotation( x=x_pos[i], y=y_pos[i], - text=text, + text=label_text, showarrow=False, font={"size": font_size, "color": text_colors[i], "family": "Arial"}, ) -# Layout — symmetric ranges for balanced centering -x_ext = max(abs((x_pos - radii).min()), abs((x_pos + radii).max())) + 30 -y_ext = max(abs((y_pos - radii).min()), abs((y_pos + radii).max())) + 30 +# Layout fig.update_layout( title={ "text": "Department Budget Allocation · bubble-packed · plotly · pyplots.ai", @@ -157,15 +142,14 @@ "scaleratio": 1, "range": [-y_ext, y_ext], }, - shapes=shapes, template="plotly_white", showlegend=False, - margin={"l": 50, "r": 50, "t": 100, "b": 60}, + margin={"l": m_l, "r": m_r, "t": m_t, "b": m_b}, paper_bgcolor="white", plot_bgcolor="white", ) -# Add total budget annotation just below the cluster +# Total budget annotation below the cluster fig.add_annotation( text=f"Total: {total}", x=0, @@ -175,5 +159,5 @@ ) # Save -fig.write_image("plot.png", width=1600, height=900, scale=3) +fig.write_image("plot.png", width=fig_w, height=fig_h, scale=3) fig.write_html("plot.html", include_plotlyjs=True, full_html=True) From 49b710e659d6f678514ae67a6d7133c20fb547f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 16:31:49 +0000 Subject: [PATCH 6/8] chore(plotly): update quality score 89 and review feedback for bubble-packed --- plots/bubble-packed/implementations/plotly.py | 3 +- plots/bubble-packed/metadata/plotly.yaml | 156 +++++++++--------- 2 files changed, 81 insertions(+), 78 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index 129d4bb0f7..298cfad620 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,6 +1,7 @@ -"""pyplots.ai +""" pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 +Quality: 89/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/bubble-packed/metadata/plotly.yaml b/plots/bubble-packed/metadata/plotly.yaml index 9727cbfc26..b7deed553c 100644 --- a/plots/bubble-packed/metadata/plotly.yaml +++ b/plots/bubble-packed/metadata/plotly.yaml @@ -1,7 +1,7 @@ library: plotly specification_id: bubble-packed created: '2025-12-23T09:16:37Z' -updated: '2026-02-23T16:03:22Z' +updated: '2026-02-23T16:31:48Z' generated_by: claude-opus-4-6 workflow_run: 20456557994 issue: 0 @@ -10,51 +10,53 @@ library_version: 6.5.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.html -quality_score: 85 +quality_score: 89 impl_tags: dependencies: [] techniques: - annotations - hover-tooltips - html-export - - patches patterns: - data-generation - iteration-over-groups dataprep: - normalization styling: + - custom-colormap - minimal-chrome - edge-highlighting - alpha-blending review: strengths: - - Perfect spec compliance — all required features implemented correctly - - Realistic, neutral department budget data with excellent value range - - Clever invisible scatter + shapes pattern for hover interactivity - - Adaptive text color using luminance calculation ensures readability on all bubble - colors - - Clean, well-structured code with proper seeding + - Excellent circle packing algorithm with 600-iteration force simulation producing + clean, overlap-free layout + - Custom 6-stop sequential blue colorscale with adaptive text colors (white/dark) + for optimal readability + - 'Professional polish: white bubble outlines, hidden axes, weight-based centering, + size-adaptive labels' + - Rich Plotly interactivity via hovertemplate with budget amounts and share percentages + - Realistic, neutral department budget data with good value range (10x spread) weaknesses: - - 15-color palette is diverse but not harmonious — looks colorful rather than cohesive - - Canvas utilization is slightly asymmetric due to packing algorithm - - Library mastery limited by the manual nature of circle packing + - Canvas utilization could be tighter — noticeable whitespace around the bubble + cluster + - Color and size both encode the same variable (value), missing opportunity for + a second data dimension + - Smallest bubble labels at 12pt are at the lower bound of comfortable readability image_description: 'The plot displays a packed bubble chart titled "Department Budget Allocation · bubble-packed · plotly · pyplots.ai". Fifteen circles of varying - sizes are packed together in a roughly central cluster on a white background. - Each circle represents a department: Engineering ($4.5M, largest, yellow), R&D - ($3.8M, dark teal-green), Sales ($3.2M, magenta/pink), Marketing ($2.8M, dark - steel blue), IT ($2.1M, salmon/coral), Operations ($1.8M, orange), Data Science - ($1.6M, green), Product ($1.5M, brown), Finance ($1.2M, light yellow), Support - ($1.1M, peach), HR ($950K, muted red), QA ($880K, tan/beige), Design ($720K, blue-purple), - Legal ($650K, teal), and Admin ($450K, smallest, lavender). Each circle has a - white border and contains its department name in bold plus the budget amount (for - larger circles). Text color adapts — white on dark backgrounds, dark gray on light - backgrounds. Below the cluster is "Total: $27.3M" in gray. Axes are hidden (no - grid, no ticks).' + sizes represent department budgets, packed tightly together without overlap. A + sequential blue color palette ranges from light blue (smaller budgets like Admin + $450K) to dark navy (larger budgets like Engineering $4.5M). Each bubble contains + a bold department name and budget value (e.g., "Engineering $4.5M", "R&D $3.8M"). + Smaller bubbles like "Admin" show only the name. White outlines (2.5px) separate + adjacent bubbles. Axes are hidden (no grid, ticks, or labels). A "Total: $27.3M" + annotation sits below the cluster. The background is clean white. The largest + bubbles (Engineering, R&D, Sales, Marketing) immediately draw the eye due to both + size and dark color.' criteria_checklist: visual_quality: - score: 27 + score: 28 max: 30 items: - id: VQ-01 @@ -62,71 +64,70 @@ review: score: 7 max: 8 passed: true - comment: Title at 32pt, annotations 12-20pt dynamically sized, total at 18pt. - All fonts explicitly set with Arial family. Smallest bubbles have slightly - compact text but still legible. + comment: Title at 32pt excellent. Annotation fonts explicitly calculated 12-20pt. + Smallest labels at 12pt on edge of ideal but legible. Adaptive text colors + ensure contrast. - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: Force simulation with padding ensures no circle overlap. All labels - contained within their bubbles. + comment: Force simulation with 600 iterations produces clean packing. No text + or bubble overlap visible. - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: Circles clearly visible with good size differentiation (10:1 ratio). - White borders at 2.5px separate adjacent circles. Opacity 0.88 provides - solid fills. + comment: All 15 bubbles clearly visible with good size differentiation. Opacity + 0.9 with white borders provides excellent separation. - id: VQ-04 name: Color Accessibility - score: 3 + score: 4 max: 4 passed: true - comment: 15 distinct colors with good variety in hue and lightness. Adaptive - text color ensures readability. However, some green pairs could be confusing - for colorblind users. + comment: Sequential blue palette is colorblind-safe, relying on luminance + rather than hue distinction. - id: VQ-05 name: Layout & Canvas score: 3 max: 4 passed: true - comment: Cluster reasonably well-centered, fills approximately 55% of canvas. - Slight asymmetry from packing algorithm. + comment: Bubble cluster well-centered but fills roughly 40-45% of canvas. + Notable whitespace on left and bottom-left. - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Axes correctly hidden for packed bubble chart. Descriptive title - with proper format. + comment: Axes correctly hidden for packed bubble chart. Title descriptive + with correct format. Dollar values provide context. design_excellence: - score: 13 + score: 15 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 5 + score: 6 max: 8 passed: true - comment: Custom 15-color palette with adaptive text colors and white borders. - Professional but 15 colors creates visual variety rather than harmony. + comment: Custom 6-stop blue colorscale, white outlines, adaptive text coloring, + Arial font. Cohesive and professional, above defaults. - id: DE-02 name: Visual Refinement - score: 4 + score: 5 max: 6 passed: true - comment: Grid and axes properly hidden. plotly_white template. White borders - on circles add polish. Total annotation provides context. + comment: All chrome removed, clean white background, white outlines, weight-based + centering, generous margins. Minor gap in canvas utilization. - id: DE-03 name: Data Storytelling score: 4 max: 6 passed: true - comment: Size variation creates natural visual hierarchy — Engineering dominates. - Dollar formatting aids comparison. Total budget annotation provides context. + comment: Size and color create clear visual hierarchy with Engineering as + focal point. Total annotation provides context. Both channels encode same + dimension. spec_compliance: score: 15 max: 15 @@ -136,28 +137,29 @@ review: score: 5 max: 5 passed: true - comment: Correct packed bubble chart with force simulation packing. + comment: Correct packed bubble chart with physics-based force simulation. + Position meaningless, only size matters. - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Area-proportional sizing, force simulation packing, labels inside - large circles, color per category, hover tooltips. + comment: Labels, values, area scaling, force packing, labels inside circles + all present. Optional grouping not required. - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: Values correctly mapped to circle area via sqrt scaling. All 15 items - visible. + comment: Circle area correctly scaled by sqrt of value. Color maps to value. + Labels mapped to categories. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title follows required format. No legend needed as labels are inside - circles. + comment: Title follows required format with descriptive prefix. No legend + needed for single-series chart. data_quality: score: 14 max: 15 @@ -167,21 +169,22 @@ review: score: 5 max: 6 passed: true - comment: 15 departments with 10:1 value range. Good variety in sizes. Optional - grouping not demonstrated. + comment: 15 departments with 10x value range showing good variation. No grouping + dimension demonstrated. - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Corporate department budgets — realistic, neutral, comprehensible. + comment: Department budget allocation is a classic, neutral business scenario + with realistic department names. - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Budget values ($450K–$4.5M, total $27.3M) realistic for a mid-to-large - company. + comment: Budget values $450K to $4.5M with $27.3M total are realistic for + a medium-to-large company. code_quality: score: 10 max: 10 @@ -191,14 +194,14 @@ review: score: 3 max: 3 passed: true - comment: 'Linear flow: data, scale, pack, color, figure, save. No functions - or classes.' + comment: 'Clean linear flow: imports, data, circle packing, figure, annotations, + layout, save. No functions or classes.' - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: np.random.seed(42) set before random operations. + comment: np.random.seed(42) ensures deterministic layout. - id: CQ-03 name: Clean Imports score: 2 @@ -210,32 +213,31 @@ review: score: 2 max: 2 passed: true - comment: Clean, readable code. Force simulation well-commented. Adaptive text - color is elegant. + comment: Force simulation appropriately complex. Marker diameter calculation + well-engineered. No fake UI. - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png (4800x2700) and plot.html. Current Plotly API. + comment: Saves plot.png (1600x900, scale=3) and plot.html. Current Plotly + API used. library_mastery: - score: 6 + score: 7 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 3 + score: 4 max: 5 - passed: false - comment: Uses go.Figure, go.Scatter, layout shapes, add_annotation, scaleanchor - correctly. But core visualization is custom code, not Plotly's plotting - functions. + passed: true + comment: Good use of go.Scatter with sizemode, hovertemplate, customdata, + add_annotation, scaleanchor, plotly_white template. - id: LM-02 name: Distinctive Features score: 3 max: 5 - passed: false - comment: Invisible scatter with hovertemplate for hover interactivity, HTML - export, scaleanchor for 1:1 ratio are Plotly-specific. But core packing - algorithm is library-agnostic. + passed: true + comment: Rich hovertemplate with formatted data, HTML export for interactivity, + sizemode diameter, custom colorscale. verdict: REJECTED From 81a2b12178e424b43a34a3af466d5415bd4fee77 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 16:43:06 +0000 Subject: [PATCH 7/8] fix(plotly): address review feedback for bubble-packed Attempt 3/3 - fixes based on AI review --- plots/bubble-packed/implementations/plotly.py | 155 ++++++++++-------- 1 file changed, 84 insertions(+), 71 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index 298cfad620..c4cfd582b6 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,36 +1,39 @@ -""" pyplots.ai +"""pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 -Quality: 89/100 | Updated: 2026-02-23 """ import numpy as np import plotly.graph_objects as go -# Data - department budget allocation -budgets = { - "Marketing": 2800000, - "Engineering": 4500000, - "Sales": 3200000, - "Operations": 1800000, - "HR": 950000, - "Finance": 1200000, - "R&D": 3800000, - "Support": 1100000, - "Legal": 650000, - "IT": 2100000, - "Product": 1500000, - "QA": 880000, - "Data Science": 1650000, - "Design": 720000, - "Admin": 450000, -} - -labels = list(budgets.keys()) -values = np.array(list(budgets.values())) +# Data — department budgets with functional groupings +departments = [ + ("Engineering", 4500000, "Technology"), + ("R&D", 3800000, "Technology"), + ("IT", 2100000, "Technology"), + ("Data Science", 1650000, "Technology"), + ("QA", 880000, "Technology"), + ("Sales", 3200000, "Revenue"), + ("Marketing", 2800000, "Revenue"), + ("Operations", 1800000, "Operations"), + ("Finance", 1200000, "Operations"), + ("Support", 1100000, "Operations"), + ("Admin", 450000, "Operations"), + ("HR", 950000, "Corporate"), + ("Legal", 650000, "Corporate"), + ("Product", 1500000, "Corporate"), + ("Design", 720000, "Corporate"), +] + +labels = [d[0] for d in departments] +values = np.array([d[1] for d in departments]) +groups = [d[2] for d in departments] n = len(labels) +# Group colors — colorblind-safe palette starting with Python Blue +group_colors = {"Technology": "#306998", "Revenue": "#E69F00", "Operations": "#009E73", "Corporate": "#CC79A7"} + # Scale radii by area (sqrt) for accurate visual perception radii = np.sqrt(values / values.max()) * 110 @@ -61,61 +64,61 @@ x_pos -= np.average(x_pos, weights=area_weights) y_pos -= np.average(y_pos, weights=area_weights) -# Axis ranges — symmetric with generous padding for balanced layout -x_ext = max(abs((x_pos - radii).min()), abs((x_pos + radii).max())) + 50 -y_ext = max(abs((y_pos - radii).min()), abs((y_pos + radii).max())) + 50 +# Format values for display +formatted = [f"${v / 1e6:.1f}M" if v >= 1e6 else f"${v / 1e3:.0f}K" for v in values] +shares = [f"{v / values.sum() * 100:.1f}" for v in values] +total = f"${values.sum() / 1e6:.1f}M" + +# Tight axis ranges for better canvas utilization +pad = 15 +x_lo = (x_pos - radii).min() - pad +x_hi = (x_pos + radii).max() + pad +y_lo = (y_pos - radii).min() - pad +y_hi = (y_pos + radii).max() + pad # Convert data-coordinate radii to pixel marker diameters -# With scaleanchor y=x, the smaller dimension constrains the scale fig_w, fig_h = 1600, 900 -m_l, m_r, m_t, m_b = 50, 50, 100, 60 +m_l, m_r, m_t, m_b = 35, 35, 85, 85 plot_w, plot_h = fig_w - m_l - m_r, fig_h - m_t - m_b -px_per_unit = min(plot_w / (2 * x_ext), plot_h / (2 * y_ext)) +px_per_unit = min(plot_w / (x_hi - x_lo), plot_h / (y_hi - y_lo)) marker_diameters = 2 * radii * px_per_unit -# Sequential blue palette — adaptive text color for readability -norm_vals = (values - values.min()) / (values.max() - values.min()) -text_colors = ["white" if nv > 0.3 else "#333" for nv in norm_vals] +# Text colors for contrast against group backgrounds +text_colors = [] +for g in groups: + c = group_colors[g] + lum = 0.299 * int(c[1:3], 16) + 0.587 * int(c[3:5], 16) + 0.114 * int(c[5:7], 16) + text_colors.append("white" if lum < 160 else "#333") -# Format values for display -formatted = [f"${v / 1e6:.1f}M" if v >= 1e6 else f"${v / 1e3:.0f}K" for v in values] -shares = [f"{v / values.sum() * 100:.1f}" for v in values] -total = f"${values.sum() / 1e6:.1f}M" - -# Build figure — go.Scatter with sized markers as primary visualization +# Build figure — one trace per group for idiomatic Plotly legend fig = go.Figure() -fig.add_trace( - go.Scatter( - x=x_pos, - y=y_pos, - mode="markers", - marker={ - "size": marker_diameters, - "sizemode": "diameter", - "color": values, - "colorscale": [ - [0, "#C6DBEF"], - [0.2, "#9ECAE1"], - [0.4, "#6BAED6"], - [0.6, "#3182BD"], - [0.8, "#1565A0"], - [1, "#08306B"], - ], - "showscale": False, - "opacity": 0.9, - "line": {"color": "white", "width": 2.5}, - }, - text=labels, - customdata=np.column_stack([formatted, shares]), - hovertemplate="%{text}
Budget: %{customdata[0]}
Share: %{customdata[1]}%", - showlegend=False, +for group_name, group_color in group_colors.items(): + idx = [i for i in range(n) if groups[i] == group_name] + fig.add_trace( + go.Scatter( + x=x_pos[idx], + y=y_pos[idx], + mode="markers", + name=group_name, + marker={ + "size": marker_diameters[idx], + "sizemode": "diameter", + "color": group_color, + "opacity": 0.9, + "line": {"color": "white", "width": 2.5}, + }, + text=[labels[i] for i in idx], + customdata=np.column_stack( + [[formatted[i] for i in idx], [shares[i] for i in idx], [groups[i] for i in idx]] + ), + hovertemplate="%{text} (%{customdata[2]})
Budget: %{customdata[0]}
Share: %{customdata[1]}%", + ) ) -) -# Text labels inside bubbles +# Text labels inside bubbles — minimum 14pt for readability for i in range(n): - font_size = max(12, min(20, int(radii[i] * 0.20))) + font_size = max(14, min(20, int(radii[i] * 0.22))) label_text = f"{labels[i]}
{formatted[i]}" if radii[i] > 35 else f"{labels[i]}" fig.add_annotation( x=x_pos[i], @@ -133,7 +136,7 @@ "x": 0.5, "xanchor": "center", }, - xaxis={"showgrid": False, "zeroline": False, "showticklabels": False, "title": "", "range": [-x_ext, x_ext]}, + xaxis={"showgrid": False, "zeroline": False, "showticklabels": False, "title": "", "range": [x_lo, x_hi]}, yaxis={ "showgrid": False, "zeroline": False, @@ -141,10 +144,18 @@ "title": "", "scaleanchor": "x", "scaleratio": 1, - "range": [-y_ext, y_ext], + "range": [y_lo, y_hi], }, template="plotly_white", - showlegend=False, + legend={ + "font": {"size": 16, "family": "Arial"}, + "orientation": "h", + "yanchor": "top", + "y": -0.04, + "xanchor": "center", + "x": 0.5, + "itemsizing": "constant", + }, margin={"l": m_l, "r": m_r, "t": m_t, "b": m_b}, paper_bgcolor="white", plot_bgcolor="white", @@ -153,8 +164,10 @@ # Total budget annotation below the cluster fig.add_annotation( text=f"Total: {total}", - x=0, - y=(y_pos - radii).min() - 25, + xref="paper", + yref="paper", + x=0.5, + y=-0.01, showarrow=False, font={"size": 18, "color": "#666", "family": "Arial"}, ) From 20ca72f3f355f9986363e246449619cd2cf54022 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 16:50:08 +0000 Subject: [PATCH 8/8] chore(plotly): update quality score 91 and review feedback for bubble-packed --- plots/bubble-packed/implementations/plotly.py | 3 +- plots/bubble-packed/metadata/plotly.yaml | 159 +++++++++--------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/plots/bubble-packed/implementations/plotly.py b/plots/bubble-packed/implementations/plotly.py index c4cfd582b6..4e59524280 100644 --- a/plots/bubble-packed/implementations/plotly.py +++ b/plots/bubble-packed/implementations/plotly.py @@ -1,6 +1,7 @@ -"""pyplots.ai +""" pyplots.ai bubble-packed: Basic Packed Bubble Chart Library: plotly 6.5.2 | Python 3.14.3 +Quality: 91/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/bubble-packed/metadata/plotly.yaml b/plots/bubble-packed/metadata/plotly.yaml index b7deed553c..8c86dd2f05 100644 --- a/plots/bubble-packed/metadata/plotly.yaml +++ b/plots/bubble-packed/metadata/plotly.yaml @@ -1,7 +1,7 @@ library: plotly specification_id: bubble-packed created: '2025-12-23T09:16:37Z' -updated: '2026-02-23T16:31:48Z' +updated: '2026-02-23T16:50:07Z' generated_by: claude-opus-4-6 workflow_run: 20456557994 issue: 0 @@ -10,7 +10,7 @@ library_version: 6.5.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/bubble-packed/plotly/plot.html -quality_score: 89 +quality_score: 91 impl_tags: dependencies: [] techniques: @@ -20,40 +20,38 @@ impl_tags: patterns: - data-generation - iteration-over-groups - dataprep: - - normalization + dataprep: [] styling: - - custom-colormap - minimal-chrome - edge-highlighting - alpha-blending review: strengths: - - Excellent circle packing algorithm with 600-iteration force simulation producing - clean, overlap-free layout - - Custom 6-stop sequential blue colorscale with adaptive text colors (white/dark) - for optimal readability - - 'Professional polish: white bubble outlines, hidden axes, weight-based centering, - size-adaptive labels' - - Rich Plotly interactivity via hovertemplate with budget amounts and share percentages - - Realistic, neutral department budget data with good value range (10x spread) + - Excellent force simulation with weighted centering for tight non-overlapping packing + - Colorblind-safe palette with luminance-based text contrast calculation + - Rich hover tooltips with budget amounts and share percentages via hovertemplate + and customdata + - Pixel-to-data coordinate conversion for accurate bubble marker sizing + - Size-adaptive labels prevent cramped text in smaller bubbles + - Both PNG and HTML output maximize utility weaknesses: - - Canvas utilization could be tighter — noticeable whitespace around the bubble - cluster - - Color and size both encode the same variable (value), missing opportunity for - a second data dimension - - Smallest bubble labels at 12pt are at the lower bound of comfortable readability - image_description: 'The plot displays a packed bubble chart titled "Department Budget - Allocation · bubble-packed · plotly · pyplots.ai". Fifteen circles of varying - sizes represent department budgets, packed tightly together without overlap. A - sequential blue color palette ranges from light blue (smaller budgets like Admin - $450K) to dark navy (larger budgets like Engineering $4.5M). Each bubble contains - a bold department name and budget value (e.g., "Engineering $4.5M", "R&D $3.8M"). - Smaller bubbles like "Admin" show only the name. White outlines (2.5px) separate - adjacent bubbles. Axes are hidden (no grid, ticks, or labels). A "Total: $27.3M" - annotation sits below the cluster. The background is clean white. The largest - bubbles (Engineering, R&D, Sales, Marketing) immediately draw the eye due to both - size and dark color.' + - Force simulation packing could be slightly tighter for a more compact overall + shape + - Minor asymmetry in the bubble cluster positioning due to force-directed approach + image_description: 'The plot shows a packed bubble chart titled "Department Budget + Allocation · bubble-packed · plotly · pyplots.ai" centered at the top in large + dark text. Fifteen circles of varying sizes represent department budgets, packed + tightly together without overlap in the center of a white canvas. Four color groups + are used: steel blue (#306998) for Technology departments (Engineering $4.5M, + R&D $3.8M, IT $2.1M, Data Science $1.6M, QA $880K), gold/amber (#E69F00) for Revenue + (Sales $3.2M, Marketing $2.8M), teal (#009E73) for Operations (Operations $1.8M, + Finance $1.2M, Support $1.1M, Admin $450K), and pink/mauve (#CC79A7) for Corporate + (Product $1.5M, HR $950K, Design $720K, Legal $650K). Each bubble contains the + department name in bold white or dark text (contrast-adjusted), with budget amounts + shown for larger bubbles. White borders (2.5px) separate the circles visually. + A "Total: $27.3M" annotation appears below the cluster, and a horizontal legend + at the bottom identifies the four groups. The bubble cluster fills roughly 60-65% + of the canvas, with balanced margins.' criteria_checklist: visual_quality: score: 28 @@ -64,44 +62,44 @@ review: score: 7 max: 8 passed: true - comment: Title at 32pt excellent. Annotation fonts explicitly calculated 12-20pt. - Smallest labels at 12pt on edge of ideal but legible. Adaptive text colors - ensure contrast. + comment: 'All font sizes explicitly set: title 32pt, bubble labels 14-20pt + adaptive, legend 16pt, total annotation 18pt. All readable at full resolution. + Minor deduction for tight fit in smallest bubbles.' - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: Force simulation with 600 iterations produces clean packing. No text - or bubble overlap visible. + comment: Force simulation with padding ensures no bubble overlap. All labels + contained within circles. No text collisions. - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: All 15 bubbles clearly visible with good size differentiation. Opacity - 0.9 with white borders provides excellent separation. + comment: All 15 bubbles clearly visible with 10x size range. White borders + provide clean separation. Opacity 0.9 gives appropriate visual weight. - id: VQ-04 name: Color Accessibility score: 4 max: 4 passed: true - comment: Sequential blue palette is colorblind-safe, relying on luminance - rather than hue distinction. + comment: 'Colorblind-safe palette: steel blue, gold, teal, pink. All distinguishable + under common color vision deficiencies.' - id: VQ-05 name: Layout & Canvas score: 3 max: 4 passed: true - comment: Bubble cluster well-centered but fills roughly 40-45% of canvas. - Notable whitespace on left and bottom-left. + comment: Bubble cluster fills ~60-65% of canvas. Minor deduction for slight + asymmetry and uneven corner spacing inherent to force-directed packing. - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Axes correctly hidden for packed bubble chart. Title descriptive - with correct format. Dollar values provide context. + comment: Axes appropriately hidden for packed bubble chart. Title is descriptive + with context. Budget values inside bubbles provide quantitative context. design_excellence: score: 15 max: 20 @@ -111,23 +109,24 @@ review: score: 6 max: 8 passed: true - comment: Custom 6-stop blue colorscale, white outlines, adaptive text coloring, - Arial font. Cohesive and professional, above defaults. + comment: Custom colorblind-safe palette, contrast-aware text colors via luminance + calculation, white marker borders, consistent Arial typography. Clearly + above defaults. - id: DE-02 name: Visual Refinement score: 5 max: 6 passed: true - comment: All chrome removed, clean white background, white outlines, weight-based - centering, generous margins. Minor gap in canvas utilization. + comment: Axes and gridlines hidden, clean white background, white marker borders, + opacity 0.9, horizontal legend, generous whitespace. - id: DE-03 name: Data Storytelling score: 4 max: 6 passed: true - comment: Size and color create clear visual hierarchy with Engineering as - focal point. Total annotation provides context. Both channels encode same - dimension. + comment: Size hierarchy communicates budget dominance. Color grouping reveals + Technology as largest spending category. Budget labels and total annotation + provide context. spec_compliance: score: 15 max: 15 @@ -137,54 +136,54 @@ review: score: 5 max: 5 passed: true - comment: Correct packed bubble chart with physics-based force simulation. - Position meaningless, only size matters. + comment: Correct packed bubble chart with force simulation, size-mapped circles, + hidden axes. - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Labels, values, area scaling, force packing, labels inside circles - all present. Optional grouping not required. + comment: Area-scaled circles, force packing, adaptive labels, color-coded + groups, hover tooltips all present. - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: Circle area correctly scaled by sqrt of value. Color maps to value. - Labels mapped to categories. + comment: Values correctly mapped to circle areas via sqrt. Groups mapped to + colors. 15 items within recommended range. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title follows required format with descriptive prefix. No legend - needed for single-series chart. + comment: Title includes spec-id, library, pyplots.ai format. Legend labels + match group data exactly. data_quality: - score: 14 + score: 15 max: 15 items: - id: DQ-01 name: Feature Coverage - score: 5 + score: 6 max: 6 passed: true - comment: 15 departments with 10x value range showing good variation. No grouping - dimension demonstrated. + comment: Wide size variation (10x range), four distinct groups with varying + membership, size-adaptive labels. - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Department budget allocation is a classic, neutral business scenario - with realistic department names. + comment: Department budgets at a tech company — real, comprehensible, neutral + business scenario with recognizable department names. - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Budget values $450K to $4.5M with $27.3M total are realistic for - a medium-to-large company. + comment: Budget values $450K-$4.5M and total $27.3M are realistic for a mid-to-large + company. code_quality: score: 10 max: 10 @@ -194,36 +193,36 @@ review: score: 3 max: 3 passed: true - comment: 'Clean linear flow: imports, data, circle packing, figure, annotations, - layout, save. No functions or classes.' + comment: 'Clean linear flow: imports, data, packing, formatting, figure, layout, + save. No functions or classes.' - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: np.random.seed(42) ensures deterministic layout. + comment: np.random.seed(42) set before random operations. Deterministic simulation. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: Only numpy and plotly.graph_objects imported, both used. + comment: Only numpy and plotly.graph_objects imported, both fully utilized. - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Force simulation appropriately complex. Marker diameter calculation - well-engineered. No fake UI. + comment: Well-structured force simulation, weighted centering, luminance-based + text contrast. Appropriate complexity. - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot.png (1600x900, scale=3) and plot.html. Current Plotly - API used. + comment: Saves plot.png via write_image at 4800x2700 and plot.html. Current + Plotly API. library_mastery: - score: 7 + score: 8 max: 10 items: - id: LM-01 @@ -231,13 +230,13 @@ review: score: 4 max: 5 passed: true - comment: Good use of go.Scatter with sizemode, hovertemplate, customdata, - add_annotation, scaleanchor, plotly_white template. + comment: Idiomatic go.Figure with per-group traces, hovertemplate with customdata, + add_annotation, update_layout, sizemode=diameter. - id: LM-02 name: Distinctive Features - score: 3 + score: 4 max: 5 passed: true - comment: Rich hovertemplate with formatted data, HTML export for interactivity, - sizemode diameter, custom colorscale. - verdict: REJECTED + comment: Rich hover tooltips via hovertemplate+customdata, HTML export, scaleanchor/scaleratio, + itemsizing=constant in legend. + verdict: APPROVED