def logistic_bifurcation_diagram():
t_range = srange(1000)
discard = 875
show = 150
t_axis_range = (0, 50)
r_values = [round(r, 2) for r in srange(2.5, 3.41, 0.1) + srange(3.43, 4.001, 0.01)]
r_finished = set()
initial_state = 0.42
fig = plotly.subplots.make_subplots(rows=int(1), cols=int(2),
subplot_titles=("Time series", "Bifurcation diagram"))
fig = plotly.graph_objects.FigureWidget(fig)
fig.layout.showlegend = False
fig.layout.margin.update(t=50, r=0)
fig.layout.xaxis.title.text = "t"
fig.layout.yaxis.title.text = "X"
fig.layout.xaxis2.title.text = "r"
fig.layout.yaxis2.title.text = "X"
fig.layout.xaxis.range = t_axis_range
fig.layout.yaxis.range = (0, 1.02)
fig.layout.xaxis2.range = (r_values[0] - 0.03, r_values[-1] + 0.03)
fig.layout.yaxis2.range = (0, 1.02)
fig.add_scatter(row=int(1), col=int(1), x=t_range, mode="markers+lines",
marker_color="blue", line_color="gray")
timeseries = fig.data[-1]
fig.add_scatter(row=int(1), col=int(2), x=[], y=[], mode="markers",
marker_color="blue", marker_symbol="square", marker_size=2)
bifurcation_diagram = fig.data[-1]
fig.add_scatter(row=int(1), col=int(2), x=[], y=[], mode="markers",
marker_color="red", marker_size=4)
bifurcation_new = fig.data[-1]
def update_r(change=None):
X_next = fast_float(r.value*x*(1 - x), x)
X = initial_state
solution = np.zeros([len(t_range)], dtype=float)
for t in t_range:
solution[t] = X
X = X_next(X)
with fig.batch_update():
timeseries.y = solution
if len(bifurcation_new.x) and bifurcation_new.x[0] not in r_finished:
bifurcation_diagram.x = np.append(bifurcation_diagram.x, bifurcation_new.x)
bifurcation_diagram.y = np.append(bifurcation_diagram.y, bifurcation_new.y)
r_finished.add(bifurcation_new.x[0])
if auto_checkbox.value:
add_to_diagram(solution)
else:
bifurcation_new.x = []
bifurcation_new.y = []
def add_to_diagram(values):
X_values = set(values[discard:].round(3))
bifurcation_new.x = [r.value] * len(X_values)
bifurcation_new.y = list(X_values)
def show_lines(change):
with fig.batch_update():
timeseries.mode = "markers+lines" if connect_checkbox.value else "markers"
timeseries.marker.size = 6 if connect_checkbox.value else 3
def button_clicked(button):
with fig.batch_update():
add_to_diagram(timeseries.y)
r = SelectionSlider(options=r_values, value=r_values[0], description="r", continuous_update=False)
r.observe(update_r, "value")
connect_checkbox = checkbox(True, label="Connect the dots")
connect_checkbox.observe(show_lines, "value")
add_button = Button(description="Add to diagram")
add_button.on_click(button_clicked)
auto_checkbox = checkbox(False, label="Auto mode")
update_r()
display(HBox((r, connect_checkbox, add_button, auto_checkbox)), fig)
return fig