Skip to content

Commit 6f4a89c

Browse files
update(arc-basic): plotnine — comprehensive quality review (#4372)
## Summary Updated **plotnine** 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 8023f9f commit 6f4a89c

2 files changed

Lines changed: 216 additions & 170 deletions

File tree

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
""" pyplots.ai
22
arc-basic: Basic Arc Diagram
3-
Library: plotnine 0.15.2 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-23
3+
Library: plotnine 0.15.3 | Python 3.14.3
4+
Quality: 90/100 | Updated: 2026-02-23
55
"""
66

77
import sys
@@ -13,27 +13,32 @@
1313
import pandas as pd # noqa: E402
1414
from plotnine import ( # noqa: E402
1515
aes,
16-
element_blank,
16+
annotate,
17+
coord_cartesian,
18+
element_rect,
1719
element_text,
1820
geom_path,
1921
geom_point,
22+
geom_segment,
2023
geom_text,
2124
ggplot,
25+
guide_colorbar,
2226
labs,
27+
scale_alpha_identity,
28+
scale_color_gradient,
2329
scale_size_identity,
2430
theme,
31+
theme_void,
2532
)
2633

2734

2835
# Data: Character interactions in a story chapter
29-
np.random.seed(42)
30-
3136
nodes = ["Alice", "Bob", "Carol", "David", "Eve", "Frank", "Grace", "Henry", "Iris", "Jack"]
3237
n_nodes = len(nodes)
3338

34-
# Edges: pairs of connected nodes with weights (source, target, weight)
39+
# Edges: (source_idx, target_idx, weight)
3540
edges = [
36-
(0, 1, 3), # Alice-Bob (strong connection)
41+
(0, 1, 3), # Alice-Bob (strong)
3742
(0, 3, 2), # Alice-David
3843
(1, 2, 2), # Bob-Carol
3944
(2, 4, 1), # Carol-Eve
@@ -52,74 +57,90 @@
5257

5358
# Node positions along x-axis
5459
x_positions = np.linspace(0, 1, n_nodes)
55-
y_baseline = 0.1
56-
57-
# Create arc paths dataframe
58-
arc_data = []
59-
arc_id = 0
60+
y_baseline = 0.0
6061

61-
for start, end, weight in edges:
62-
x_start = x_positions[start]
63-
x_end = x_positions[end]
62+
# Build arc paths
63+
n_points = 50
64+
theta = np.linspace(0, np.pi, n_points)
65+
arc_rows = []
6466

65-
# Arc center and radius
67+
for arc_id, (start, end, weight) in enumerate(edges):
68+
x_start, x_end = x_positions[start], x_positions[end]
6669
x_center = (x_start + x_end) / 2
6770
arc_radius = abs(x_end - x_start) / 2
71+
height = 0.08 * abs(end - start)
6872

69-
# Arc height proportional to distance between nodes
70-
distance = abs(end - start)
71-
height = 0.08 * distance
72-
73-
# Generate arc points (semi-circle above baseline)
74-
n_points = 50
75-
theta = np.linspace(0, np.pi, n_points)
7673
x_arc = x_center - arc_radius * np.cos(theta)
7774
y_arc = y_baseline + height * np.sin(theta)
7875

79-
# Add points to dataframe with arc identifier
80-
for i in range(n_points):
81-
arc_data.append(
76+
arc_rows.append(
77+
pd.DataFrame(
8278
{
83-
"x": x_arc[i],
84-
"y": y_arc[i],
79+
"x": x_arc,
80+
"y": y_arc,
8581
"arc_id": arc_id,
86-
"weight": weight,
87-
"size": 1.0 + weight * 0.8, # Line thickness based on weight
82+
"weight": float(weight),
83+
"size": 1.2 + weight * 0.7,
84+
"alpha": 0.50 + weight * 0.15,
8885
}
8986
)
90-
arc_id += 1
91-
92-
arc_df = pd.DataFrame(arc_data)
87+
)
9388

94-
# Create nodes dataframe
95-
node_df = pd.DataFrame({"x": x_positions, "y": [y_baseline] * n_nodes, "name": nodes})
89+
arc_df = pd.concat(arc_rows, ignore_index=True)
9690

97-
# Create label dataframe (below nodes)
98-
label_df = pd.DataFrame({"x": x_positions, "y": [y_baseline - 0.05] * n_nodes, "name": nodes})
91+
# Baseline, node, and label dataframes
92+
baseline_df = pd.DataFrame({"x": [x_positions[0]], "xend": [x_positions[-1]], "y": [y_baseline], "yend": [y_baseline]})
93+
node_df = pd.DataFrame({"x": x_positions, "y": [y_baseline] * n_nodes})
94+
label_df = pd.DataFrame({"x": x_positions, "y": [y_baseline - 0.035] * n_nodes, "name": nodes})
9995

100-
# Create the plot
96+
# Plot with grammar of graphics layering and guide customization
10197
plot = (
10298
ggplot()
103-
# Draw arcs
104-
+ geom_path(arc_df, aes(x="x", y="y", group="arc_id", size="size"), color="#306998", alpha=0.6)
99+
+ geom_segment(
100+
baseline_df, aes(x="x", y="y", xend="xend", yend="yend"), color="#C0C8D0", size=0.8, linetype="solid"
101+
)
102+
+ geom_path(arc_df, aes(x="x", y="y", group="arc_id", color="weight", size="size", alpha="alpha"))
103+
+ scale_color_gradient(
104+
low="#A8C4D8",
105+
high="#1A3A5C",
106+
name="Interaction\nStrength",
107+
breaks=[1, 2, 3],
108+
labels=["Weak", "Medium", "Strong"],
109+
guide=guide_colorbar(direction="vertical"),
110+
)
105111
+ scale_size_identity()
106-
# Draw nodes
107-
+ geom_point(node_df, aes(x="x", y="y"), color="#FFD43B", size=10, stroke=1.5, fill="#FFD43B")
108-
# Add node labels
109-
+ geom_text(label_df, aes(x="x", y="y", label="name"), size=11, color="#306998", fontweight="bold", va="top")
110-
+ labs(title="Character Interactions · arc-basic · plotnine · pyplots.ai")
112+
+ scale_alpha_identity()
113+
+ geom_point(node_df, aes(x="x", y="y"), color="#1A3A5C", size=11, stroke=1.8, fill="white")
114+
+ geom_text(label_df, aes(x="x", y="y", label="name"), size=16, color="#1A3A5C", fontweight="bold", va="top")
115+
+ annotate(
116+
"text",
117+
x=0.5,
118+
y=0.76,
119+
label="Stronger connections shown with darker, thicker arcs",
120+
size=16,
121+
color="#666666",
122+
ha="center",
123+
fontstyle="italic",
124+
)
125+
+ coord_cartesian(xlim=(-0.06, 1.06), ylim=(-0.10, 0.82))
126+
+ labs(
127+
title="Character Interactions \u00b7 arc-basic \u00b7 plotnine \u00b7 pyplots.ai",
128+
subtitle="Narrative connections in Chapter 1 \u2014 arc thickness and color encode interaction strength",
129+
)
130+
+ theme_void()
111131
+ theme(
112132
figure_size=(16, 9),
113-
plot_title=element_text(size=24, ha="center"),
114-
axis_title=element_blank(),
115-
axis_text=element_blank(),
116-
axis_ticks=element_blank(),
117-
panel_grid=element_blank(),
118-
panel_background=element_blank(),
119-
plot_background=element_blank(),
120-
legend_position="none",
133+
plot_title=element_text(size=24, ha="center", weight="bold", color="#1A3A5C"),
134+
plot_subtitle=element_text(size=16, ha="center", color="#555555"),
135+
plot_margin=0.02,
136+
plot_background=element_rect(fill="white", color="white"),
137+
legend_position="right",
138+
legend_title=element_text(size=14, weight="bold", color="#1A3A5C"),
139+
legend_text=element_text(size=12, color="#444444"),
140+
legend_key_height=40,
141+
legend_key_width=12,
121142
)
122143
)
123144

124-
# Save the plot
145+
# Save
125146
plot.save("plot.png", dpi=300, verbose=False)

0 commit comments

Comments
 (0)