Skip to content

Commit 889ad94

Browse files
feat(matplotlib): implement network-directed (#2893)
## Implementation: `network-directed` - matplotlib Implements the **matplotlib** version of `network-directed`. **File:** `plots/network-directed/implementations/matplotlib.py` **Parent Issue:** #2858 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608483162)* --------- 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 42f410c commit 889ad94

2 files changed

Lines changed: 154 additions & 0 deletions

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
""" pyplots.ai
2+
network-directed: Directed Network Graph
3+
Library: matplotlib 3.10.8 | Python 3.13.11
4+
Quality: 92/100 | Created: 2025-12-30
5+
"""
6+
7+
import matplotlib.patches as mpatches
8+
import matplotlib.pyplot as plt
9+
import numpy as np
10+
from matplotlib.patches import Circle, FancyArrowPatch
11+
12+
13+
# Data: Software package dependencies (arrows show import direction)
14+
np.random.seed(42)
15+
16+
# Define modules with groups (core, utils, api, tests)
17+
# Positions optimized for 16:9 aspect ratio with better spread
18+
nodes = {
19+
"main": {"group": "core", "pos": (0.45, 0.88)},
20+
"config": {"group": "core", "pos": (0.18, 0.68)},
21+
"database": {"group": "core", "pos": (0.45, 0.55)},
22+
"auth": {"group": "api", "pos": (0.72, 0.73)},
23+
"routes": {"group": "api", "pos": (0.88, 0.52)},
24+
"handlers": {"group": "api", "pos": (0.68, 0.32)},
25+
"validators": {"group": "utils", "pos": (0.32, 0.38)},
26+
"helpers": {"group": "utils", "pos": (0.48, 0.15)},
27+
"logger": {"group": "utils", "pos": (0.12, 0.38)},
28+
"cache": {"group": "utils", "pos": (0.05, 0.58)},
29+
"test_auth": {"group": "tests", "pos": (0.92, 0.88)},
30+
"test_routes": {"group": "tests", "pos": (0.95, 0.32)},
31+
"test_db": {"group": "tests", "pos": (0.25, 0.12)},
32+
}
33+
34+
# Define dependencies (arrow from source to target means source imports target)
35+
edges = [
36+
("main", "config"),
37+
("main", "database"),
38+
("main", "routes"),
39+
("main", "logger"),
40+
("config", "validators"),
41+
("database", "logger"),
42+
("database", "config"),
43+
("auth", "database"),
44+
("auth", "validators"),
45+
("auth", "logger"),
46+
("routes", "auth"),
47+
("routes", "handlers"),
48+
("routes", "validators"),
49+
("handlers", "database"),
50+
("handlers", "helpers"),
51+
("handlers", "logger"),
52+
("validators", "helpers"),
53+
("cache", "logger"),
54+
("cache", "config"),
55+
("test_auth", "auth"),
56+
("test_routes", "routes"),
57+
("test_db", "database"),
58+
]
59+
60+
# Group colors (colorblind-safe palette)
61+
group_colors = {
62+
"core": "#306998", # Python Blue
63+
"api": "#FFD43B", # Python Yellow
64+
"utils": "#4DAF4A", # Green
65+
"tests": "#984EA3", # Purple
66+
}
67+
68+
# Create plot (16:9 for directed graph)
69+
fig, ax = plt.subplots(figsize=(16, 9))
70+
71+
# Node radius for arrow endpoint calculations
72+
node_radius = 0.055
73+
74+
# Draw edges with arrows
75+
for source, target in edges:
76+
pos1 = nodes[source]["pos"]
77+
pos2 = nodes[target]["pos"]
78+
79+
# Calculate edge start/end points outside node circles
80+
dx = pos2[0] - pos1[0]
81+
dy = pos2[1] - pos1[1]
82+
dist = np.sqrt(dx**2 + dy**2)
83+
dx_norm, dy_norm = dx / dist, dy / dist
84+
start = (pos1[0] + dx_norm * node_radius, pos1[1] + dy_norm * node_radius)
85+
end = (pos2[0] - dx_norm * node_radius * 1.6, pos2[1] - dy_norm * node_radius * 1.6)
86+
87+
# Create curved arrow
88+
arrow = FancyArrowPatch(
89+
start,
90+
end,
91+
arrowstyle="-|>",
92+
mutation_scale=25,
93+
color="#555555",
94+
linewidth=2.5,
95+
alpha=0.65,
96+
connectionstyle="arc3,rad=0.12",
97+
)
98+
ax.add_patch(arrow)
99+
100+
# Draw nodes
101+
for name, props in nodes.items():
102+
pos = props["pos"]
103+
color = group_colors[props["group"]]
104+
105+
# Draw node circle
106+
circle = Circle(pos, radius=node_radius, facecolor=color, edgecolor="#333333", linewidth=2.5, alpha=0.95, zorder=10)
107+
ax.add_patch(circle)
108+
109+
# Draw label
110+
ax.text(pos[0], pos[1], name, ha="center", va="center", fontsize=13, fontweight="bold", color="#222222", zorder=11)
111+
112+
# Create legend
113+
legend_handles = [
114+
mpatches.Patch(color=color, label=group.capitalize(), alpha=0.95) for group, color in group_colors.items()
115+
]
116+
ax.legend(
117+
handles=legend_handles, loc="upper left", fontsize=16, framealpha=0.95, title="Module Type", title_fontsize=18
118+
)
119+
120+
# Styling
121+
ax.set_title("network-directed · matplotlib · pyplots.ai", fontsize=24, fontweight="bold", pad=20)
122+
ax.set_xlim(-0.02, 1.02)
123+
ax.set_ylim(0.0, 1.0)
124+
ax.set_aspect("equal")
125+
ax.axis("off")
126+
127+
plt.tight_layout()
128+
plt.savefig("plot.png", dpi=300, bbox_inches="tight", facecolor="white")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library: matplotlib
2+
specification_id: network-directed
3+
created: '2025-12-30T23:57:08Z'
4+
updated: '2025-12-31T00:04:41Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608483162
7+
issue: 2858
8+
python_version: 3.13.11
9+
library_version: 3.10.8
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/network-directed/matplotlib/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/network-directed/matplotlib/plot_thumb.png
12+
preview_html: null
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent directed graph visualization with clear arrow directions showing import
17+
dependencies
18+
- Colorblind-safe palette with good distinction between Core (blue), Api (yellow),
19+
Utils (green), and Tests (purple) groups
20+
- Well-positioned nodes using manual layout that minimizes edge crossings
21+
- Curved arrows effectively handle overlapping paths and clearly show direction
22+
- Proper title format following spec-id · library · pyplots.ai convention
23+
- Clean KISS code structure with no functions or classes
24+
weaknesses:
25+
- Some node labels are slightly cramped within circles (e.g., validators, test_routes)
26+
- Node radius could be slightly larger to better accommodate longer labels

0 commit comments

Comments
 (0)