diff --git a/plots/chord-basic/implementations/plotly.py b/plots/chord-basic/implementations/plotly.py
index 66dc4e5179..5a748e593d 100644
--- a/plots/chord-basic/implementations/plotly.py
+++ b/plots/chord-basic/implementations/plotly.py
@@ -1,19 +1,18 @@
""" pyplots.ai
chord-basic: Basic Chord Diagram
-Library: plotly 6.5.0 | Python 3.13.11
-Quality: 91/100 | Created: 2025-12-23
+Library: plotly 6.5.2 | Python 3.14
+Quality: 88/100 | Updated: 2026-04-06
"""
import numpy as np
import plotly.graph_objects as go
-# Data: Migration flows between 6 continents (bidirectional)
+# Data: Migration flows between 6 continents (bidirectional, millions of people)
continents = ["Africa", "Asia", "Europe", "N. America", "S. America", "Oceania"]
n = len(continents)
# Flow matrix (row = source, col = target) - realistic migration patterns
-np.random.seed(42)
flow_matrix = np.array(
[
[0, 15, 25, 10, 5, 3], # Africa to others
@@ -25,19 +24,33 @@
]
)
-# Colors for each continent (Python Blue first, then colorblind-safe palette)
-colors = ["#306998", "#FFD43B", "#2E8B57", "#DC143C", "#9370DB", "#FF8C00"]
+# Colors: Python Blue first, then colorblind-safe palette
+# Replaced green (#2E8B57) with teal (#00B4D8) for deuteranopia accessibility
+colors = ["#306998", "#FFD43B", "#00B4D8", "#DC143C", "#9370DB", "#FF8C00"]
+colors_dim = [
+ "rgba(48,105,152,0.4)",
+ "rgba(255,212,59,0.4)",
+ "rgba(0,180,216,0.4)",
+ "rgba(220,20,60,0.4)",
+ "rgba(147,112,219,0.4)",
+ "rgba(255,140,0,0.4)",
+]
# Calculate totals for each continent
totals = flow_matrix.sum(axis=0) + flow_matrix.sum(axis=1)
total_flow = flow_matrix.sum()
+# Identify the dominant corridor for storytelling emphasis
+max_flow_idx = np.unravel_index(np.argmax(flow_matrix + flow_matrix.T), flow_matrix.shape)
+dominant_src, dominant_tgt = max_flow_idx
+dominant_flow = flow_matrix[dominant_src, dominant_tgt] + flow_matrix[dominant_tgt, dominant_src]
+
# Calculate arc positions around the circle
gap = 0.02
arc_starts = []
arc_ends = []
current_pos = 0
-for _, total in enumerate(totals):
+for total in totals:
arc_starts.append(current_pos)
arc_ends.append(current_pos + (total / total_flow) * (1 - n * gap))
current_pos = arc_ends[-1] + gap
@@ -45,17 +58,33 @@
# Create figure
fig = go.Figure()
-# Draw outer arcs for each continent
+# Draw outer arcs with gradient-like layered effect
for i in range(n):
- # Generate arc points (outer)
angles_outer = np.linspace(2 * np.pi * arc_starts[i] - np.pi / 2, 2 * np.pi * arc_ends[i] - np.pi / 2, 100)
+ # Outer ring (thicker, slightly transparent for depth)
+ x_o = 1.02 * np.cos(angles_outer)
+ y_o = 1.02 * np.sin(angles_outer)
+ angles_rev = angles_outer[::-1]
+ x_i = 0.98 * np.cos(angles_rev)
+ y_i = 0.98 * np.sin(angles_rev)
+
+ fig.add_trace(
+ go.Scatter(
+ x=np.concatenate([x_o, x_i]),
+ y=np.concatenate([y_o, y_i]),
+ fill="toself",
+ fillcolor=colors_dim[i],
+ line={"color": "rgba(255,255,255,0)", "width": 0},
+ hoverinfo="skip",
+ showlegend=False,
+ )
+ )
+
+ # Inner ring (solid color, main arc)
x_outer = 1.0 * np.cos(angles_outer)
y_outer = 1.0 * np.sin(angles_outer)
-
- # Generate arc points (inner, reversed)
- angles_inner = np.linspace(2 * np.pi * arc_ends[i] - np.pi / 2, 2 * np.pi * arc_starts[i] - np.pi / 2, 100)
- x_inner = 0.95 * np.cos(angles_inner)
- y_inner = 0.95 * np.sin(angles_inner)
+ x_inner = 0.94 * np.cos(angles_rev)
+ y_inner = 0.94 * np.sin(angles_rev)
fig.add_trace(
go.Scatter(
@@ -63,98 +92,187 @@
y=np.concatenate([y_outer, y_inner]),
fill="toself",
fillcolor=colors[i],
- line=dict(color="white", width=1),
- hoverinfo="text",
- text=f"{continents[i]}
Total flow: {totals[i]}",
+ line={"color": "white", "width": 0.5},
+ hovertemplate=(
+ f"{continents[i]}
"
+ f"Outgoing: {int(flow_matrix[i].sum())}M
"
+ f"Incoming: {int(flow_matrix[:, i].sum())}M
"
+ f"Total: {int(totals[i])}M people"
+ ""
+ ),
name=continents[i],
showlegend=True,
+ legendgroup=continents[i],
)
)
-# Draw chords between continents
-shapes = []
+# Draw chords with enhanced visibility and storytelling
+min_chord_width = 0.008 # Minimum visual width for thin chords
for i in range(n):
src_pos = arc_starts[i]
for j in range(n):
- if i != j and flow_matrix[i, j] > 0:
- flow = flow_matrix[i, j]
- chord_width = (flow / total_flow) * (1 - n * gap)
-
- # Calculate target position offset
- tgt_base = arc_starts[j]
- tgt_offset = sum(
- (flow_matrix[k, j] / total_flow) * (1 - n * gap) for k in range(i) if flow_matrix[k, j] > 0
- )
+ if i == j or flow_matrix[i, j] == 0:
+ continue
- # Calculate chord endpoints (source)
- src_angle1 = 2 * np.pi * src_pos - np.pi / 2
- src_angle2 = 2 * np.pi * (src_pos + chord_width) - np.pi / 2
- x1 = 0.95 * np.cos(src_angle1)
- y1 = 0.95 * np.sin(src_angle1)
- x2 = 0.95 * np.cos(src_angle2)
- y2 = 0.95 * np.sin(src_angle2)
-
- # Calculate chord endpoints (target)
- tgt_start = tgt_base + tgt_offset
- tgt_end = tgt_start + chord_width
- tgt_angle1 = 2 * np.pi * tgt_start - np.pi / 2
- tgt_angle2 = 2 * np.pi * tgt_end - np.pi / 2
- x3 = 0.95 * np.cos(tgt_angle1)
- y3 = 0.95 * np.sin(tgt_angle1)
- x4 = 0.95 * np.cos(tgt_angle2)
- y4 = 0.95 * np.sin(tgt_angle2)
-
- # SVG path with quadratic bezier curves through center
- path = (
- f"M {x1},{y1} Q 0,0 {x3},{y3} A 0.95,0.95 0 0,1 {x4},{y4} Q 0,0 {x2},{y2} A 0.95,0.95 0 0,1 {x1},{y1} Z"
- )
+ flow = flow_matrix[i, j]
+ chord_width = max((flow / total_flow) * (1 - n * gap), min_chord_width)
+
+ # Highlight dominant corridor with higher opacity
+ is_dominant = (i == dominant_src and j == dominant_tgt) or (i == dominant_tgt and j == dominant_src)
+ opacity = 0.72 if is_dominant else 0.45
+ line_width = 1.0 if is_dominant else 0.3
+
+ # Target position offset based on prior incoming flows
+ tgt_base = arc_starts[j]
+ tgt_offset = sum(
+ max((flow_matrix[k, j] / total_flow) * (1 - n * gap), min_chord_width)
+ for k in range(i)
+ if flow_matrix[k, j] > 0
+ )
- shapes.append(
- dict(type="path", path=path, fillcolor=colors[i], opacity=0.6, line=dict(color=colors[i], width=0.5))
+ # Source arc endpoints
+ src_angle1 = 2 * np.pi * src_pos - np.pi / 2
+ src_angle2 = 2 * np.pi * (src_pos + chord_width) - np.pi / 2
+ sx1, sy1 = 0.94 * np.cos(src_angle1), 0.94 * np.sin(src_angle1)
+ sx2, sy2 = 0.94 * np.cos(src_angle2), 0.94 * np.sin(src_angle2)
+
+ # Target arc endpoints
+ tgt_start = tgt_base + tgt_offset
+ tgt_end = tgt_start + chord_width
+ tgt_angle1 = 2 * np.pi * tgt_start - np.pi / 2
+ tgt_angle2 = 2 * np.pi * tgt_end - np.pi / 2
+ tx1, ty1 = 0.94 * np.cos(tgt_angle1), 0.94 * np.sin(tgt_angle1)
+ tx2, ty2 = 0.94 * np.cos(tgt_angle2), 0.94 * np.sin(tgt_angle2)
+
+ # Build chord path with smoother bezier curves
+ src_angles = np.linspace(src_angle1, src_angle2, 20)
+ src_x = 0.94 * np.cos(src_angles)
+ src_y = 0.94 * np.sin(src_angles)
+
+ t = np.linspace(0, 1, 40)
+ bez1_x = (1 - t) ** 2 * sx2 + 2 * (1 - t) * t * 0 + t**2 * tx1
+ bez1_y = (1 - t) ** 2 * sy2 + 2 * (1 - t) * t * 0 + t**2 * ty1
+
+ tgt_angles = np.linspace(tgt_angle1, tgt_angle2, 20)
+ tgt_x = 0.94 * np.cos(tgt_angles)
+ tgt_y = 0.94 * np.sin(tgt_angles)
+
+ bez2_x = (1 - t) ** 2 * tx2 + 2 * (1 - t) * t * 0 + t**2 * sx1
+ bez2_y = (1 - t) ** 2 * ty2 + 2 * (1 - t) * t * 0 + t**2 * sy1
+
+ chord_x = np.concatenate([src_x, bez1_x, tgt_x, bez2_x])
+ chord_y = np.concatenate([src_y, bez1_y, tgt_y, bez2_y])
+
+ fig.add_trace(
+ go.Scatter(
+ x=chord_x,
+ y=chord_y,
+ fill="toself",
+ fillcolor=colors[i],
+ opacity=opacity,
+ line={"color": colors[i], "width": line_width},
+ hovertemplate=(
+ f"{continents[i]} → {continents[j]}
"
+ f"Flow: {flow}M people
"
+ f"Share: {flow / total_flow * 100:.1f}% of total"
+ ""
+ ),
+ showlegend=False,
+ hoveron="fills",
)
+ )
- src_pos += chord_width
+ src_pos += chord_width
-# Add continent labels around the perimeter
+# Add continent labels around the perimeter (horizontal for clarity)
for i in range(n):
mid_pos = (arc_starts[i] + arc_ends[i]) / 2
angle = 2 * np.pi * mid_pos - np.pi / 2
- label_radius = 1.12
+ label_radius = 1.16
+
+ lx = label_radius * np.cos(angle)
+ ly = label_radius * np.sin(angle)
+ angle_deg = np.degrees(angle) % 360
- # Rotate text for readability
- text_angle_deg = np.degrees(angle)
- if 90 < text_angle_deg < 270 or -270 < text_angle_deg < -90:
- text_angle_deg += 180
- rotation = -text_angle_deg + 90 if -90 < np.degrees(angle) < 90 else -text_angle_deg - 90
+ # Anchor text toward the circle center for clean alignment
+ if 45 < angle_deg < 135:
+ xanchor, yanchor = "center", "bottom"
+ elif 135 <= angle_deg < 225:
+ xanchor, yanchor = "right", "middle"
+ elif 225 <= angle_deg < 315:
+ xanchor, yanchor = "center", "top"
+ else:
+ xanchor, yanchor = "left", "middle"
fig.add_annotation(
- x=label_radius * np.cos(angle),
- y=label_radius * np.sin(angle),
- text=f"{continents[i]}",
- font=dict(size=18, color=colors[i]),
+ x=lx,
+ y=ly,
+ text=f"{continents[i]} {int(totals[i])}M",
+ font={"size": 20, "color": colors[i], "family": "Arial, Helvetica, sans-serif"},
showarrow=False,
- textangle=rotation,
+ xanchor=xanchor,
+ yanchor=yanchor,
)
-# Layout
-fig.update_layout(
- title=dict(
- text="Migration Flows Between Continents · chord-basic · plotly · pyplots.ai",
- font=dict(size=28),
- x=0.5,
- xanchor="center",
+# Subtitle annotation for storytelling
+fig.add_annotation(
+ text=(
+ f"Europe–Asia corridor dominates at {dominant_flow}M combined flow"
+ " · Chord width proportional to flow magnitude"
),
- shapes=shapes,
- xaxis=dict(showgrid=False, zeroline=False, showticklabels=False, range=[-1.4, 1.4]),
- yaxis=dict(showgrid=False, zeroline=False, showticklabels=False, range=[-1.4, 1.4], scaleanchor="x"),
+ xref="paper",
+ yref="paper",
+ x=0.5,
+ y=0.955,
+ showarrow=False,
+ font={"size": 17, "color": "#666666", "family": "Arial, Helvetica, sans-serif"},
+ xanchor="center",
+)
+
+# Layout with refined styling
+fig.update_layout(
+ title={
+ "text": "Migration Flows Between Continents · chord-basic · plotly · pyplots.ai",
+ "font": {"size": 28, "color": "#222222", "family": "Arial Black, Arial, sans-serif"},
+ "x": 0.5,
+ "xanchor": "center",
+ "y": 0.98,
+ },
+ xaxis={"showgrid": False, "zeroline": False, "showticklabels": False, "showline": False, "range": [-1.5, 1.5]},
+ yaxis={
+ "showgrid": False,
+ "zeroline": False,
+ "showticklabels": False,
+ "showline": False,
+ "range": [-1.6, 1.4],
+ "scaleanchor": "x",
+ },
template="plotly_white",
showlegend=True,
- legend=dict(font=dict(size=16), x=1.02, y=0.5, yanchor="middle"),
- margin=dict(l=50, r=150, t=100, b=50),
+ legend={
+ "font": {"size": 18, "family": "Arial, Helvetica, sans-serif"},
+ "title": {"text": "Continents", "font": {"size": 18, "color": "#444"}},
+ "x": 0.98,
+ "y": 0.02,
+ "xanchor": "right",
+ "yanchor": "bottom",
+ "bgcolor": "rgba(255,255,255,0.9)",
+ "bordercolor": "#ddd",
+ "borderwidth": 1,
+ "tracegroupgap": 6,
+ "itemsizing": "constant",
+ },
+ margin={"l": 20, "r": 20, "t": 80, "b": 15},
plot_bgcolor="white",
- paper_bgcolor="white",
+ paper_bgcolor="#FAFAFA",
+ hovermode="closest",
+ hoverlabel={
+ "bgcolor": "white",
+ "bordercolor": "#ccc",
+ "font": {"size": 16, "family": "Arial, Helvetica, sans-serif", "color": "#333"},
+ },
)
# Save outputs
-fig.write_image("plot.png", width=1600, height=900, scale=3)
+fig.write_image("plot.png", width=1200, height=1200, scale=3)
fig.write_html("plot.html", include_plotlyjs="cdn")
diff --git a/plots/chord-basic/metadata/plotly.yaml b/plots/chord-basic/metadata/plotly.yaml
index 8fcb4f99bb..915b9e5e12 100644
--- a/plots/chord-basic/metadata/plotly.yaml
+++ b/plots/chord-basic/metadata/plotly.yaml
@@ -1,162 +1,190 @@
library: plotly
specification_id: chord-basic
created: '2025-12-23T10:01:12Z'
-updated: '2025-12-23T10:06:59Z'
-generated_by: claude-opus-4-5-20251101
+updated: '2026-04-06T21:00:11Z'
+generated_by: claude-opus-4-6
workflow_run: 20457530538
issue: 0
-python_version: 3.13.11
-library_version: 6.5.0
+python_version: '3.14'
+library_version: 6.5.2
preview_url: https://storage.googleapis.com/pyplots-images/plots/chord-basic/plotly/plot.png
preview_html: https://storage.googleapis.com/pyplots-images/plots/chord-basic/plotly/plot.html
-quality_score: 91
+quality_score: 88
impl_tags:
dependencies: []
techniques:
- bezier-curves
- - html-export
+ - annotations
- hover-tooltips
+ - html-export
patterns:
- data-generation
- matrix-construction
- iteration-over-groups
dataprep: []
styling:
+ - minimal-chrome
- alpha-blending
+ - edge-highlighting
review:
strengths:
- - Excellent chord diagram implementation from scratch using Plotly low-level primitives
- - Clean visual design with well-chosen colorblind-safe color palette
- - Proper bidirectional flow handling with chord widths proportional to flow values
- - Good use of SVG path shapes for chord ribbons with bezier curves through center
- - Informative hover tooltips on outer arcs showing total flow per continent
- - Well-positioned rotated labels around the perimeter
- - Dual output format (PNG + interactive HTML) leverages Plotly strength
+ - Excellent data storytelling with dominant corridor highlighting and informative
+ subtitle
+ - Professional layered arc effect with depth perception
+ - Full spec compliance including all 4 required features (colors, proportional widths,
+ tooltips, bidirectional flows)
+ - Colorblind-safe palette with intentional green-to-teal replacement
+ - Clean, well-structured code with appropriate complexity
+ - Dual output (PNG + interactive HTML) leverages Plotly strengths
weaknesses:
- - Some smaller flow chords are difficult to distinguish due to overlapping
- - Interactive hover on individual chords would enhance the HTML version
- image_description: 'The chord diagram displays migration flows between 6 continents
- arranged in a circular layout. The outer ring shows colored arcs for each continent:
- Africa (blue, #306998), Asia (yellow, #FFD43B), Europe (green, #2E8B57), N. America
- (red, #DC143C), S. America (purple, #9370DB), and Oceania (orange, #FF8C00). Continent
- labels are positioned around the perimeter with rotated text for readability.
- Chords connect the continents with widths proportional to migration flow values,
- using semi-transparent fills (opacity 0.6) to show overlapping flows. The title
- "Migration Flows Between Continents · chord-basic · plotly · pyplots.ai" appears
- at the top. A legend on the right identifies each continent. The layout is clean
- with a white background.'
+ - Some thin chords between minor flows are hard to visually distinguish from each
+ other
+ - Vertical layout balance could be improved (more whitespace at top than bottom)
+ - Low-level construction is necessary but limits idiomatic library usage score
+ image_description: 'The plot displays a chord diagram with 6 continents arranged
+ around a circle. Each continent has a layered arc segment (outer translucent ring
+ + inner solid ring) with distinct colors: Africa (dark blue #306998), Asia (yellow
+ #FFD43B), Europe (teal #00B4D8), N. America (crimson #DC143C), S. America (purple
+ #9370DB), Oceania (orange #FF8C00). Continent labels with total flow values (e.g.,
+ "Europe 205M", "Asia 175M") are positioned around the perimeter in matching colors.
+ Chords of varying widths connect continents, with the Europe-Asia corridor visually
+ emphasized through higher opacity. The title reads "Migration Flows Between Continents
+ · chord-basic · plotly · pyplots.ai" with a subtitle noting "Europe–Asia corridor
+ dominates at 65M combined flow · Chord width proportional to flow magnitude".
+ A legend in the bottom-right lists all continents. Background is clean white (#FAFAFA
+ paper).'
criteria_checklist:
visual_quality:
- score: 36
- max: 40
+ score: 27
+ max: 30
items:
- id: VQ-01
name: Text Legibility
- score: 9
- max: 10
+ score: 7
+ max: 8
passed: true
- comment: Title and legend are clear; perimeter labels are readable but some
- rotation angles could be improved
+ comment: All font sizes explicitly set (title 28pt, labels 20pt, subtitle
+ 17pt, legend 18pt). All text clearly readable. Subtitle slightly small but
+ acceptable.
- id: VQ-02
name: No Overlap
- score: 8
- max: 8
+ score: 6
+ max: 6
passed: true
- comment: No overlapping text elements
+ comment: No overlapping text elements. Labels well-positioned around perimeter
+ with proper anchoring.
- id: VQ-03
name: Element Visibility
- score: 7
- max: 8
+ score: 5
+ max: 6
passed: true
- comment: Chords are well-sized with good opacity; some thin flows harder to
- see
+ comment: Chords clearly visible with minimum width enforcement. Dominant corridor
+ stands out via opacity. Some thinner chords hard to distinguish.
- id: VQ-04
name: Color Accessibility
- score: 5
- max: 5
+ score: 4
+ max: 4
passed: true
- comment: Distinct colors for all 6 continents, colorblind-friendly palette
+ comment: Palette explicitly avoids green, replacing with teal for deuteranopia
+ safety. Six distinct hues well-separated.
- id: VQ-05
- name: Layout Balance
- score: 5
- max: 5
+ name: Layout & Canvas
+ score: 3
+ max: 4
passed: true
- comment: Well-centered circle with good margins and legend placement
- - id: VQ-07
- name: Grid & Legend
+ comment: 1:1 aspect ratio ideal for circular diagram. Slight vertical imbalance
+ with more whitespace at top.
+ - id: VQ-06
+ name: Axis Labels & Title
score: 2
max: 2
passed: true
- comment: No grid (appropriate), legend well-positioned on right
+ comment: Axes appropriately hidden for chord diagram. Labels include units
+ (M for millions).
+ design_excellence:
+ score: 16
+ max: 20
+ items:
+ - id: DE-01
+ name: Aesthetic Sophistication
+ score: 6
+ max: 8
+ passed: true
+ comment: Custom palette, layered arc effect, styled hover labels, intentional
+ typography hierarchy. Clearly above defaults.
+ - id: DE-02
+ name: Visual Refinement
+ score: 5
+ max: 6
+ passed: true
+ comment: All grid/axes hidden. Clean white background. White line borders
+ on arcs. Outer ring glow effect adds polish.
+ - id: DE-03
+ name: Data Storytelling
+ score: 5
+ max: 6
+ passed: true
+ comment: Dominant corridor highlighted with higher opacity. Subtitle calls
+ out insight. Continent totals displayed. Strong visual hierarchy.
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 chord diagram implementation
- - id: SC-02
- name: Data Mapping
score: 5
max: 5
passed: true
- comment: Source/target/value correctly mapped to arcs and chords
- - id: SC-03
+ comment: Correct chord diagram with entities on circle perimeter connected
+ by proportional-width chords.
+ - id: SC-02
name: Required Features
- score: 5
- max: 5
+ score: 4
+ max: 4
passed: true
- comment: 'All spec features present: distinct colors, proportional widths,
- bidirectional flows'
- - id: SC-04
- name: Data Range
+ comment: Distinct colors, proportional chord widths, hover tooltips, bidirectional
+ flows all present.
+ - id: SC-03
+ name: Data Mapping
score: 3
max: 3
passed: true
- comment: All data visible within the circular layout
- - id: SC-05
- name: Legend Accuracy
- score: 2
- max: 2
- passed: true
- comment: Legend correctly identifies all 6 continents
- - id: SC-06
- name: Title Format
- score: 2
- max: 2
+ comment: Flow matrix correctly maps sources to targets. Arc sizes proportional
+ to totals.
+ - id: SC-04
+ name: Title & Legend
+ score: 3
+ max: 3
passed: true
- comment: 'Correct format: "Migration Flows Between Continents · chord-basic
- · plotly · pyplots.ai"'
+ comment: Title follows exact format. Legend shows all 6 continents with correct
+ colors.
data_quality:
- score: 18
- max: 20
+ score: 13
+ max: 15
items:
- id: DQ-01
name: Feature Coverage
- score: 7
- max: 8
+ score: 5
+ max: 6
passed: true
- comment: Shows bidirectional flows with varying magnitudes; good variety in
- flow sizes
+ comment: 6 entities with varying connection strengths. Both strong and weak
+ flows present. Some weaker flows hard to visually distinguish.
- id: DQ-02
name: Realistic Context
- score: 7
- max: 7
+ score: 5
+ max: 5
passed: true
- comment: Migration flows between continents is a realistic and comprehensible
- scenario
+ comment: Migration flows between continents is real-world, comprehensible,
+ neutral scenario.
- id: DQ-03
name: Appropriate Scale
- score: 4
- max: 5
+ score: 3
+ max: 4
passed: true
- comment: Values are plausible migration units; largest flows from Europe/Asia
- align with reality
+ comment: Values in millions, individual flows range 2-35M. Total ~704M is
+ slightly high but acceptable for demonstration.
code_quality:
- score: 9
+ score: 10
max: 10
items:
- id: CQ-01
@@ -164,40 +192,49 @@ review:
score: 3
max: 3
passed: true
- comment: 'Clean linear structure: imports → data → plot → save'
+ comment: 'Linear flow: imports, data, calculations, figure creation, 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) (though data is actually hardcoded matrix)
+ comment: Fully deterministic with hardcoded flow matrix.
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
- comment: Only numpy and plotly.graph_objects imported
+ 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: Well-structured with clear sections. Appropriate complexity. No fake
+ UI.
- id: CQ-05
- name: Output Correct
- score: 0
+ name: Output & API
+ score: 1
max: 1
passed: true
- comment: Saves as plot.png but also plot.html (minor)
- library_features:
- score: 3
- max: 5
+ comment: Saves plot.png and plot.html. Uses current Plotly API.
+ library_mastery:
+ score: 7
+ max: 10
items:
- - id: LF-01
- name: Uses distinctive library features
+ - id: LM-01
+ name: Idiomatic Usage
score: 3
max: 5
passed: true
- comment: Uses go.Scatter with SVG paths for chords; could leverage hover interactivity
- more in the HTML output
- verdict: APPROVED
+ comment: Plotly lacks native chord diagram. Manual go.Scatter construction
+ necessary. Good use of available features.
+ - id: LM-02
+ name: Distinctive Features
+ score: 4
+ max: 5
+ passed: true
+ comment: Leverages hovertemplate, hoveron=fills, HTML export, hoverlabel customization.
+ Genuinely distinctive Plotly capabilities.
+ verdict: REJECTED