从一个视频中重建 Veritasium 的情节
Reconstruct Veritasium's plots from one the videos
灵感来自 Veritasium Youtube 视频之一,他在其中解释了混沌分叉图(逻辑图)。数学方程很简单:X[i+1]=R*X[i](1-X[i])
他绘制的第一张图:这个X[i]
值(y轴值,在0到1的范围内)与迭代时间i
(x轴值,计算次数)具有特定的 R 值(例如,R_init=2,我想在我的代码中加入一个滑块来更改 R 的值)
他绘制的第二张图(分叉图):值 R(x 轴值)与 X[i] 的平衡总体,即:它在 (根据 R 值,在 certain/many 次迭代 i 之后,X[i] 可以在有限数和无限数之间振荡——混沌!)
最终,在代码中,我想要两个并排的子图,左边一个是“第一张图”,带有用于这两个变量的滑块,右边是“第二张图”。
下面我粘贴了我的入门代码,我只尝试用 R 的滑块和 X[0] 的初始值来绘制“第一张图”(但是,当然,到目前为止它没有显示任何东西..)
如果有人能帮我完成这个项目,或者给我一些有问题的代码的建议,我将不胜感激。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
R = 1.5
x = np.linspace(0, 100, 1)
k_init = 0.4 # initial y value
fig = plt.figure(figsize=(8, 8))
ax = plt.axes([0.125, 0.15, 0.775, 0.80])
myplot, = plt.plot(0, 0, c="royalblue") # not really ploting anything first
plt.xlim(0, 100)
plt.ylim(0, 1)
# create slider panel & values sets
slider_r = plt.axes([0.125, 0.03, 0.775, 0.03])
slider_k = plt.axes([0.125, 0.07, 0.775, 0.03])
r_slider = Slider(slider_r, "R", 1, 20, valinit=R, valstep=0.1)
k_slider = Slider(slider_k, "k_init", 0, 1, valinit=k_init, valstep=0.05)
k = [] # y-values starts with List items
def update(*args):
k.append(k_init)
for i in np.arange(1,100,1):
k_new = R*(k[i-1])*(1-(k[i-1]))
k.append(k_new)
y = np.array(k)
myplot.set_xdata(x)
myplot.set_ydata(y)
r_slider.on_changed(update)
k_slider.on_changed(update)
update()
plt.show()
简答
- 将
x = np.linspace(0, 100, 1)
替换为x = np.arange(100)
- 移除
k = []
- 在
update
函数的开头添加k0, R = k_slider.val, r_slider.val
- 将
k.append(k_init)
替换为k = [k0]
长答案
1。获取运行的模拟(无动画)
首先,让我们尝试获得一个没有滑块的工作图。以下是一些提示和一些需要解决的问题:
x = np.linspace(0, 100, 1)
只包含一个元素,而y
将包含100个值!
- 由于
y
的最终大小已知,因此将其初始化为空数组,而不是将项目添加到列表 k
。这将使代码更具可读性和更快。
- 使用变量来存储常量值,例如轮数。
- 在问题的描述中,您使用变量
x
,而在实现中它是 y
ans k
:定义有意义的符号,并坚持使用它们。
- 定义像
r_slider
和 slider_r
这样相似的名称是相当混乱的,特别是因为这两个变量存储完全不同的对象。
## define constants
R = 2.6
X0 = 0.5 # initial value
N = 75 # number of epochs
## logistic map iterates
def get_logistic_map(x0, R, N):
x = np.empty(N)
x[0] = x0
for i in range(1, N):
x[i] = R * x[i-1] * (1 - x[i-1])
return x
x = get_logistic_map(X0, R, N)
## plot
plt.figure(figsize=(7, 4))
plt.plot(x, 'o-', c="royalblue", ms=2)
plt.ylim(0, 1)
plt.margins(x=.01)
plt.grid(c="lightgray")
plt.xlabel(r"$n$")
plt.ylabel(r"$x_n$")
plt.show()
2。让我们引入与滑块的交互
函数中update
:
- 您应该使用滑块的新值更新显示的数据。通常当更新滑块时,它会将其新值作为参数提供给回调函数(此处为
update
函数)。由于此处两个滑块链接到同一个更新函数,因此您不能使用此输入参数。但是,您可以使用每个滑块的属性 val
访问这些值。 (并且由于此类回调函数需要一个参数,因此您可以适当地使用 *args
;)。
- 我不确定这是否是有意的,但
k
是一个全局列表。所以每次 update
被调用 100 新的 值被添加。
## Prepare figure layout
fig = plt.figure(figsize=(7, 5))
ax = plt.axes([0.125, 0.15, 0.775, 0.80])
line, = plt.plot(range(N), np.zeros(N), 'o-', c="royalblue", ms=2)
# set the layout of the main axes before defining the axes of the sliders
plt.ylim(0, 1)
plt.xlim(0, N-1)
## Create sliders
ax_slider_x0 = plt.axes([0.125, 0.03, 0.775, 0.03])
ax_slider_r = plt.axes([0.125, 0.07, 0.775, 0.03])
slider_x0 = Slider(ax_slider_x0, r"$x_0$", 0, 1, valinit=X0)
slider_r = Slider(ax_slider_r, r"$R$", 0, 4, valinit=R)
# plt.sca(ax) # uncomment to set the main axes as the current one
def update(*args):
x0_val, r_val = slider_x0.val, slider_r.val
x = get_logistic_map(x0_val, r_val, N)
line.set_ydata(x)
# Set the title on the main axes (plt.title would have added a
# title on the current axes (by default the last one to be defined)
ax.set_title(rf"Logistic map with $R$={r_val:.3f} and $x_0={x0_val:.3f}$")
slider_x0.on_changed(update)
slider_r.on_changed(update)
update() # initialize the plot
plt.show()
A personal tip – To debug a callback function with sliders, it is tempting to scatter some print
. But as this turns out to be fruitless, you can instead display the debugging text inside the title of the plot!
3。接下来是什么?
现在第一个情节是互动的。对于分叉图,我没有看到可以添加的交互性。
灵感来自 Veritasium Youtube 视频之一,他在其中解释了混沌分叉图(逻辑图)。数学方程很简单:X[i+1]=R*X[i](1-X[i])
他绘制的第一张图:这个X[i]
值(y轴值,在0到1的范围内)与迭代时间i
(x轴值,计算次数)具有特定的 R 值(例如,R_init=2,我想在我的代码中加入一个滑块来更改 R 的值)
他绘制的第二张图(分叉图):值 R(x 轴值)与 X[i] 的平衡总体,即:它在 (根据 R 值,在 certain/many 次迭代 i 之后,X[i] 可以在有限数和无限数之间振荡——混沌!)
最终,在代码中,我想要两个并排的子图,左边一个是“第一张图”,带有用于这两个变量的滑块,右边是“第二张图”。 下面我粘贴了我的入门代码,我只尝试用 R 的滑块和 X[0] 的初始值来绘制“第一张图”(但是,当然,到目前为止它没有显示任何东西..) 如果有人能帮我完成这个项目,或者给我一些有问题的代码的建议,我将不胜感激。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
R = 1.5
x = np.linspace(0, 100, 1)
k_init = 0.4 # initial y value
fig = plt.figure(figsize=(8, 8))
ax = plt.axes([0.125, 0.15, 0.775, 0.80])
myplot, = plt.plot(0, 0, c="royalblue") # not really ploting anything first
plt.xlim(0, 100)
plt.ylim(0, 1)
# create slider panel & values sets
slider_r = plt.axes([0.125, 0.03, 0.775, 0.03])
slider_k = plt.axes([0.125, 0.07, 0.775, 0.03])
r_slider = Slider(slider_r, "R", 1, 20, valinit=R, valstep=0.1)
k_slider = Slider(slider_k, "k_init", 0, 1, valinit=k_init, valstep=0.05)
k = [] # y-values starts with List items
def update(*args):
k.append(k_init)
for i in np.arange(1,100,1):
k_new = R*(k[i-1])*(1-(k[i-1]))
k.append(k_new)
y = np.array(k)
myplot.set_xdata(x)
myplot.set_ydata(y)
r_slider.on_changed(update)
k_slider.on_changed(update)
update()
plt.show()
简答
- 将
x = np.linspace(0, 100, 1)
替换为x = np.arange(100)
- 移除
k = []
- 在
update
函数的开头添加k0, R = k_slider.val, r_slider.val
- 将
k.append(k_init)
替换为k = [k0]
长答案
1。获取运行的模拟(无动画)
首先,让我们尝试获得一个没有滑块的工作图。以下是一些提示和一些需要解决的问题:
x = np.linspace(0, 100, 1)
只包含一个元素,而y
将包含100个值!- 由于
y
的最终大小已知,因此将其初始化为空数组,而不是将项目添加到列表k
。这将使代码更具可读性和更快。 - 使用变量来存储常量值,例如轮数。
- 在问题的描述中,您使用变量
x
,而在实现中它是y
ansk
:定义有意义的符号,并坚持使用它们。 - 定义像
r_slider
和slider_r
这样相似的名称是相当混乱的,特别是因为这两个变量存储完全不同的对象。
## define constants
R = 2.6
X0 = 0.5 # initial value
N = 75 # number of epochs
## logistic map iterates
def get_logistic_map(x0, R, N):
x = np.empty(N)
x[0] = x0
for i in range(1, N):
x[i] = R * x[i-1] * (1 - x[i-1])
return x
x = get_logistic_map(X0, R, N)
## plot
plt.figure(figsize=(7, 4))
plt.plot(x, 'o-', c="royalblue", ms=2)
plt.ylim(0, 1)
plt.margins(x=.01)
plt.grid(c="lightgray")
plt.xlabel(r"$n$")
plt.ylabel(r"$x_n$")
plt.show()
2。让我们引入与滑块的交互
函数中update
:
- 您应该使用滑块的新值更新显示的数据。通常当更新滑块时,它会将其新值作为参数提供给回调函数(此处为
update
函数)。由于此处两个滑块链接到同一个更新函数,因此您不能使用此输入参数。但是,您可以使用每个滑块的属性val
访问这些值。 (并且由于此类回调函数需要一个参数,因此您可以适当地使用*args
;)。 - 我不确定这是否是有意的,但
k
是一个全局列表。所以每次update
被调用 100 新的 值被添加。
## Prepare figure layout
fig = plt.figure(figsize=(7, 5))
ax = plt.axes([0.125, 0.15, 0.775, 0.80])
line, = plt.plot(range(N), np.zeros(N), 'o-', c="royalblue", ms=2)
# set the layout of the main axes before defining the axes of the sliders
plt.ylim(0, 1)
plt.xlim(0, N-1)
## Create sliders
ax_slider_x0 = plt.axes([0.125, 0.03, 0.775, 0.03])
ax_slider_r = plt.axes([0.125, 0.07, 0.775, 0.03])
slider_x0 = Slider(ax_slider_x0, r"$x_0$", 0, 1, valinit=X0)
slider_r = Slider(ax_slider_r, r"$R$", 0, 4, valinit=R)
# plt.sca(ax) # uncomment to set the main axes as the current one
def update(*args):
x0_val, r_val = slider_x0.val, slider_r.val
x = get_logistic_map(x0_val, r_val, N)
line.set_ydata(x)
# Set the title on the main axes (plt.title would have added a
# title on the current axes (by default the last one to be defined)
ax.set_title(rf"Logistic map with $R$={r_val:.3f} and $x_0={x0_val:.3f}$")
slider_x0.on_changed(update)
slider_r.on_changed(update)
update() # initialize the plot
plt.show()
A personal tip – To debug a callback function with sliders, it is tempting to scatter some
3。接下来是什么?
现在第一个情节是互动的。对于分叉图,我没有看到可以添加的交互性。