Skip to content

Commit ff4ee36

Browse files
feat(plotly): implement bifurcation-basic (#5110)
## Implementation: `bifurcation-basic` - plotly Implements the **plotly** version of `bifurcation-basic`. **File:** `plots/bifurcation-basic/implementations/plotly.py` **Parent Issue:** #4415 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/23361206064)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 1dddd26 commit ff4ee36

2 files changed

Lines changed: 342 additions & 0 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
""" pyplots.ai
2+
bifurcation-basic: Bifurcation Diagram for Dynamical Systems
3+
Library: plotly 6.6.0 | Python 3.14.3
4+
Quality: 90/100 | Created: 2026-03-20
5+
"""
6+
7+
import numpy as np
8+
import plotly.graph_objects as go
9+
10+
11+
# Data: Logistic map x(n+1) = r * x(n) * (1 - x(n))
12+
r_values = np.linspace(2.5, 4.0, 2000)
13+
transient = 200
14+
iterations = 100
15+
16+
r_all = []
17+
x_all = []
18+
19+
for r in r_values:
20+
x = 0.5
21+
for _ in range(transient):
22+
x = r * x * (1.0 - x)
23+
for _ in range(iterations):
24+
x = r * x * (1.0 - x)
25+
r_all.append(r)
26+
x_all.append(x)
27+
28+
r_all = np.array(r_all)
29+
x_all = np.array(x_all)
30+
31+
# Plot
32+
python_blue = "#306998"
33+
34+
fig = go.Figure()
35+
36+
fig.add_trace(
37+
go.Scattergl(
38+
x=r_all,
39+
y=x_all,
40+
mode="markers",
41+
marker={"size": 1, "color": python_blue, "opacity": 0.15},
42+
showlegend=False,
43+
hovertemplate="r = %{x:.4f}<br>x = %{y:.4f}<extra></extra>",
44+
)
45+
)
46+
47+
# Key bifurcation points
48+
bifurcation_points = [(3.0, "Period-2"), (3.449, "Period-4"), (3.544, "Period-8"), (3.5699, "Chaos onset")]
49+
50+
annotations = []
51+
offsets = {"Period-2": "center", "Period-4": "right", "Period-8": "right", "Chaos onset": "left"}
52+
for r_bif, label in bifurcation_points:
53+
fig.add_vline(x=r_bif, line={"color": "rgba(200, 80, 80, 0.35)", "width": 1.5, "dash": "dot"})
54+
annotations.append(
55+
{
56+
"x": r_bif,
57+
"y": 1.03,
58+
"yref": "paper",
59+
"text": f"<b>{label}</b><br>r ≈ {r_bif}",
60+
"showarrow": False,
61+
"font": {"size": 13, "color": "#8B3A3A", "family": "Arial, sans-serif"},
62+
"bgcolor": "rgba(255,255,255,0.9)",
63+
"borderpad": 4,
64+
"xanchor": offsets[label],
65+
}
66+
)
67+
68+
# Style
69+
fig.update_layout(
70+
title={
71+
"text": "Logistic Map · bifurcation-basic · plotly · pyplots.ai",
72+
"font": {"size": 28, "color": "#2C3E50", "family": "Arial Black, Arial, sans-serif"},
73+
"x": 0.5,
74+
"xanchor": "center",
75+
"y": 0.95,
76+
},
77+
xaxis={
78+
"title": {"text": "Growth Rate (r)", "font": {"size": 22, "family": "Arial, sans-serif"}, "standoff": 12},
79+
"tickfont": {"size": 18},
80+
"showgrid": False,
81+
"range": [2.45, 4.05],
82+
"zeroline": False,
83+
"dtick": 0.25,
84+
},
85+
yaxis={
86+
"title": {
87+
"text": "Steady-State Population (x)",
88+
"font": {"size": 22, "family": "Arial, sans-serif"},
89+
"standoff": 12,
90+
},
91+
"tickfont": {"size": 18},
92+
"showgrid": True,
93+
"gridwidth": 1,
94+
"gridcolor": "rgba(0,0,0,0.06)",
95+
"range": [-0.05, 1.05],
96+
"zeroline": False,
97+
},
98+
template="plotly_white",
99+
showlegend=False,
100+
margin={"l": 80, "r": 40, "t": 130, "b": 70},
101+
annotations=annotations,
102+
plot_bgcolor="white",
103+
paper_bgcolor="#FAFBFC",
104+
hoverlabel={"bgcolor": "white", "font_size": 14, "font_color": python_blue},
105+
)
106+
107+
# Save
108+
fig.write_image("plot.png", width=1600, height=900, scale=3)
109+
fig.write_html("plot.html")
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
library: plotly
2+
specification_id: bifurcation-basic
3+
created: '2026-03-20T20:28:31Z'
4+
updated: '2026-03-20T20:33:16Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 23361206064
7+
issue: 4415
8+
python_version: 3.14.3
9+
library_version: 6.6.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/plotly/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/plotly/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/plotly/plot.html
13+
quality_score: 90
14+
review:
15+
strengths:
16+
- Excellent use of Scattergl for performant rendering of ~200K data points — expert
17+
Plotly choice
18+
- Density-based visualization with tiny markers and low alpha perfectly reveals
19+
the bifurcation structure
20+
- Annotated bifurcation points with vertical reference lines create a clear narrative
21+
- Fully deterministic data generation with well-chosen parameters (2000 r-values,
22+
200 transient, 100 recorded)
23+
- Dual output (PNG + HTML) leverages Plotly interactive capabilities
24+
weaknesses:
25+
- Annotation font size (13) is slightly small relative to other text elements
26+
- Title prepends extra text before the standard format
27+
- Design could be elevated with stronger visual emphasis on the chaos transition
28+
region
29+
image_description: 'The plot displays a bifurcation diagram of the logistic map
30+
with growth rate (r) on the x-axis ranging from 2.5 to 4.0 and steady-state population
31+
(x) on the y-axis ranging from 0 to 1. Data points are rendered in a steel blue
32+
color (#306998) with very low opacity, creating a density-based visualization.
33+
The diagram clearly shows: a single stable fixed point from r=2.5 to r≈3.0, a
34+
period-2 bifurcation at r≈3.0, period-4 at r≈3.449, period-8 at r≈3.544, and the
35+
onset of chaos at r≈3.5699. Four vertical dotted red lines mark these key bifurcation
36+
points, with brownish-red labels at the top of the plot identifying each transition.
37+
The chaotic regime from r≈3.57 to r=4.0 is richly detailed, with visible windows
38+
of periodicity. The title reads "Logistic Map · bifurcation-basic · plotly · pyplots.ai"
39+
in dark blue bold font. The background is white with a very light gray paper background
40+
(#FAFBFC). The y-axis has a subtle grid; the x-axis has no grid. Overall layout
41+
is clean and well-proportioned.'
42+
criteria_checklist:
43+
visual_quality:
44+
score: 29
45+
max: 30
46+
items:
47+
- id: VQ-01
48+
name: Text Legibility
49+
score: 7
50+
max: 8
51+
passed: true
52+
comment: All font sizes explicitly set (title 28, labels 22, ticks 18). Annotation
53+
font at 13 is readable but slightly small.
54+
- id: VQ-02
55+
name: No Overlap
56+
score: 6
57+
max: 6
58+
passed: true
59+
comment: No overlapping elements. Annotations use different xanchor offsets
60+
for closely-spaced bifurcation points.
61+
- id: VQ-03
62+
name: Element Visibility
63+
score: 6
64+
max: 6
65+
passed: true
66+
comment: Marker size 1 with opacity 0.15 perfectly adapted to ~200K point
67+
density. Bifurcation structure is crystal clear.
68+
- id: VQ-04
69+
name: Color Accessibility
70+
score: 4
71+
max: 4
72+
passed: true
73+
comment: Single color (Python Blue) against white background. No colorblind
74+
concerns.
75+
- id: VQ-05
76+
name: Layout & Canvas
77+
score: 4
78+
max: 4
79+
passed: true
80+
comment: Good canvas utilization with appropriate margins.
81+
- id: VQ-06
82+
name: Axis Labels & Title
83+
score: 2
84+
max: 2
85+
passed: true
86+
comment: 'Descriptive labels with parameter notation: Growth Rate (r), Steady-State
87+
Population (x).'
88+
design_excellence:
89+
score: 13
90+
max: 20
91+
items:
92+
- id: DE-01
93+
name: Aesthetic Sophistication
94+
score: 5
95+
max: 8
96+
passed: true
97+
comment: 'Above defaults: custom Python Blue, plotly_white template, subtle
98+
paper background, cohesive annotation palette.'
99+
- id: DE-02
100+
name: Visual Refinement
101+
score: 4
102+
max: 6
103+
passed: true
104+
comment: X-axis grid removed, y-axis grid at very low opacity, zeroline off,
105+
generous margins.
106+
- id: DE-03
107+
name: Data Storytelling
108+
score: 4
109+
max: 6
110+
passed: true
111+
comment: Vertical reference lines with labels guide the viewer through the
112+
period-doubling cascade to chaos.
113+
spec_compliance:
114+
score: 14
115+
max: 15
116+
items:
117+
- id: SC-01
118+
name: Plot Type
119+
score: 5
120+
max: 5
121+
passed: true
122+
comment: Correct scatter/point bifurcation diagram.
123+
- id: SC-02
124+
name: Required Features
125+
score: 4
126+
max: 4
127+
passed: true
128+
comment: 'All spec requirements met: small points, low alpha, full cascade,
129+
labeled bifurcation points, transient discarded.'
130+
- id: SC-03
131+
name: Data Mapping
132+
score: 3
133+
max: 3
134+
passed: true
135+
comment: X=parameter (r), Y=state (x), both axes show full range.
136+
- id: SC-04
137+
name: Title & Legend
138+
score: 2
139+
max: 3
140+
passed: true
141+
comment: Title prepends 'Logistic Map' before the required format. No legend
142+
needed for single-series.
143+
data_quality:
144+
score: 15
145+
max: 15
146+
items:
147+
- id: DQ-01
148+
name: Feature Coverage
149+
score: 6
150+
max: 6
151+
passed: true
152+
comment: 'Shows all aspects: stable fixed point, period-2/4/8 doubling, chaotic
153+
regime, windows of periodicity.'
154+
- id: DQ-02
155+
name: Realistic Context
156+
score: 5
157+
max: 5
158+
passed: true
159+
comment: Logistic map is the canonical example for bifurcation diagrams in
160+
nonlinear dynamics.
161+
- id: DQ-03
162+
name: Appropriate Scale
163+
score: 4
164+
max: 4
165+
passed: true
166+
comment: 'Standard ranges: r in [2.5, 4.0], x in [0, 1]. Well-calibrated iteration
167+
parameters.'
168+
code_quality:
169+
score: 10
170+
max: 10
171+
items:
172+
- id: CQ-01
173+
name: KISS Structure
174+
score: 3
175+
max: 3
176+
passed: true
177+
comment: 'Clean linear flow: imports, data generation, plot, style, save.'
178+
- id: CQ-02
179+
name: Reproducibility
180+
score: 2
181+
max: 2
182+
passed: true
183+
comment: 'Fully deterministic: logistic map with fixed initial condition x=0.5.'
184+
- id: CQ-03
185+
name: Clean Imports
186+
score: 2
187+
max: 2
188+
passed: true
189+
comment: Only numpy and plotly.graph_objects, both used.
190+
- id: CQ-04
191+
name: Code Elegance
192+
score: 2
193+
max: 2
194+
passed: true
195+
comment: Clean, straightforward implementation with appropriate complexity.
196+
- id: CQ-05
197+
name: Output & API
198+
score: 1
199+
max: 1
200+
passed: true
201+
comment: Saves as plot.png (4800x2700) and plot.html. Uses current API.
202+
library_mastery:
203+
score: 9
204+
max: 10
205+
items:
206+
- id: LM-01
207+
name: Idiomatic Usage
208+
score: 5
209+
max: 5
210+
passed: true
211+
comment: Expert use of go.Scattergl for WebGL rendering of ~200K points. Proper
212+
graph_objects API.
213+
- id: LM-02
214+
name: Distinctive Features
215+
score: 4
216+
max: 5
217+
passed: true
218+
comment: Scattergl (WebGL), custom hovertemplate, HTML export. Could leverage
219+
more Plotly-specific features.
220+
verdict: APPROVED
221+
impl_tags:
222+
dependencies: []
223+
techniques:
224+
- annotations
225+
- hover-tooltips
226+
- html-export
227+
patterns:
228+
- data-generation
229+
- iteration-over-groups
230+
dataprep: []
231+
styling:
232+
- alpha-blending
233+
- grid-styling

0 commit comments

Comments
 (0)