Skip to content

Commit 97d0c25

Browse files
feat(bokeh): implement bifurcation-basic (#5112)
## Implementation: `bifurcation-basic` - bokeh Implements the **bokeh** version of `bifurcation-basic`. **File:** `plots/bifurcation-basic/implementations/bokeh.py` **Parent Issue:** #4415 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/23361206273)* --------- 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 60b6cf6 commit 97d0c25

2 files changed

Lines changed: 371 additions & 0 deletions

File tree

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
""" pyplots.ai
2+
bifurcation-basic: Bifurcation Diagram for Dynamical Systems
3+
Library: bokeh 3.9.0 | Python 3.14.3
4+
Quality: 87/100 | Created: 2026-03-20
5+
"""
6+
7+
import numpy as np
8+
from bokeh.io import export_png, save
9+
from bokeh.models import ColumnDataSource, HoverTool, Label, Range1d, Span
10+
from bokeh.plotting import figure
11+
from bokeh.resources import Resources
12+
13+
14+
# Data - Logistic map: x(n+1) = r * x(n) * (1 - x(n))
15+
r_min, r_max = 2.5, 4.0
16+
n_r = 3000
17+
n_transient = 300
18+
n_keep = 150
19+
20+
r_values = np.linspace(r_min, r_max, n_r)
21+
all_r = np.repeat(r_values, n_keep)
22+
all_x = np.empty_like(all_r)
23+
24+
idx = 0
25+
for r in r_values:
26+
x = 0.5
27+
for _ in range(n_transient):
28+
x = r * x * (1.0 - x)
29+
for _ in range(n_keep):
30+
x = r * x * (1.0 - x)
31+
all_x[idx] = x
32+
idx += 1
33+
34+
# Regime-based coloring for visual storytelling
35+
colors = np.empty(len(all_r), dtype="U7")
36+
alphas = np.empty(len(all_r))
37+
38+
for i in range(len(all_r)):
39+
r = all_r[i]
40+
if r < 3.0:
41+
colors[i] = "#306998" # Python blue - stable
42+
alphas[i] = 0.35
43+
elif r < 3.449:
44+
colors[i] = "#4A90D9" # Lighter blue - periodic
45+
alphas[i] = 0.25
46+
elif r < 3.5699:
47+
colors[i] = "#8B5CF6" # Purple - higher period
48+
alphas[i] = 0.20
49+
else:
50+
colors[i] = "#E74C3C" # Red-orange - chaotic
51+
alphas[i] = 0.15
52+
53+
source = ColumnDataSource(data={"r": all_r, "x": all_x, "color": colors, "alpha": alphas})
54+
55+
# Plot
56+
p = figure(
57+
width=4800,
58+
height=2700,
59+
title="bifurcation-basic · bokeh · pyplots.ai",
60+
x_axis_label="Growth Rate (r)",
61+
y_axis_label="Steady-State Population (x)",
62+
x_range=Range1d(r_min - 0.02, r_max + 0.02),
63+
y_range=Range1d(-0.05, 1.05),
64+
tools="pan,wheel_zoom,box_zoom,reset,save",
65+
active_scroll="wheel_zoom",
66+
)
67+
68+
scatter = p.scatter(x="r", y="x", source=source, size=1.5, color="color", alpha="alpha", line_color=None)
69+
70+
# HoverTool - Bokeh-distinctive interactive feature
71+
hover = HoverTool(
72+
renderers=[scatter], tooltips=[("r", "@r{0.000}"), ("x", "@x{0.0000}")], point_policy="snap_to_data", mode="mouse"
73+
)
74+
p.add_tools(hover)
75+
76+
# Vertical spans at key bifurcation points for visual storytelling
77+
bif_spans = [(3.0, "Period-2"), (3.449, "Period-4"), (3.5699, "Chaos onset")]
78+
for r_bif, _ in bif_spans:
79+
span = Span(
80+
location=r_bif, dimension="height", line_color="#AA3939", line_width=2, line_alpha=0.25, line_dash="dashed"
81+
)
82+
p.add_layout(span)
83+
84+
# Key bifurcation point annotations - spread apart for readability
85+
annotations = [
86+
(3.0, 0.68, "r ≈ 3.0\nPeriod-2"),
87+
(3.449, 0.92, "r ≈ 3.449\nPeriod-4"),
88+
(3.5699, 0.05, "r ≈ 3.57\nOnset of chaos"),
89+
]
90+
91+
for r_bif, y_pos, label_text in annotations:
92+
label = Label(
93+
x=r_bif,
94+
y=y_pos,
95+
text=label_text,
96+
text_font_size="36pt",
97+
text_font_style="bold",
98+
text_color="#AA3939",
99+
text_alpha=0.85,
100+
text_align="center",
101+
x_offset=5,
102+
)
103+
p.add_layout(label)
104+
105+
# Style - typography and colors
106+
p.title.text_font_size = "72pt"
107+
p.title.text_color = "#2B2B2B"
108+
p.title.text_font = "Helvetica"
109+
110+
p.xaxis.axis_label_text_font_size = "48pt"
111+
p.yaxis.axis_label_text_font_size = "48pt"
112+
p.xaxis.axis_label_text_font = "Helvetica"
113+
p.yaxis.axis_label_text_font = "Helvetica"
114+
p.xaxis.major_label_text_font_size = "36pt"
115+
p.yaxis.major_label_text_font_size = "36pt"
116+
p.xaxis.axis_label_text_color = "#3A3A3A"
117+
p.yaxis.axis_label_text_color = "#3A3A3A"
118+
p.xaxis.major_label_text_color = "#555555"
119+
p.yaxis.major_label_text_color = "#555555"
120+
121+
p.xaxis.axis_line_color = None
122+
p.yaxis.axis_line_color = None
123+
p.xaxis.major_tick_line_color = None
124+
p.yaxis.major_tick_line_color = None
125+
p.xaxis.minor_tick_line_color = None
126+
p.yaxis.minor_tick_line_color = None
127+
128+
p.grid.grid_line_alpha = 0.12
129+
p.grid.grid_line_width = 2
130+
p.grid.grid_line_color = "#999999"
131+
132+
p.background_fill_color = "#FAFAFA"
133+
p.border_fill_color = "white"
134+
p.outline_line_color = None
135+
136+
p.xaxis.ticker.desired_num_ticks = 12
137+
p.yaxis.ticker.desired_num_ticks = 8
138+
139+
# Save
140+
export_png(p, filename="plot.png")
141+
save(p, filename="plot.html", resources=Resources(mode="cdn"), title="Bifurcation Diagram")
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
library: bokeh
2+
specification_id: bifurcation-basic
3+
created: '2026-03-20T20:28:57Z'
4+
updated: '2026-03-20T20:56:02Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 23361206273
7+
issue: 4415
8+
python_version: 3.14.3
9+
library_version: 3.9.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/bokeh/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/bokeh/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/bifurcation-basic/bokeh/plot.html
13+
quality_score: 87
14+
review:
15+
strengths:
16+
- Perfect spec compliance with all required features (bifurcation points labeled,
17+
transients discarded, correct parameter range)
18+
- Regime-based color encoding (blue to purple to red) effectively tells the chaos
19+
story
20+
- Clean visual refinement with removed axis lines, subtle grid, and Helvetica typography
21+
- Dual output (PNG + interactive HTML) leverages Bokeh strengths
22+
- Fully deterministic computation with appropriate resolution (3000 r-values x 150
23+
states)
24+
weaknesses:
25+
- Chaotic region (red, alpha=0.15) has low contrast against light background
26+
- Onset of chaos annotation placed at y=0.05 feels visually disconnected from the
27+
chaotic structure
28+
- Element-by-element color/alpha loop could be vectorized for cleaner code
29+
image_description: The plot displays a classic logistic map bifurcation diagram
30+
with the title "bifurcation-basic · bokeh · pyplots.ai". The x-axis shows "Growth
31+
Rate (r)" from 2.5 to 4.0, and the y-axis shows "Steady-State Population (x)"
32+
from 0 to 1. From r=2.5 to ~3.0, a single dark blue stable fixed point line curves
33+
downward slightly then rises. At r≈3.0 the line splits into two branches (period-2,
34+
labeled in red). The branches continue in lighter blue, splitting again at r≈3.449
35+
(period-4, labeled in red at top). Beyond r≈3.57 (labeled "Onset of chaos" at
36+
bottom), the diagram explodes into the characteristic chaotic fractal structure
37+
rendered in faint red/pink points. Dashed red vertical lines mark each bifurcation
38+
point. The background is light gray (#FAFAFA) with subtle grid lines. Typography
39+
uses Helvetica with axis lines and ticks removed for a clean look. The regime-based
40+
color transition from blue (stable) to purple (higher period) to red (chaotic)
41+
provides effective visual storytelling.
42+
criteria_checklist:
43+
visual_quality:
44+
score: 27
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: 72pt title, 48pt axis labels, 36pt
53+
tick labels, 36pt annotations'
54+
- id: VQ-02
55+
name: No Overlap
56+
score: 6
57+
max: 6
58+
passed: true
59+
comment: Annotations well-spaced at different y-positions, no text collisions
60+
- id: VQ-03
61+
name: Element Visibility
62+
score: 5
63+
max: 6
64+
passed: true
65+
comment: Point size 1.5 appropriate for 450K points; chaotic region alpha=0.15
66+
slightly faint
67+
- id: VQ-04
68+
name: Color Accessibility
69+
score: 3
70+
max: 4
71+
passed: false
72+
comment: Blue-purple-red avoids red-green issue but light red alpha=0.15 has
73+
low contrast on light background
74+
- id: VQ-05
75+
name: Layout & Canvas
76+
score: 3
77+
max: 4
78+
passed: false
79+
comment: Good proportions; data points at far right edge slightly compressed
80+
- id: VQ-06
81+
name: Axis Labels & Title
82+
score: 2
83+
max: 2
84+
passed: true
85+
comment: 'Descriptive labels with parameter notation: Growth Rate (r), Steady-State
86+
Population (x)'
87+
design_excellence:
88+
score: 14
89+
max: 20
90+
items:
91+
- id: DE-01
92+
name: Aesthetic Sophistication
93+
score: 6
94+
max: 8
95+
passed: true
96+
comment: Regime-based color palette, Helvetica typography, removed axis/tick
97+
lines, custom background
98+
- id: DE-02
99+
name: Visual Refinement
100+
score: 4
101+
max: 6
102+
passed: false
103+
comment: Axis lines removed, subtle grid alpha=0.12, clean background; grid
104+
could be more subtle
105+
- id: DE-03
106+
name: Data Storytelling
107+
score: 4
108+
max: 6
109+
passed: false
110+
comment: Regime coloring creates visual hierarchy; Onset of chaos annotation
111+
at y=0.05 feels disconnected
112+
spec_compliance:
113+
score: 15
114+
max: 15
115+
items:
116+
- id: SC-01
117+
name: Plot Type
118+
score: 5
119+
max: 5
120+
passed: true
121+
comment: Correct bifurcation diagram showing logistic map behavior
122+
- id: SC-02
123+
name: Required Features
124+
score: 4
125+
max: 4
126+
passed: true
127+
comment: 'All spec features present: small points, low alpha, cascade, labels,
128+
transients discarded'
129+
- id: SC-03
130+
name: Data Mapping
131+
score: 3
132+
max: 3
133+
passed: true
134+
comment: X=parameter r, Y=steady-state x, correct ranges
135+
- id: SC-04
136+
name: Title & Legend
137+
score: 3
138+
max: 3
139+
passed: true
140+
comment: Title follows exact format, no legend needed for this plot type
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-2, period-4, chaos, and periodicity
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 with proper scientific terminology
158+
- id: DQ-03
159+
name: Appropriate Scale
160+
score: 4
161+
max: 4
162+
passed: true
163+
comment: r in [2.5, 4.0] and x in [0, 1] are mathematically correct ranges
164+
code_quality:
165+
score: 9
166+
max: 10
167+
items:
168+
- id: CQ-01
169+
name: KISS Structure
170+
score: 3
171+
max: 3
172+
passed: true
173+
comment: 'Linear flow: imports, data generation, plot, styling, save'
174+
- id: CQ-02
175+
name: Reproducibility
176+
score: 2
177+
max: 2
178+
passed: true
179+
comment: 'Fully deterministic: logistic map with fixed x0=0.5'
180+
- id: CQ-03
181+
name: Clean Imports
182+
score: 2
183+
max: 2
184+
passed: true
185+
comment: All imports used
186+
- id: CQ-04
187+
name: Code Elegance
188+
score: 1
189+
max: 2
190+
passed: false
191+
comment: Per-element color/alpha loop could be vectorized with np.select
192+
- id: CQ-05
193+
name: Output & API
194+
score: 1
195+
max: 1
196+
passed: true
197+
comment: Saves as plot.png via export_png, current API
198+
library_mastery:
199+
score: 7
200+
max: 10
201+
items:
202+
- id: LM-01
203+
name: Idiomatic Usage
204+
score: 4
205+
max: 5
206+
passed: true
207+
comment: Proper ColumnDataSource, figure API, Label/Span models; could use
208+
Bokeh transforms
209+
- id: LM-02
210+
name: Distinctive Features
211+
score: 3
212+
max: 5
213+
passed: false
214+
comment: HoverTool, HTML export with CDN, Span, active_scroll; hover only
215+
visible in HTML
216+
verdict: REJECTED
217+
impl_tags:
218+
dependencies: []
219+
techniques:
220+
- annotations
221+
- hover-tooltips
222+
- html-export
223+
patterns:
224+
- data-generation
225+
- iteration-over-groups
226+
- columndatasource
227+
dataprep: []
228+
styling:
229+
- alpha-blending
230+
- grid-styling

0 commit comments

Comments
 (0)