Skip to content

Commit 3f6cdd5

Browse files
feat(matplotlib): implement bifurcation-basic (#5111)
## Implementation: `bifurcation-basic` - matplotlib Implements the **matplotlib** version of `bifurcation-basic`. **File:** `plots/bifurcation-basic/implementations/matplotlib.py` **Parent Issue:** #4415 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/23361206203)* --------- 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 920564c commit 3f6cdd5

2 files changed

Lines changed: 345 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
""" pyplots.ai
2+
bifurcation-basic: Bifurcation Diagram for Dynamical Systems
3+
Library: matplotlib 3.10.8 | Python 3.14.3
4+
Quality: 94/100 | Created: 2026-03-20
5+
"""
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
from matplotlib.colors import PowerNorm
10+
11+
12+
# Data
13+
r_min, r_max = 2.5, 4.0
14+
num_r = 2000
15+
transient = 200
16+
iterations = 100
17+
18+
r_values = np.linspace(r_min, r_max, num_r)
19+
r_plot = np.empty(num_r * iterations)
20+
x_plot = np.empty(num_r * iterations)
21+
22+
for i, r in enumerate(r_values):
23+
x = 0.5
24+
for _ in range(transient):
25+
x = r * x * (1 - x)
26+
for j in range(iterations):
27+
x = r * x * (1 - x)
28+
r_plot[i * iterations + j] = r
29+
x_plot[i * iterations + j] = x
30+
31+
# Create 2D histogram for density-based rendering of the chaotic region
32+
# This reveals structure (periodic windows, attractor density) far better than scatter
33+
r_bins = 800
34+
x_bins = 600
35+
hist, r_edges, x_edges = np.histogram2d(r_plot, x_plot, bins=[r_bins, x_bins], range=[[r_min, r_max], [0, 1]])
36+
37+
# Plot
38+
fig, ax = plt.subplots(figsize=(16, 9))
39+
40+
# Subtle regime background shading
41+
ax.axvspan(r_min, 3.0, color="#E8F4FD", alpha=0.3, zorder=0)
42+
ax.axvspan(3.0, 3.57, color="#F0EBF8", alpha=0.3, zorder=0)
43+
ax.axvspan(3.57, r_max, color="#FDE8E8", alpha=0.2, zorder=0)
44+
45+
# Density heatmap with PowerNorm to reveal structure across the full range
46+
# cividis is perceptually uniform and colorblind-safe
47+
ax.pcolormesh(
48+
r_edges,
49+
x_edges,
50+
hist.T,
51+
cmap="cividis",
52+
norm=PowerNorm(gamma=0.35, vmin=0, vmax=hist.max()),
53+
rasterized=True,
54+
zorder=1,
55+
)
56+
57+
# Regime labels at bottom with semi-transparent background for readability
58+
label_bbox = {"boxstyle": "round,pad=0.3", "facecolor": "white", "edgecolor": "none", "alpha": 0.7}
59+
for rx, label in [(2.75, "Stable"), (3.28, "Periodic"), (3.78, "Chaotic")]:
60+
ax.text(
61+
rx,
62+
0.04,
63+
label,
64+
transform=ax.get_xaxis_transform(),
65+
fontsize=14,
66+
color="#666666",
67+
ha="center",
68+
va="bottom",
69+
fontstyle="italic",
70+
bbox=label_bbox,
71+
zorder=3,
72+
)
73+
74+
# Annotations for key bifurcation points — well spaced
75+
bifurcation_points = [(3.0, "Period-2", -14, 0.97), (3.449, "Period-4", -60, 0.97), (3.544, "Period-8", -60, 0.87)]
76+
for r_bif, label, x_offset, y_frac in bifurcation_points:
77+
ax.axvline(r_bif, color="#CCCCCC", linewidth=0.8, linestyle="--", alpha=0.6, zorder=2)
78+
ha = "right" if x_offset < 0 else "left"
79+
ann_bbox = {"boxstyle": "round,pad=0.3", "facecolor": "white", "edgecolor": "none", "alpha": 0.8}
80+
ax.annotate(
81+
f"{label} r ≈ {r_bif}",
82+
xy=(r_bif, y_frac),
83+
xycoords=("data", "axes fraction"),
84+
xytext=(x_offset, 0),
85+
textcoords="offset points",
86+
fontsize=14,
87+
color="#444444",
88+
ha=ha,
89+
va="top",
90+
bbox=ann_bbox,
91+
zorder=4,
92+
)
93+
94+
# Onset of chaos annotation
95+
ax.annotate(
96+
"Onset of chaos\nr ≈ 3.57",
97+
xy=(3.57, 0.75),
98+
xytext=(3.75, 0.93),
99+
fontsize=14,
100+
color="#444444",
101+
ha="center",
102+
bbox={"boxstyle": "round,pad=0.3", "facecolor": "white", "edgecolor": "none", "alpha": 0.8},
103+
arrowprops={"arrowstyle": "->", "color": "#666666", "connectionstyle": "arc3,rad=-0.2"},
104+
zorder=4,
105+
)
106+
107+
# Style
108+
ax.set_xlabel("Growth Rate (r)", fontsize=20)
109+
ax.set_ylabel("Steady-State Population (x)", fontsize=20)
110+
ax.set_title("bifurcation-basic · matplotlib · pyplots.ai", fontsize=24, fontweight="medium")
111+
ax.tick_params(axis="both", labelsize=16)
112+
ax.set_xlim(r_min, r_max)
113+
ax.set_ylim(0, 1)
114+
ax.spines["top"].set_visible(False)
115+
ax.spines["right"].set_visible(False)
116+
117+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
library: matplotlib
2+
specification_id: bifurcation-basic
3+
created: '2026-03-20T20:28:45Z'
4+
updated: '2026-03-20T21:08:54Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 23361206203
7+
issue: 4415
8+
python_version: 3.14.3
9+
library_version: 3.10.8
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/matplotlib/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/matplotlib/plot_thumb.png
12+
preview_html: null
13+
quality_score: 94
14+
review:
15+
strengths:
16+
- Density heatmap approach (histogram2d + pcolormesh + PowerNorm) is far superior
17+
to scatter for revealing bifurcation structure including periodic windows within
18+
chaos
19+
- Excellent data storytelling with regime labels, bifurcation annotations, and Onset
20+
of chaos arrow creating a clear narrative
21+
- Cohesive design with cividis colormap, consistent annotation styling, and subtle
22+
regime background shading
23+
- All spec requirements fully satisfied with appropriate parameter choices
24+
- Clean, deterministic, well-structured code
25+
weaknesses:
26+
- Regime background shading (axvspan) is largely invisible in the periodic and chaotic
27+
regions because the heatmap covers it
28+
image_description: 'The plot displays a bifurcation diagram of the logistic map
29+
using a density-based heatmap (pcolormesh) with the cividis colormap on a dark
30+
blue background. The x-axis shows "Growth Rate (r)" ranging from 2.5 to 4.0, and
31+
the y-axis shows "Steady-State Population (x)" from 0 to 1.0. The title reads
32+
"bifurcation-basic · matplotlib · pyplots.ai" in large text at the top. The stable
33+
fixed-point branch appears as a bright yellowish line from r=2.5 to r=3.0, then
34+
period-doubling cascades are clearly visible as the branches split. Three regime
35+
background shadings are subtly applied (light blue for stable, light purple for
36+
periodic, light red for chaotic). Dashed vertical lines mark key bifurcation points
37+
with annotations: "Period-2 r ≈ 3.0", "Period-4 r ≈ 3.449", "Period-8 r ≈ 3.544",
38+
and "Onset of chaos r ≈ 3.57" (with an arrow). Regime labels ("Stable", "Periodic",
39+
"Chaotic") appear at the bottom in italic with white rounded boxes. Top and right
40+
spines are removed. The chaotic region shows rich density structure including
41+
periodic windows.'
42+
criteria_checklist:
43+
visual_quality:
44+
score: 30
45+
max: 30
46+
items:
47+
- id: VQ-01
48+
name: Text Legibility
49+
score: 8
50+
max: 8
51+
passed: true
52+
comment: 'All font sizes explicitly set: title 24pt, labels 20pt, ticks 16pt,
53+
annotations 14pt'
54+
- id: VQ-02
55+
name: No Overlap
56+
score: 6
57+
max: 6
58+
passed: true
59+
comment: All annotations well-spaced, no text collisions
60+
- id: VQ-03
61+
name: Element Visibility
62+
score: 6
63+
max: 6
64+
passed: true
65+
comment: Density heatmap with PowerNorm reveals structure excellently across
66+
full range
67+
- id: VQ-04
68+
name: Color Accessibility
69+
score: 4
70+
max: 4
71+
passed: true
72+
comment: Cividis is perceptually uniform and colorblind-safe
73+
- id: VQ-05
74+
name: Layout & Canvas
75+
score: 4
76+
max: 4
77+
passed: true
78+
comment: 16:9 figsize with bbox_inches tight, balanced margins
79+
- id: VQ-06
80+
name: Axis Labels & Title
81+
score: 2
82+
max: 2
83+
passed: true
84+
comment: 'Descriptive labels with variable names: Growth Rate (r), Steady-State
85+
Population (x)'
86+
design_excellence:
87+
score: 16
88+
max: 20
89+
items:
90+
- id: DE-01
91+
name: Aesthetic Sophistication
92+
score: 6
93+
max: 8
94+
passed: true
95+
comment: Strong design with density heatmap, cividis colormap, regime shading,
96+
cohesive annotation styling
97+
- id: DE-02
98+
name: Visual Refinement
99+
score: 5
100+
max: 6
101+
passed: true
102+
comment: Spines removed, no grid, subtle dashed lines, consistent bbox styling.
103+
Regime shading partially hidden under heatmap
104+
- id: DE-03
105+
name: Data Storytelling
106+
score: 5
107+
max: 6
108+
passed: true
109+
comment: Clear narrative from stability to chaos with regime labels, bifurcation
110+
annotations, and onset-of-chaos arrow
111+
spec_compliance:
112+
score: 15
113+
max: 15
114+
items:
115+
- id: SC-01
116+
name: Plot Type
117+
score: 5
118+
max: 5
119+
passed: true
120+
comment: Correct bifurcation diagram using density heatmap
121+
- id: SC-02
122+
name: Required Features
123+
score: 4
124+
max: 4
125+
passed: true
126+
comment: 'All spec requirements met: logistic map, transient discard, labeled
127+
bifurcation points'
128+
- id: SC-03
129+
name: Data Mapping
130+
score: 3
131+
max: 3
132+
passed: true
133+
comment: X=parameter r, Y=state x, full range 2.5-4.0
134+
- id: SC-04
135+
name: Title & Legend
136+
score: 3
137+
max: 3
138+
passed: true
139+
comment: Correct title format, no legend needed for single-series density
140+
plot
141+
data_quality:
142+
score: 15
143+
max: 15
144+
items:
145+
- id: DQ-01
146+
name: Feature Coverage
147+
score: 6
148+
max: 6
149+
passed: true
150+
comment: Shows stable fixed point, period-doubling cascade, chaos, and periodic
151+
windows
152+
- id: DQ-02
153+
name: Realistic Context
154+
score: 5
155+
max: 5
156+
passed: true
157+
comment: Logistic map is the canonical example, real scientific context
158+
- id: DQ-03
159+
name: Appropriate Scale
160+
score: 4
161+
max: 4
162+
passed: true
163+
comment: 'Standard parameter ranges: r 2.5-4.0, x 0-1, 2000 r values, 200
164+
transient, 100 iterations'
165+
code_quality:
166+
score: 10
167+
max: 10
168+
items:
169+
- id: CQ-01
170+
name: KISS Structure
171+
score: 3
172+
max: 3
173+
passed: true
174+
comment: Clean linear structure with no functions or classes
175+
- id: CQ-02
176+
name: Reproducibility
177+
score: 2
178+
max: 2
179+
passed: true
180+
comment: 'Fully deterministic: logistic map from fixed x=0.5'
181+
- id: CQ-03
182+
name: Clean Imports
183+
score: 2
184+
max: 2
185+
passed: true
186+
comment: All three imports used
187+
- id: CQ-04
188+
name: Code Elegance
189+
score: 2
190+
max: 2
191+
passed: true
192+
comment: Elegant histogram2d approach for density, no fake UI
193+
- id: CQ-05
194+
name: Output & API
195+
score: 1
196+
max: 1
197+
passed: true
198+
comment: Saves as plot.png with dpi=300, current API
199+
library_mastery:
200+
score: 8
201+
max: 10
202+
items:
203+
- id: LM-01
204+
name: Idiomatic Usage
205+
score: 4
206+
max: 5
207+
passed: true
208+
comment: Consistent Axes methods, proper fig/ax pattern, object-oriented API
209+
- id: LM-02
210+
name: Distinctive Features
211+
score: 4
212+
max: 5
213+
passed: true
214+
comment: PowerNorm, pcolormesh, axvspan, annotate with mixed coordinate systems
215+
verdict: APPROVED
216+
impl_tags:
217+
dependencies: []
218+
techniques:
219+
- annotations
220+
- layer-composition
221+
patterns:
222+
- data-generation
223+
- matrix-construction
224+
dataprep:
225+
- binning
226+
styling:
227+
- custom-colormap
228+
- alpha-blending

0 commit comments

Comments
 (0)