我正在创建一个交互式绘图,它将跟踪等式的零点并调整滑块。我遇到了更新零源数据的问题。
1)如何更新/重新计算零?
2)这样做有效吗?
#@title Interactive Phase Plane Plot
output_notebook()
mu = 0
x = np.linspace(-2*np.pi, 2*np.pi, 2000)
y = mu*np.sin(x)-np.sin(2*x)
滑块操作前的原始功能。下一节粗略估计零。
def init_fp(x):
fp_x = []
fp_y = []
i = 0
while i < len(x):
if np.abs(y[i]) > 0.005:
pass
else:
fp_x.append(x[i])
fp_y.append(0)
i += 1
return fp_x, fp_y
此部分在Bokeh图中为回溯操作创建数据源。
source = ColumnDataSource(data={
'x' : x,
'y' : y
})
fpx, fpy = init_fp(x)
source1 = ColumnDataSource(data={
'fpx' : fpx,
'fpy' : fpy
})
这定义了回调操作,内部是我用新的func更新绘图并重新计算零的地方。
callback_single = CustomJS(args=dict(source=source, source1=source1), code="""
var data = source.data;
var mu = cb_obj.value
var x = data['x']
var y = data['y']
var x1 = data['xfp']
var y1 = data['yfp']
for (var i = 0; i < x.length; i++) {
y[i] = mu*Math.sin(x[i])-Math.sin(2*x[i]);
}
source.change.emit();
for (var i=0; i < x.length; i++){
if (Math.fps(y[i]) < 0.05){
x1[i] = x[i];
y1[i] = 0;
}
}
source1.change.emit();
""")
这里是滑块的定义和绘图,以及绘图的各种美学。
mu = Slider(start=-5, end=5, value=0, step=0.01, title="mu", callback=callback_single)
p = figure(plot_width=1000, plot_height=500)
p.line('x', 'y', source=source)
p.circle('fpx', 'fpy', source=source1)
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.8
p.xaxis.axis_label = 'Theta'
p.yaxis.axis_label = 'd Theta/dt'
t = Title()
t.text = 'Interactive Phase Plane Plot'
layout = column(p, widgetbox(mu))
p.title = t
show(layout)
您的示例中可以更改一些内容:
fpx
,fpy
属性属于source1
,而不属于source
。Math.fps
应该是Math.abs
。x1
和y1
时,字段名称中有拼写错误。CustomJS
回调中的第二个循环将无法正常工作。重写回调的一种方法如下:
callback_single = CustomJS(args=dict(source=source, source1=source1), code="""
const mu = cb_obj.value
const { x } = source.data;
const y = x.map( val => mu * Math.sin(val) - Math.sin(2*val));
source.data = { x, y };
const fpx = x.filter((val, ind) => Math.abs(y[ind]) < 0.05);
const fpy = fpx.map(() => 0);
source1.data = { fpx, fpy };
""")
此外,还有一种方法可以在init_fp
中使用更多惯用的numpy:
def init_fp(x, y):
fp_x = x[np.abs(y) < 0.05]
fp_y = np.zeros_like(fp_x)
return fp_x, fp_y
这是完整的代码,我按原样保留零的数学,并且从output_notebook
更改为output_file
:
from bokeh.io import show, output_file
from bokeh.layouts import column, widgetbox
from bokeh.models import ColumnDataSource, CustomJS, Slider, Title
from bokeh.plotting import figure
import numpy as np
output_file('zeros.html')
mu = 0
x = np.linspace(-2*np.pi, 2*np.pi, 2000)
y = mu*np.sin(x)-np.sin(2*x)
def init_fp(x, y):
fp_x = x[np.abs(y) < 0.05]
fp_y = np.zeros_like(fp_x)
return fp_x, fp_y
source = ColumnDataSource(data={
'x' : x,
'y' : y
})
fpx, fpy = init_fp(x, y)
source1 = ColumnDataSource(data={
'fpx' : fpx,
'fpy' : fpy
})
callback_single = CustomJS(args=dict(source=source, source1=source1), code="""
const mu = cb_obj.value;
const { x } = source.data;
const y = x.map( val => mu * Math.sin(val) - Math.sin(2*val));
source.data = { x, y };
const fpx = x.filter((val, ind) => Math.abs(y[ind]) < 0.05);
const fpy = fpx.map(() => 0);
source1.data = { fpx, fpy };
""")
mu = Slider(start=-5, end=5, value=0, step=0.01, title="mu", callback=callback_single)
p = figure(plot_width=1000, plot_height=500)
p.line('x', 'y', source=source)
p.circle('fpx', 'fpy', source=source1)
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.8
p.xaxis.axis_label = 'Theta'
p.yaxis.axis_label = 'd Theta/dt'
t = Title()
t.text = 'Interactive Phase Plane Plot'
layout = column(p, widgetbox(mu))
p.title = t
show(layout)