diff --git a/plots/arc-basic/implementations/seaborn.py b/plots/arc-basic/implementations/seaborn.py index 08079e3ce0..56889b7c4d 100644 --- a/plots/arc-basic/implementations/seaborn.py +++ b/plots/arc-basic/implementations/seaborn.py @@ -1,120 +1,151 @@ """ pyplots.ai arc-basic: Basic Arc Diagram -Library: seaborn 0.13.2 | Python 3.13.11 -Quality: 88/100 | Created: 2025-12-23 +Library: seaborn 0.13.2 | Python 3.14.3 +Quality: 91/100 | Updated: 2026-02-23 """ -import matplotlib.patches as patches import matplotlib.pyplot as plt import numpy as np import pandas as pd import seaborn as sns -from matplotlib.lines import Line2D -# Data: Character interactions in a story (12 characters for readability) -np.random.seed(42) +# Data: Character interactions in a story (12 characters) nodes = ["Alice", "Bob", "Carol", "Dave", "Eve", "Frank", "Grace", "Henry", "Ivy", "Jack", "Kate", "Leo"] n_nodes = len(nodes) -# Create edges with weights (character interaction strength) +# Edges: (source_index, target_index, interaction_weight) edges = [ - (0, 1, 5), # Alice - Bob (close friends) - (0, 3, 2), # Alice - Dave - (1, 2, 4), # Bob - Carol - (1, 4, 3), # Bob - Eve - (2, 5, 2), # Carol - Frank - (3, 4, 5), # Dave - Eve (close) - (3, 6, 3), # Dave - Grace - (4, 7, 4), # Eve - Henry - (5, 6, 2), # Frank - Grace - (0, 11, 1), # Alice - Leo (distant, long arc) - (2, 6, 3), # Carol - Grace - (1, 5, 2), # Bob - Frank - (7, 8, 4), # Henry - Ivy - (8, 9, 3), # Ivy - Jack - (9, 10, 5), # Jack - Kate (close) - (10, 11, 2), # Kate - Leo - (6, 9, 2), # Grace - Jack - (5, 10, 1), # Frank - Kate (distant) + (0, 1, 5), # Alice – Bob + (0, 3, 2), # Alice – Dave + (1, 2, 4), # Bob – Carol + (1, 4, 3), # Bob – Eve + (2, 5, 2), # Carol – Frank + (3, 4, 5), # Dave – Eve + (3, 6, 3), # Dave – Grace + (4, 7, 4), # Eve – Henry + (5, 6, 2), # Frank – Grace + (0, 11, 1), # Alice – Leo (long-range) + (2, 6, 3), # Carol – Grace + (1, 5, 2), # Bob – Frank + (7, 8, 4), # Henry – Ivy + (8, 9, 3), # Ivy – Jack + (9, 10, 5), # Jack – Kate + (10, 11, 2), # Kate – Leo + (6, 9, 2), # Grace – Jack + (5, 10, 1), # Frank – Kate (long-range) ] -# Node positions along x-axis x_positions = np.arange(n_nodes) -# Create figure with seaborn styling - use whitegrid then disable grid +# Build long-form DataFrame of arc coordinates for seaborn lineplot +arc_rows = [] +n_pts = 80 +for eid, (src, tgt, w) in enumerate(edges): + x1, x2 = x_positions[src], x_positions[tgt] + dist = abs(x2 - x1) + h = dist * 0.4 + t = np.linspace(0, np.pi, n_pts) + cx, rx = (x1 + x2) / 2, dist / 2 + arc_x = cx + rx * np.cos(np.pi - t) + arc_y = h * np.sin(t) + for xi, yi in zip(arc_x, arc_y, strict=True): + arc_rows.append({"x": xi, "y": yi, "weight": w, "edge_id": eid}) + +arc_df = pd.DataFrame(arc_rows) + +# Categorize weights for seaborn hue encoding +strength_names = {1: "1 · Weak", 2: "2 · Light", 3: "3 · Moderate", 4: "4 · Strong", 5: "5 · Intense"} +cat_order = [strength_names[k] for k in sorted(strength_names)] +arc_df["strength"] = pd.Categorical(arc_df["weight"].map(strength_names), categories=cat_order, ordered=True) + +# Theme sns.set_theme(style="white", context="talk", font_scale=1.1) fig, ax = plt.subplots(figsize=(16, 9)) -# Explicitly disable grid for arc diagram (abstract visualization) -ax.grid(False) - -# Plot nodes as points using seaborn -node_data = pd.DataFrame({"x": x_positions, "y": np.zeros(n_nodes), "node": nodes}) -sns.scatterplot(data=node_data, x="x", y="y", s=600, color="#306998", zorder=5, ax=ax, legend=False) - -# Draw arcs for each edge -for start, end, weight in edges: - x1, x2 = x_positions[start], x_positions[end] - # Arc height proportional to distance between nodes - distance = abs(x2 - x1) - height = distance * 0.4 - - # Arc thickness based on weight - linewidth = weight * 0.8 + 0.5 - - # Create arc using matplotlib patches - center_x = (x1 + x2) / 2 - width = abs(x2 - x1) - - arc = patches.Arc( - (center_x, 0), - width, - height * 2, - angle=0, - theta1=0, - theta2=180, - color="#FFD43B", - linewidth=linewidth, - alpha=0.6, - zorder=2, - ) - ax.add_patch(arc) - -# Add node labels below the axis -for i, name in enumerate(nodes): - ax.text(x_positions[i], -0.15, name, ha="center", va="top", fontsize=16, fontweight="bold", color="#306998") - -# Styling - adjust limits for 12 nodes -ax.set_xlim(-0.8, n_nodes - 0.2) -ax.set_ylim(-0.8, 5.0) # More vertical space for longer arcs -ax.set_title("arc-basic · seaborn · pyplots.ai", fontsize=24, pad=20) - -# Remove all axis elements for abstract visualization -for spine in ax.spines.values(): - spine.set_visible(False) -ax.set_xticks([]) -ax.set_yticks([]) - -# Add a subtle horizontal baseline -ax.axhline(y=0, color="#306998", linewidth=2, alpha=0.3, zorder=1) +# Viridis palette (reversed so stronger connections = darker/more prominent) +viridis = sns.color_palette("viridis", as_cmap=True) +palette = [viridis(v) for v in [0.82, 0.66, 0.48, 0.30, 0.12]] + +# Draw arcs via seaborn lineplot (hue=color by strength, size=thickness by weight) +sns.lineplot( + data=arc_df, + x="x", + y="y", + hue="strength", + size="weight", + units="edge_id", + estimator=None, + palette=palette, + sizes=(2.0, 6.0), + alpha=0.7, + ax=ax, + sort=False, +) -# Add legend for arc thickness (interaction strength) -legend_elements = [ - Line2D([0], [0], color="#FFD43B", linewidth=1.3, alpha=0.6, label="Weak (1)"), - Line2D([0], [0], color="#FFD43B", linewidth=2.9, alpha=0.6, label="Medium (3)"), - Line2D([0], [0], color="#FFD43B", linewidth=4.5, alpha=0.6, label="Strong (5)"), -] -legend = ax.legend( - handles=legend_elements, +# Keep only color legend entries (remove redundant size entries) +handles, labels = ax.get_legend_handles_labels() +cat_set = set(cat_order) +filtered = [(h, lab) for h, lab in zip(handles, labels, strict=True) if lab in cat_set] +ax.legend( + [h for h, _ in filtered], + [lab for _, lab in filtered], title="Interaction Strength", + title_fontsize=20, + fontsize=16, loc="upper right", - fontsize=14, - title_fontsize=16, frameon=True, fancybox=True, framealpha=0.9, + edgecolor="#cccccc", +) + +# Draw nodes with seaborn scatterplot +node_df = pd.DataFrame({"x": x_positions, "y": np.zeros(n_nodes)}) +sns.scatterplot( + data=node_df, x="x", y="y", s=600, color="#306998", zorder=5, ax=ax, legend=False, edgecolor="white", linewidth=1.5 +) + +# Node labels below the baseline +for i, name in enumerate(nodes): + ax.text(x_positions[i], -0.22, name, ha="center", va="top", fontsize=16, fontweight="medium", color="#306998") + +# Storytelling: highlight the contrast between arc distance and weight +# The tallest arc (Alice–Leo) is the weakest connection +ax.annotate( + "Weakest link, longest reach", + xy=(5.5, 4.2), + fontsize=13, + fontstyle="italic", + color="#555555", + ha="center", + xytext=(2.0, 4.9), + arrowprops={"arrowstyle": "->", "color": "#888888", "lw": 1.0}, +) +# Three strongest bonds are all between nearest neighbors +ax.annotate( + "Strongest local bonds", + xy=(3.5, 0.42), + fontsize=13, + fontstyle="italic", + color="#555555", + ha="center", + xytext=(6.0, 2.0), + arrowprops={"arrowstyle": "->", "color": "#888888", "lw": 1.0}, ) +# Axis styling +ax.set_xlim(-0.8, n_nodes - 0.2) +ax.set_ylim(-0.45, 5.6) +ax.set_title("arc-basic \u00b7 seaborn \u00b7 pyplots.ai", fontsize=24, fontweight="medium", pad=20) +ax.set_xlabel("") +ax.set_ylabel("") +sns.despine(ax=ax, left=True, bottom=True) +ax.set_xticks([]) +ax.set_yticks([]) + +# Subtle horizontal baseline +ax.axhline(y=0, color="#306998", linewidth=2, alpha=0.3, zorder=1) + plt.tight_layout() plt.savefig("plot.png", dpi=300, bbox_inches="tight") diff --git a/plots/arc-basic/metadata/seaborn.yaml b/plots/arc-basic/metadata/seaborn.yaml index 098aea0f98..79f97375e0 100644 --- a/plots/arc-basic/metadata/seaborn.yaml +++ b/plots/arc-basic/metadata/seaborn.yaml @@ -1,38 +1,232 @@ library: seaborn specification_id: arc-basic created: '2025-12-23T08:49:25Z' -updated: '2025-12-23T09:46:10Z' -generated_by: claude-opus-4-5-20251101 +updated: '2026-02-23T21:52:19Z' +generated_by: claude-opus-4-6 workflow_run: 20455960864 issue: 0 -python_version: 3.13.11 +python_version: 3.14.3 library_version: 0.13.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/arc-basic/seaborn/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/arc-basic/seaborn/plot_thumb.png preview_html: null -quality_score: 88 +quality_score: 91 impl_tags: dependencies: [] techniques: + - annotations - custom-legend - - patches - - manual-ticks patterns: - data-generation - iteration-over-groups dataprep: [] styling: - alpha-blending + - edge-highlighting review: strengths: - - Excellent visual clarity with clear node labels and well-proportioned arcs - - Arc height correctly proportional to node distance as specified - - Weight-based arc thickness adds meaningful information dimension - - Good use of transparency (alpha=0.6) for overlapping arcs - - Realistic character interaction scenario demonstrates practical use case - - Clean title format and well-placed legend + - Excellent data storytelling with two annotations creating a compelling narrative + contrast between long-range weak and short-range strong connections + - 'Cohesive color scheme: reversed viridis for semantic encoding (darker = stronger) + plus Python Blue nodes' + - All spines/ticks removed with subtle baseline creates a clean, modern look + - Full spec compliance with all required features (proportional height, semi-transparency, + color coding, thickness) + - Well-crafted legend with styled frame, appropriate title, and descriptive category + labels weaknesses: - - Residual x and y axis labels still visible on the plot - need to call ax.set_xlabel - and ax.set_ylabel to remove them completely - - Minimal use of seaborn-specific features - primarily matplotlib with seaborn styling - only + - Annotation text at fontsize=13 is noticeably smaller than other text elements + (16-24pt) + - Some arc crowding in the Dave-Eve-Frank cluster makes individual arcs harder to + trace + image_description: 'The plot displays a basic arc diagram with 12 character nodes + (Alice through Leo) arranged along a horizontal baseline. Curved arcs above the + baseline connect pairs of characters, with arc height proportional to the distance + between connected nodes. Arcs are color-coded using a reversed viridis palette + across 5 interaction strength levels: Weak (yellow-green), Light (green), Moderate + (teal), Strong (blue), and Intense (dark purple). Arc thickness also varies with + weight — thicker arcs indicate stronger connections. Two italic annotations with + arrows provide narrative context: "Weakest link, longest reach" points to the + tall Alice–Leo arc spanning the full diagram, while "Strongest local bonds" points + to the cluster of short, thick arcs near Dave–Eve. Nodes are rendered as dark + blue (#306998) dots with white edges. The title "arc-basic · seaborn · pyplots.ai" + appears at the top. A legend in the upper right shows all 5 strength categories. + All spines and ticks are removed, and a subtle light-blue horizontal baseline + anchors the nodes.' + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: All font sizes explicitly set (title 24pt, legend 16/20pt, node labels + 16pt). Annotation text at 13pt slightly small. + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: No text overlap. Node labels well-spaced, annotations clear, legend + positioned well. + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Arcs visible with sizes 2.0-6.0 and alpha=0.7. Some crowding in Dave-Eve-Frank + cluster. + - id: VQ-04 + name: Color Accessibility + score: 4 + max: 4 + passed: true + comment: Viridis palette is perceptually uniform and colorblind-safe. + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: 16:9 canvas well-utilized, balanced margins, nothing cut off. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Axes appropriately hidden for arc diagram. Nodes labeled directly. + design_excellence: + score: 16 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + passed: true + comment: 'Strong design: reversed viridis palette, Python Blue nodes, styled + legend, cohesive color scheme.' + - id: DE-02 + name: Visual Refinement + score: 5 + max: 6 + passed: true + comment: All spines removed, no ticks, subtle baseline at alpha=0.3, clean + white theme, styled legend. + - id: DE-03 + name: Data Storytelling + score: 5 + max: 6 + passed: true + comment: Two annotations create narrative contrast between long-range weak + and short-range strong connections. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: 'Correct arc diagram: nodes on horizontal line, curved arcs above.' + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: 'All features: proportional height, semi-transparency, color coding, + thickness by weight.' + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: Nodes correctly positioned, arcs connect correct pairs, height/color/thickness + mapped correctly. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title in correct format, legend with descriptive category labels. + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 12 nodes, 18 edges, varied weights, short and long range connections, + dense and sparse regions. + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Character interactions in a story - real, comprehensible, neutral + scenario. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: 12 nodes within recommended range, 18 edges good density, weights + 1-5 sensible scale. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Clean linear flow, no functions or classes. + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: All data hardcoded and deterministic. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All four imports used, no unused imports. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean arc generation, good pd.Categorical usage, appropriate complexity. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves as plot.png at dpi=300 with bbox_inches tight. + library_mastery: + score: 7 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Good use of sns.lineplot with units/hue/size, sns.scatterplot, set_theme, + despine. Falls back to matplotlib for arc geometry. + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: units+estimator=None is distinctively seaborn, hue+size simultaneous + encoding, long-form data paradigm. + verdict: APPROVED