Skip to content

Commit bf63401

Browse files
feat(matplotlib): implement line-reaction-coordinate (#5155)
## Implementation: `line-reaction-coordinate` - matplotlib Implements the **matplotlib** version of `line-reaction-coordinate`. **File:** `plots/line-reaction-coordinate/implementations/matplotlib.py` **Parent Issue:** #4409 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/23388404489)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent bc90856 commit bf63401

2 files changed

Lines changed: 339 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
""" pyplots.ai
2+
line-reaction-coordinate: Reaction Coordinate Energy Diagram
3+
Library: matplotlib 3.10.8 | Python 3.14.3
4+
Quality: 91/100 | Created: 2026-03-21
5+
"""
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
from matplotlib.patches import FancyArrowPatch
10+
11+
12+
# Data
13+
reactant_energy = 50.0
14+
transition_energy = 120.0
15+
product_energy = 20.0
16+
peak_pos = 0.45
17+
18+
reaction_coord = np.linspace(0, 1, 500)
19+
sigma = 0.13
20+
baseline = reactant_energy + (product_energy - reactant_energy) * (3 * reaction_coord**2 - 2 * reaction_coord**3)
21+
gaussian_bump = (transition_energy - (reactant_energy + product_energy) / 2) * np.exp(
22+
-((reaction_coord - peak_pos) ** 2) / (2 * sigma**2)
23+
)
24+
energy = baseline + gaussian_bump
25+
26+
peak_idx = np.argmax(energy)
27+
actual_peak = energy[peak_idx]
28+
peak_x = reaction_coord[peak_idx]
29+
30+
# Plot
31+
fig, ax = plt.subplots(figsize=(16, 9))
32+
33+
ax.plot(reaction_coord, energy, color="#306998", linewidth=3.5, zorder=3)
34+
35+
# Dashed reference lines at reactant and product energy levels
36+
ax.hlines(reactant_energy, -0.05, 0.20, colors="#999999", linestyles="--", linewidth=1.5, alpha=0.5)
37+
ax.hlines(reactant_energy, 0.82, 1.12, colors="#999999", linestyles="--", linewidth=1.5, alpha=0.5)
38+
ax.hlines(product_energy, 0.78, 1.12, colors="#999999", linestyles="--", linewidth=1.5, alpha=0.5)
39+
40+
# Transition state marker
41+
ax.scatter([peak_x], [actual_peak], s=140, color="#C84B31", zorder=4, edgecolors="white", linewidth=1.5)
42+
43+
# Labels
44+
ax.text(
45+
0.02, reactant_energy + 4, "Reactants\n(50 kJ/mol)", fontsize=16, fontweight="medium", color="#333333", va="bottom"
46+
)
47+
ax.text(0.78, product_energy - 4, "Products\n(20 kJ/mol)", fontsize=16, fontweight="medium", color="#333333", va="top")
48+
ax.text(
49+
peak_x,
50+
actual_peak + 5,
51+
"Transition State",
52+
fontsize=16,
53+
fontweight="medium",
54+
color="#C84B31",
55+
va="bottom",
56+
ha="center",
57+
)
58+
59+
# Activation energy arrow (Ea)
60+
ea_x = 0.14
61+
arrow_ea = FancyArrowPatch(
62+
(ea_x, reactant_energy),
63+
(ea_x, actual_peak),
64+
arrowstyle="<->",
65+
mutation_scale=18,
66+
linewidth=2,
67+
color="#E07A2F",
68+
zorder=5,
69+
)
70+
ax.add_patch(arrow_ea)
71+
ea_value = actual_peak - reactant_energy
72+
ax.text(
73+
ea_x + 0.03,
74+
(reactant_energy + actual_peak) / 2,
75+
f"$E_a$ = {ea_value:.0f} kJ/mol",
76+
fontsize=16,
77+
fontweight="bold",
78+
color="#E07A2F",
79+
ha="left",
80+
va="center",
81+
bbox={"boxstyle": "round,pad=0.3", "facecolor": "white", "edgecolor": "none", "alpha": 0.9},
82+
)
83+
84+
# Enthalpy change arrow (ΔH)
85+
dh_x = 1.05
86+
arrow_dh = FancyArrowPatch(
87+
(dh_x, reactant_energy),
88+
(dh_x, product_energy),
89+
arrowstyle="<->",
90+
mutation_scale=18,
91+
linewidth=2,
92+
color="#2D8659",
93+
zorder=5,
94+
)
95+
ax.add_patch(arrow_dh)
96+
dh_value = product_energy - reactant_energy
97+
ax.text(
98+
dh_x + 0.02,
99+
(reactant_energy + product_energy) / 2,
100+
f"$\\Delta H$ = {dh_value:.0f} kJ/mol",
101+
fontsize=16,
102+
fontweight="bold",
103+
color="#2D8659",
104+
ha="left",
105+
va="center",
106+
bbox={"boxstyle": "round,pad=0.3", "facecolor": "white", "edgecolor": "none", "alpha": 0.9},
107+
)
108+
109+
# Style
110+
ax.set_xlabel("Reaction Coordinate", fontsize=20)
111+
ax.set_ylabel("Potential Energy (kJ/mol)", fontsize=20)
112+
ax.set_title("line-reaction-coordinate · matplotlib · pyplots.ai", fontsize=24, fontweight="medium")
113+
ax.tick_params(axis="both", labelsize=16)
114+
ax.set_xlim(-0.05, 1.22)
115+
ax.set_ylim(0, actual_peak + 25)
116+
ax.spines["top"].set_visible(False)
117+
ax.spines["right"].set_visible(False)
118+
ax.yaxis.grid(True, alpha=0.2, linewidth=0.8)
119+
ax.set_xticks([])
120+
121+
plt.tight_layout()
122+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
library: matplotlib
2+
specification_id: line-reaction-coordinate
3+
created: '2026-03-21T20:47:52Z'
4+
updated: '2026-03-21T20:51:34Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 23388404489
7+
issue: 4409
8+
python_version: 3.14.3
9+
library_version: 3.10.8
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/line-reaction-coordinate/matplotlib/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/line-reaction-coordinate/matplotlib/plot_thumb.png
12+
preview_html: null
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent spec compliance — all required features (Ea arrow, ΔH arrow, labeled
17+
species, dashed reference lines) implemented precisely
18+
- Strong color-coded visual storytelling with intentional color assignments for
19+
each element
20+
- Clean scientific diagram aesthetic with appropriate spine removal and subtle grid
21+
- Deterministic, well-structured code with no unnecessary complexity
22+
weaknesses:
23+
- 'DQ-01: Only shows single-step reaction; could demonstrate richer feature coverage'
24+
- 'DE-01: Could push further toward publication quality with more refined typography
25+
or shading under the curve'
26+
image_description: The plot displays a reaction coordinate energy diagram with a
27+
smooth blue curve (#306998) tracing from reactants at 50 kJ/mol through a transition
28+
state peak at ~122 kJ/mol down to products at 20 kJ/mol. The title reads "line-reaction-coordinate
29+
· matplotlib · pyplots.ai" in medium-weight font. The y-axis is labeled "Potential
30+
Energy (kJ/mol)" and the x-axis "Reaction Coordinate" (with no tick marks, appropriate
31+
for arbitrary units). An orange double-headed arrow on the left shows Ea = 72
32+
kJ/mol between reactant level and peak, with a white-background label. A green
33+
double-headed arrow on the right shows ΔH = -30 kJ/mol between reactant and product
34+
levels. A red dot marks the transition state with a label above. Dashed gray reference
35+
lines extend at reactant (50) and product (20) energy levels. Top and right spines
36+
are removed, subtle y-axis grid at alpha=0.2. Clean, professional scientific diagram.
37+
criteria_checklist:
38+
visual_quality:
39+
score: 30
40+
max: 30
41+
items:
42+
- id: VQ-01
43+
name: Text Legibility
44+
score: 8
45+
max: 8
46+
passed: true
47+
comment: 'All font sizes explicitly set: title 24pt, axis labels 20pt, tick
48+
labels 16pt, annotations 16pt'
49+
- id: VQ-02
50+
name: No Overlap
51+
score: 6
52+
max: 6
53+
passed: true
54+
comment: All text labels well-positioned with no collisions
55+
- id: VQ-03
56+
name: Element Visibility
57+
score: 6
58+
max: 6
59+
passed: true
60+
comment: Line thickness 3.5, marker s=140, arrows linewidth=2 — all clearly
61+
visible
62+
- id: VQ-04
63+
name: Color Accessibility
64+
score: 4
65+
max: 4
66+
passed: true
67+
comment: Blue, orange, green, red — four distinct hues, colorblind-safe
68+
- id: VQ-05
69+
name: Layout & Canvas
70+
score: 4
71+
max: 4
72+
passed: true
73+
comment: Good canvas utilization, balanced margins
74+
- id: VQ-06
75+
name: Axis Labels & Title
76+
score: 2
77+
max: 2
78+
passed: true
79+
comment: Y-axis with units, x-axis appropriate for arbitrary reaction progress
80+
design_excellence:
81+
score: 15
82+
max: 20
83+
items:
84+
- id: DE-01
85+
name: Aesthetic Sophistication
86+
score: 5
87+
max: 8
88+
passed: true
89+
comment: Custom color palette with intentional color coding, white bbox backgrounds,
90+
good typography hierarchy
91+
- id: DE-02
92+
name: Visual Refinement
93+
score: 5
94+
max: 6
95+
passed: true
96+
comment: Spines removed, subtle grid, hidden x-ticks, clean whitespace
97+
- id: DE-03
98+
name: Data Storytelling
99+
score: 5
100+
max: 6
101+
passed: true
102+
comment: Color-coded arrows communicate Ea and ΔH as key insights, transition
103+
state highlighted
104+
spec_compliance:
105+
score: 15
106+
max: 15
107+
items:
108+
- id: SC-01
109+
name: Plot Type
110+
score: 5
111+
max: 5
112+
passed: true
113+
comment: 'Correct: smooth line plot for reaction coordinate energy diagram'
114+
- id: SC-02
115+
name: Required Features
116+
score: 4
117+
max: 4
118+
passed: true
119+
comment: 'All spec requirements met: labels, arrows, dashed lines, smooth
120+
curve'
121+
- id: SC-03
122+
name: Data Mapping
123+
score: 3
124+
max: 3
125+
passed: true
126+
comment: X=reaction coordinate, Y=potential energy, all data visible
127+
- id: SC-04
128+
name: Title & Legend
129+
score: 3
130+
max: 3
131+
passed: true
132+
comment: Correct title format, no legend needed for annotated single-series
133+
data_quality:
134+
score: 14
135+
max: 15
136+
items:
137+
- id: DQ-01
138+
name: Feature Coverage
139+
score: 5
140+
max: 6
141+
passed: true
142+
comment: Shows single-step exothermic reaction with all key features
143+
- id: DQ-02
144+
name: Realistic Context
145+
score: 5
146+
max: 5
147+
passed: true
148+
comment: Chemistry domain, values from spec example, neutral educational context
149+
- id: DQ-03
150+
name: Appropriate Scale
151+
score: 4
152+
max: 4
153+
passed: true
154+
comment: Realistic energy values for a chemical reaction
155+
code_quality:
156+
score: 10
157+
max: 10
158+
items:
159+
- id: CQ-01
160+
name: KISS Structure
161+
score: 3
162+
max: 3
163+
passed: true
164+
comment: 'Linear flow: imports → data → plot → annotations → styling → save'
165+
- id: CQ-02
166+
name: Reproducibility
167+
score: 2
168+
max: 2
169+
passed: true
170+
comment: Fully deterministic data, no randomness
171+
- id: CQ-03
172+
name: Clean Imports
173+
score: 2
174+
max: 2
175+
passed: true
176+
comment: All three imports used
177+
- id: CQ-04
178+
name: Code Elegance
179+
score: 2
180+
max: 2
181+
passed: true
182+
comment: Clean, well-organized, appropriate complexity
183+
- id: CQ-05
184+
name: Output & API
185+
score: 1
186+
max: 1
187+
passed: true
188+
comment: Saves as plot.png with dpi=300, bbox_inches=tight
189+
library_mastery:
190+
score: 7
191+
max: 10
192+
items:
193+
- id: LM-01
194+
name: Idiomatic Usage
195+
score: 4
196+
max: 5
197+
passed: true
198+
comment: Good use of ax methods, FancyArrowPatch, proper hlines
199+
- id: LM-02
200+
name: Distinctive Features
201+
score: 3
202+
max: 5
203+
passed: true
204+
comment: FancyArrowPatch with arrowstyle is distinctively matplotlib, bbox
205+
dict styling on text
206+
verdict: APPROVED
207+
impl_tags:
208+
dependencies: []
209+
techniques:
210+
- annotations
211+
- patches
212+
patterns:
213+
- data-generation
214+
dataprep: []
215+
styling:
216+
- grid-styling
217+
- edge-highlighting

0 commit comments

Comments
 (0)