Skip to content

Commit ce7c88b

Browse files
update(arc-basic): seaborn — comprehensive quality review (#4368)
## Summary Updated **seaborn** implementation for **arc-basic**. **Changes:** Comprehensive quality review and update ### Changes - Updated implementation with improved code quality and visual design ## Test Plan - [x] Preview images uploaded to GCS staging - [x] Implementation file passes ruff format/check - [x] Metadata YAML updated with current versions - [ ] Automated review triggered --- Generated with [Claude Code](https://claude.com/claude-code) `/update` command --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 287b688 commit ce7c88b

2 files changed

Lines changed: 330 additions & 105 deletions

File tree

Lines changed: 120 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,151 @@
11
""" pyplots.ai
22
arc-basic: Basic Arc Diagram
3-
Library: seaborn 0.13.2 | Python 3.13.11
4-
Quality: 88/100 | Created: 2025-12-23
3+
Library: seaborn 0.13.2 | Python 3.14.3
4+
Quality: 91/100 | Updated: 2026-02-23
55
"""
66

7-
import matplotlib.patches as patches
87
import matplotlib.pyplot as plt
98
import numpy as np
109
import pandas as pd
1110
import seaborn as sns
12-
from matplotlib.lines import Line2D
1311

1412

15-
# Data: Character interactions in a story (12 characters for readability)
16-
np.random.seed(42)
13+
# Data: Character interactions in a story (12 characters)
1714
nodes = ["Alice", "Bob", "Carol", "Dave", "Eve", "Frank", "Grace", "Henry", "Ivy", "Jack", "Kate", "Leo"]
1815
n_nodes = len(nodes)
1916

20-
# Create edges with weights (character interaction strength)
17+
# Edges: (source_index, target_index, interaction_weight)
2118
edges = [
22-
(0, 1, 5), # Alice - Bob (close friends)
23-
(0, 3, 2), # Alice - Dave
24-
(1, 2, 4), # Bob - Carol
25-
(1, 4, 3), # Bob - Eve
26-
(2, 5, 2), # Carol - Frank
27-
(3, 4, 5), # Dave - Eve (close)
28-
(3, 6, 3), # Dave - Grace
29-
(4, 7, 4), # Eve - Henry
30-
(5, 6, 2), # Frank - Grace
31-
(0, 11, 1), # Alice - Leo (distant, long arc)
32-
(2, 6, 3), # Carol - Grace
33-
(1, 5, 2), # Bob - Frank
34-
(7, 8, 4), # Henry - Ivy
35-
(8, 9, 3), # Ivy - Jack
36-
(9, 10, 5), # Jack - Kate (close)
37-
(10, 11, 2), # Kate - Leo
38-
(6, 9, 2), # Grace - Jack
39-
(5, 10, 1), # Frank - Kate (distant)
19+
(0, 1, 5), # Alice Bob
20+
(0, 3, 2), # Alice Dave
21+
(1, 2, 4), # Bob Carol
22+
(1, 4, 3), # Bob Eve
23+
(2, 5, 2), # Carol Frank
24+
(3, 4, 5), # Dave Eve
25+
(3, 6, 3), # Dave Grace
26+
(4, 7, 4), # Eve Henry
27+
(5, 6, 2), # Frank Grace
28+
(0, 11, 1), # Alice Leo (long-range)
29+
(2, 6, 3), # Carol Grace
30+
(1, 5, 2), # Bob Frank
31+
(7, 8, 4), # Henry Ivy
32+
(8, 9, 3), # Ivy Jack
33+
(9, 10, 5), # Jack Kate
34+
(10, 11, 2), # Kate Leo
35+
(6, 9, 2), # Grace Jack
36+
(5, 10, 1), # Frank Kate (long-range)
4037
]
4138

42-
# Node positions along x-axis
4339
x_positions = np.arange(n_nodes)
4440

45-
# Create figure with seaborn styling - use whitegrid then disable grid
41+
# Build long-form DataFrame of arc coordinates for seaborn lineplot
42+
arc_rows = []
43+
n_pts = 80
44+
for eid, (src, tgt, w) in enumerate(edges):
45+
x1, x2 = x_positions[src], x_positions[tgt]
46+
dist = abs(x2 - x1)
47+
h = dist * 0.4
48+
t = np.linspace(0, np.pi, n_pts)
49+
cx, rx = (x1 + x2) / 2, dist / 2
50+
arc_x = cx + rx * np.cos(np.pi - t)
51+
arc_y = h * np.sin(t)
52+
for xi, yi in zip(arc_x, arc_y, strict=True):
53+
arc_rows.append({"x": xi, "y": yi, "weight": w, "edge_id": eid})
54+
55+
arc_df = pd.DataFrame(arc_rows)
56+
57+
# Categorize weights for seaborn hue encoding
58+
strength_names = {1: "1 · Weak", 2: "2 · Light", 3: "3 · Moderate", 4: "4 · Strong", 5: "5 · Intense"}
59+
cat_order = [strength_names[k] for k in sorted(strength_names)]
60+
arc_df["strength"] = pd.Categorical(arc_df["weight"].map(strength_names), categories=cat_order, ordered=True)
61+
62+
# Theme
4663
sns.set_theme(style="white", context="talk", font_scale=1.1)
4764
fig, ax = plt.subplots(figsize=(16, 9))
4865

49-
# Explicitly disable grid for arc diagram (abstract visualization)
50-
ax.grid(False)
51-
52-
# Plot nodes as points using seaborn
53-
node_data = pd.DataFrame({"x": x_positions, "y": np.zeros(n_nodes), "node": nodes})
54-
sns.scatterplot(data=node_data, x="x", y="y", s=600, color="#306998", zorder=5, ax=ax, legend=False)
55-
56-
# Draw arcs for each edge
57-
for start, end, weight in edges:
58-
x1, x2 = x_positions[start], x_positions[end]
59-
# Arc height proportional to distance between nodes
60-
distance = abs(x2 - x1)
61-
height = distance * 0.4
62-
63-
# Arc thickness based on weight
64-
linewidth = weight * 0.8 + 0.5
65-
66-
# Create arc using matplotlib patches
67-
center_x = (x1 + x2) / 2
68-
width = abs(x2 - x1)
69-
70-
arc = patches.Arc(
71-
(center_x, 0),
72-
width,
73-
height * 2,
74-
angle=0,
75-
theta1=0,
76-
theta2=180,
77-
color="#FFD43B",
78-
linewidth=linewidth,
79-
alpha=0.6,
80-
zorder=2,
81-
)
82-
ax.add_patch(arc)
83-
84-
# Add node labels below the axis
85-
for i, name in enumerate(nodes):
86-
ax.text(x_positions[i], -0.15, name, ha="center", va="top", fontsize=16, fontweight="bold", color="#306998")
87-
88-
# Styling - adjust limits for 12 nodes
89-
ax.set_xlim(-0.8, n_nodes - 0.2)
90-
ax.set_ylim(-0.8, 5.0) # More vertical space for longer arcs
91-
ax.set_title("arc-basic · seaborn · pyplots.ai", fontsize=24, pad=20)
92-
93-
# Remove all axis elements for abstract visualization
94-
for spine in ax.spines.values():
95-
spine.set_visible(False)
96-
ax.set_xticks([])
97-
ax.set_yticks([])
98-
99-
# Add a subtle horizontal baseline
100-
ax.axhline(y=0, color="#306998", linewidth=2, alpha=0.3, zorder=1)
66+
# Viridis palette (reversed so stronger connections = darker/more prominent)
67+
viridis = sns.color_palette("viridis", as_cmap=True)
68+
palette = [viridis(v) for v in [0.82, 0.66, 0.48, 0.30, 0.12]]
69+
70+
# Draw arcs via seaborn lineplot (hue=color by strength, size=thickness by weight)
71+
sns.lineplot(
72+
data=arc_df,
73+
x="x",
74+
y="y",
75+
hue="strength",
76+
size="weight",
77+
units="edge_id",
78+
estimator=None,
79+
palette=palette,
80+
sizes=(2.0, 6.0),
81+
alpha=0.7,
82+
ax=ax,
83+
sort=False,
84+
)
10185

102-
# Add legend for arc thickness (interaction strength)
103-
legend_elements = [
104-
Line2D([0], [0], color="#FFD43B", linewidth=1.3, alpha=0.6, label="Weak (1)"),
105-
Line2D([0], [0], color="#FFD43B", linewidth=2.9, alpha=0.6, label="Medium (3)"),
106-
Line2D([0], [0], color="#FFD43B", linewidth=4.5, alpha=0.6, label="Strong (5)"),
107-
]
108-
legend = ax.legend(
109-
handles=legend_elements,
86+
# Keep only color legend entries (remove redundant size entries)
87+
handles, labels = ax.get_legend_handles_labels()
88+
cat_set = set(cat_order)
89+
filtered = [(h, lab) for h, lab in zip(handles, labels, strict=True) if lab in cat_set]
90+
ax.legend(
91+
[h for h, _ in filtered],
92+
[lab for _, lab in filtered],
11093
title="Interaction Strength",
94+
title_fontsize=20,
95+
fontsize=16,
11196
loc="upper right",
112-
fontsize=14,
113-
title_fontsize=16,
11497
frameon=True,
11598
fancybox=True,
11699
framealpha=0.9,
100+
edgecolor="#cccccc",
101+
)
102+
103+
# Draw nodes with seaborn scatterplot
104+
node_df = pd.DataFrame({"x": x_positions, "y": np.zeros(n_nodes)})
105+
sns.scatterplot(
106+
data=node_df, x="x", y="y", s=600, color="#306998", zorder=5, ax=ax, legend=False, edgecolor="white", linewidth=1.5
107+
)
108+
109+
# Node labels below the baseline
110+
for i, name in enumerate(nodes):
111+
ax.text(x_positions[i], -0.22, name, ha="center", va="top", fontsize=16, fontweight="medium", color="#306998")
112+
113+
# Storytelling: highlight the contrast between arc distance and weight
114+
# The tallest arc (Alice–Leo) is the weakest connection
115+
ax.annotate(
116+
"Weakest link, longest reach",
117+
xy=(5.5, 4.2),
118+
fontsize=13,
119+
fontstyle="italic",
120+
color="#555555",
121+
ha="center",
122+
xytext=(2.0, 4.9),
123+
arrowprops={"arrowstyle": "->", "color": "#888888", "lw": 1.0},
124+
)
125+
# Three strongest bonds are all between nearest neighbors
126+
ax.annotate(
127+
"Strongest local bonds",
128+
xy=(3.5, 0.42),
129+
fontsize=13,
130+
fontstyle="italic",
131+
color="#555555",
132+
ha="center",
133+
xytext=(6.0, 2.0),
134+
arrowprops={"arrowstyle": "->", "color": "#888888", "lw": 1.0},
117135
)
118136

137+
# Axis styling
138+
ax.set_xlim(-0.8, n_nodes - 0.2)
139+
ax.set_ylim(-0.45, 5.6)
140+
ax.set_title("arc-basic \u00b7 seaborn \u00b7 pyplots.ai", fontsize=24, fontweight="medium", pad=20)
141+
ax.set_xlabel("")
142+
ax.set_ylabel("")
143+
sns.despine(ax=ax, left=True, bottom=True)
144+
ax.set_xticks([])
145+
ax.set_yticks([])
146+
147+
# Subtle horizontal baseline
148+
ax.axhline(y=0, color="#306998", linewidth=2, alpha=0.3, zorder=1)
149+
119150
plt.tight_layout()
120151
plt.savefig("plot.png", dpi=300, bbox_inches="tight")

0 commit comments

Comments
 (0)