How to calcul tangente with Bokeh callback custom JS? - python-3.x

I have to make a graphic with a function, his derivative and the tangent.
I'm exercising on python with Bokeh library.
I've tried multiple different calcul to get the tangent. To change the variables,function but without any success.
import numpy as np
from bokeh.layouts import row, widgetbox
from bokeh.models import CustomJS, Slider
from bokeh.plotting import figure, output_file, show, ColumnDataSource
#First Curve
x = np.linspace(-10, 10)
a = -10
y = (x**3)-12*x
#fonction
def f(x):
return ((x**3)-12*x)
def fprime(x):
return ((3*x**2)-12)
yprime = fprime(x)
#prepare list of value for tan
ytan = []
yprimetan = []
tan = []
for a in range (-25,25):
y1 = f(a)
y2= fprime(a)
y3 = y1 * a + y2
ytan.append(y1)
yprimetan.append(y2)
tan.append(y3)
print('liste y ',ytan)
print('liste yprime ',yprimetan)
print('liste tan ',tan)
source = ColumnDataSource(data=dict(x=x,y=ytan))
plot = figure(y_range=(-50, 50), plot_width=800, plot_height=800)
plot.line('x','y', source=source, line_width=3,legend= 'Fonction', line_alpha=0.6)
callback = CustomJS(args=dict(source=source), code="""
var data = source.data;
var A = amp.value;
var B = offset.value;
var x = data['x']
var y = data['y']
for (var i = -10; i < x.length; i++) {
y[i] = B + A *((x[i]**3)-12*x[i]);
}
source.change.emit();
""")
amp_slider = Slider(start=-10, end=10, value=1, step=.1,
title="Amplitude", callback=callback)
callback.args["amp"] = amp_slider
offset_slider = Slider(start=-10, end=10, value=0, step=.1,
title="Offset", callback=callback)
callback.args["offset"] = offset_slider
#Second Curve dérivé
source2 = ColumnDataSource(data=dict(x=x, y=yprimetan))
plot.line('x', 'y', source=source2, line_width=3,legend= 'Dérivé', line_alpha=0.6,color='red')
#Third Curve Tan
source3 = ColumnDataSource(data=dict(x=x,tan=tan,yprime=yprimetan,y=tan))
plot.line('x','tan', source=source3,legend= 'Tangente', line_width=3, line_alpha=0.6,color='green')
callback = CustomJS(args=dict(source=source3), code="""
var data = source.data;
var Z = tangente.value;
var y = data['y']
var yprime = data['yprime']
var tan = data['tan']
var x = data['x']
for (var i = -10; i < x.length; i++) {
tan[i] = yprime[i] * (x[i]-Z) + y[i] ;
}
source.change.emit();
""")
#tan[i]= (3*(x[i]**2)-12) * (Z-x[i]) + ((x[i]**3)-12*x[i])
tan_slider = Slider(start=-10, end=10, value=1, step=.1,
title="Tangente", callback=callback)
callback.args["tangente"] = tan_slider
#Output
layout = row(
plot,
widgetbox(amp_slider, offset_slider,tan_slider),
)
output_file("slider.html", title="slider.py example")
show(layout)
I expect to have a tangent that i can move through the curve.
You can execute the code to see the graphic i have for the moment.

Related

Using colormap in cycle (python)

How to edit the for cycles under #ax5 and #ax6 to plot graphs in the same fashion? Now, the lower figure has no colour transit, as opposed to the upper one. The colour transit appears in the lower figure after increasing of dpi, however, some unwanted stuff also appears. Is there a scalling problem? Thank you
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
import math
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
# Function for plotting parallels to curves
def get_parallels(length=.1):
px, py = [], []
for idx in range(len(x)-1):
x0, y0, xa, ya = x[idx], y[idx], x[idx+1], y[idx+1]
dx, dy = xa-x0, ya-y0
norm = math.hypot(dx, dy) * 1/length
dx /= norm
dy /= norm
px.append(x0-dy)
py.append(y0+dx)
return px, py
def offset(x,y, o):
""" Offset coordinates given by array x,y by o """
X = np.c_[x,y].T
m = np.array([[0,-1],[1,0]])
R = np.zeros_like(X)
S = X[:,2:]-X[:,:-2]
R[:,1:-1] = np.dot(m, S)
R[:,0] = np.dot(m, X[:,1]-X[:,0])
R[:,-1] = np.dot(m, X[:,-1]-X[:,-2])
On = R/np.sqrt(R[0,:]**2+R[1,:]**2)*o
Out = On+X
return Out[0,:], Out[1,:]
dpi = 20
def offset_curve(ax, x,y, o):
""" Offset array x,y in data coordinates
by o in points """
trans = ax.transData.transform
inv = ax.transData.inverted().transform
X = np.c_[x,y]
Xt = trans(X)
xto, yto = offset(Xt[:,0],Xt[:,1],o*dpi/72. )
Xto = np.c_[xto, yto]
Xo = inv(Xto)
return Xo[:,0], Xo[:,1]
fig = plt.figure(constrained_layout=True)
gs = GridSpec(3, 6, figure=fig)
ax5 = fig.add_subplot(gs[1, 3:6])
ax6 = fig.add_subplot(gs[2, :3])
ax7 = fig.add_subplot(gs[2, 3:6])
cmap = plt.get_cmap('Greys_r')
# ax5
x = np.linspace(-1, 1, 100)
y = -x**2
ax5.set_ylim(-1.02, 0.3)
width_l = ax5.get_ylim()[1] - ax5.get_ylim()[0]
for t in np.linspace(0, 1, 40):
length = -0.1*width_l*t
ax5.plot(*get_parallels(length=length), color=cmap(t/2 + 0.25))
# ax6
x = np.linspace(-3, 3, 100)
y = -(1/4*x**4 - 1.6*x**2)
ax6.plot(x, y)
ax6.set_xlim(ax6.get_xlim()[0]-0.5, ax6.get_xlim()[1]+0.5)
ax6.scatter(1/2*(ax6.get_xlim()[0] + ax6.get_xlim()[1]), 1.2, marker = 'o', s=900, facecolors='none')
lines = []
width_l = ax6.get_ylim()[1] - ax6.get_ylim()[0]
for t in np.linspace(0, 1, 40):
l, = ax6.plot(x, y - t * 0.1 * width_l, color=cmap(t/2 + 0.25))
lines.append(l)
def plot_rainbow(event=None):
x0 = x
y0 = y
for i in range(len(lines)):
xx, yy = offset_curve(ax, x0, y0, -width_l)
lines[i].set_data(xx, yy)
lines[i].set_linewidth(1.1*width_l)
x0 = xx
y0 = yy
plot_rainbow()
fig.canvas.mpl_connect("resize_event", plot_rainbow)
fig.canvas.mpl_connect("button_release_event", plot_rainbow)
plt.savefig('fig.pdf')

How to plot the figure in the desired fashion?

How to edit this code to have the same width and colour map as in the following figure? The script is based on this question.
import numpy as np
import matplotlib.pyplot as plt
dpi = 100
def offset(x,y, o):
""" Offset coordinates given by array x,y by o """
X = np.c_[x,y].T
m = np.array([[0,-1],[1,0]])
R = np.zeros_like(X)
S = X[:,2:]-X[:,:-2]
R[:,1:-1] = np.dot(m, S)
R[:,0] = np.dot(m, X[:,1]-X[:,0])
R[:,-1] = np.dot(m, X[:,-1]-X[:,-2])
On = R/np.sqrt(R[0,:]**2+R[1,:]**2)*o
Out = On+X
return Out[0,:], Out[1,:]
def offset_curve(ax, x,y, o):
""" Offset array x,y in data coordinates
by o in points """
trans = ax.transData.transform
inv = ax.transData.inverted().transform
X = np.c_[x,y]
Xt = trans(X)
xto, yto = offset(Xt[:,0],Xt[:,1],o*dpi/72. )
Xto = np.c_[xto, yto]
Xo = inv(Xto)
return Xo[:,0], Xo[:,1]
x = np.linspace(-3, 3, 100)
y = -(1/4*x**4 - 1.6*x**2)
fig, ax=plt.subplots(figsize=(4,2.5), dpi=dpi)
cmap = plt.get_cmap('Greys_r')
lw = 2.
lines = []
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
for t in np.linspace(0, 1, 40):
l, = ax.plot(x, y - t * 0.1 * width_l, color=cmap(t/2 + 0.25))
lines.append(l)
def plot_rainbow(event=None):
# initialization of lists
xr, yr = 6*[None], 6*[None]
xr[0],yr[0] = offset_curve(ax, x,y, lw/2.)
xr[1],yr[1] = offset_curve(ax, x,y, -lw/2.)
xr[2],yr[2] = offset_curve(ax, xr[0],yr[0], lw)
xr[3],yr[3] = offset_curve(ax, xr[1],yr[1], -lw)
xr[4],yr[4] = offset_curve(ax, xr[2],yr[2], lw)
xr[5],yr[5] = offset_curve(ax, xr[3],yr[3], -lw)
for i in range(6):
lines[i].set_data(xr[i], yr[i])
plot_rainbow()
fig.canvas.mpl_connect("resize_event", plot_rainbow)
fig.canvas.mpl_connect("button_release_event", plot_rainbow)
plt.show()
The figure above was created by the following script:
import numpy as np
import matplotlib.pyplot as plt
import math
dpi = 100
# Function for plotting parallels to curves
def get_parallels(length=.1):
px, py = [], []
for idx in range(len(x)-1):
x0, y0, xa, ya = x[idx], y[idx], x[idx+1], y[idx+1]
dx, dy = xa-x0, ya-y0
norm = math.hypot(dx, dy) * 1/length
dx /= norm
dy /= norm
px.append(x0-dy)
py.append(y0+dx)
return px, py
fig, ax=plt.subplots(figsize=(4,2.5), dpi=dpi)
cmap = plt.get_cmap('Greys_r')
x = np.linspace(-1, 1, 100)
y = -x**2
ax.set_ylim(-1.02, 0.3)
ax.scatter(1/2*(ax.get_xlim()[0] + ax.get_xlim()[1]), 0.145, marker = 'o', s=900, facecolors='none')
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
for t in np.linspace(0, 1, 40):
length = -0.1*width_l*t
ax.plot(*get_parallels(length=length), color=cmap(t/2 + 0.25))
plt.tight_layout()
plt.show()
Several curves are plotted in camp and the length is set.
I would like to have the same "shadow" for the curve in the first scrip. How to do that, please?

Plotting solution 2nd ODE using Euler

I have used the Equation of Motion (Newtons Law) for a simple spring and mass scenario incorporating it into the given 2nd ODE equation y" + (k/m)x = 0; y(0) = 3; y'(0) = 0.
Using the Euler method and the exact solution to solve the problem, I have been able to run and receive some ok results. However, when I execute a plot of the results I get this diagonal line across the oscillating results that I am after.
Current plot output with diagonal line
Can anyone help point out what is causing this issue, and how I can fix it please?
MY CODE:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from sympy import Function, dsolve, Eq, Derivative, sin, cos, symbols
from sympy.abc import x, i
import math
# Given is y" + (k/m)x = 0; y(0) = 3; y'(0) = 0
# Parameters
h = 0.01; #Step Size
t = 50.0; #Time(sec)
k = 1; #Spring Stiffness
m = 1; #Mass
x0 = 3;
v0 = 0;
# Exact Analytical Solution
x_exact = x0*cos(math.sqrt(k/m)*t);
v_exact = -x0*math.sqrt(k/m)*sin(math.sqrt(k/m)*t);
# Eulers Method
x = np.zeros( int( t/h ) );
v = np.zeros( int( t/h ) );
x[1] = x0;
v[1] = v0;
x_exact = np.zeros( int( t/h ) );
v_exact = np.zeros( int( t/h ) );
te = np.zeros( int( t/h ) );
x_exact[1] = x0;
v_exact[1] = v0;
#print(len(x));
for i in range(1, int(t/h) - 1): #MAIN LOOP
x[i+1] = x[i] + h*v[i];
v[i+1] = v[i] - h*k/m*x[i];
te[i] = i * h
x_exact[i] = x0*cos(math.sqrt(k/m)* te[i]);
v_exact[i] = -x0*math.sqrt(k/m)*sin(math.sqrt(k/m)* te[i]);
# print(x_exact[i], '\t'*2, x[i]);
#plot
%config InlineBackend.figure_format = 'svg'
plt.plot(te, x_exact, te ,v_exact)
plt.title("DISPLACEMENT")
plt.xlabel("Time (s)")
plt.ylabel("Displacement (m)")
plt.grid(linewidth=0.3)
An in some details more direct computation is
te = np.arange(0,t,h)
N = len(te)
w = (k/m)**0.5
x_exact = x0*np.cos(w*te);
v_exact = -x0*w*np.sin(w*te);
plt.plot(te, x_exact, te ,v_exact)
resulting in
Note that arrays in python start at the index zero,
x = np.empty(N)
v = np.empty(N)
x[0] = x0;
v[0] = v0;
for i in range(N - 1): #MAIN LOOP
x[i+1] = x[i] + h*v[i];
v[i+1] = v[i] - h*k/m*x[i];
plt.plot(te, x, te ,v)
then gives the plot
with the expected increasing amplitude.

AttributeError: 'list' object has no attribute 'get_zorder'

I'm trying to animate projectile motion with the help of matplotlib.animation but I've been facing a few errors. Please help me with this.
Thank you so much
I've tried searching through the internet and I did implement solutions of a few similar problems but the code still gives an error
import matplotlib as mat
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as mat_anim
u = 5
g = 9.8
theta_degree = np.rad2deg([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
theta_rad = [0, np.pi/6, np.pi/4, np.pi/3, np.pi/2]
fr = 100
print(1)
def projectile_range():
# calculate projectile range
rng = ((u**2)*(np.sin(np.multiply(2.0, theta_rad))))/g
return rng
def max_height():
# calculate maximum height of projectile
max_ht = ((u*np.sin(theta_rad))**2)/(2*g)
return max_ht
def projectile():
# calculating projectile path
r = projectile_range()
for j in range(len(r)):
x = np.linspace(0, r[j], 100)
y.append(x*(np.tan(theta_rad[j])) - ((0.5*g*(x**2))/(u*np.cos(theta_rad[j]))**2))
return y
fig1, ax1 = plt.subplots(1,1)
fig1.suptitle("Projectile Motion Range", fontsize = 10)
ax1.set_xlim([0, round(max(projectile_range()))+1])
ax1.set_ylim([0, round(max(max_height()))+1])
# ax_range, = ax1.plot([], [])
dots, = ax1.plot([], [], 'o')
lines, = ax1.plot([], [], lw = 2)
plot_colour = ["black", "red", "green", "yellow", "blue"]
line_list = []
dot_list = []
print(2)
for index in range(len(theta_rad)):
line_obj = ax1.plot([], [], lw = 2, color = plot_colour[index])[0]
dot_obj = ax1.plot([], [], 'o', color = plot_colour[len(theta_rad)-index-1])[0]
line_list.append(line_obj)
dot_list.append(dot_obj)
print(3)
def initialize():
# initializing projectile range plot
print(4)
for line in line_list:
line.set_data([], [])
for dot in dot_list:
dot.set_data([], [])
print(5)
return dot_list, line_list,
print(6)
def proj_animation(i):
# animation function
print(7)
n = 100
# fr = n
y = np.empty([len(theta_rad), n], dtype = float)
x = np.empty([len(theta_rad), n], dtype = float)
r = projectile_range()
for j in range(len(r)):
x[j] = np.linspace(0, r[j], n)
y[j] = np.multiply(x[j], np.tan(theta_rad[j])) - ((0.5*g*(np.square(x[j])))/(u*np.cos(theta_rad[j]))**2)
for count, element in enumerate(line_list):
element.set_data(x[count][:i], y[count][:i])
for count, element in enumerate(dot_list):
element.set_data(x[count][i], y[count][i])
print(8)
return dot_list,line_list,
proj_anim = mat_anim.FuncAnimation(fig1, proj_animation, frames = fr,
interval = 20, blit = True)
proj_anim.save("projectile_range.mp4", fps = 20, extra_args = ['-vcodec', 'libx264'])
plt.show()
key=lambda x: x.get_zorder())
AttributeError: 'list' object has no attribute 'get_zorder'
I believe the issue is that in proj_animation() you are returning a tuple of two lists, but FuncAnimation() is looking for an iterable of drawn objects directly. The quickest fix for this is to concatenate dot_list with line_list and return the concatenated list. Nb This should also be done in your initialization function.
I was trying to plot sensor data using subplots and was getting the same error. The way I fixed it was to return just a variable or a list. In the animation function I was returning a list of lists, I just flattened this list of lists and the code works. The solution adapted to your code is the following:
import matplotlib as mat
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as mat_anim
u = 5
g = 9.8
theta_degree = np.rad2deg([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
theta_rad = [0, np.pi/6, np.pi/4, np.pi/3, np.pi/2]
fr = 100
print(1)
def projectile_range():
# calculate projectile range
rng = ((u**2)*(np.sin(np.multiply(2.0, theta_rad))))/g
return rng
def max_height():
# calculate maximum height of projectile
max_ht = ((u*np.sin(theta_rad))**2)/(2*g)
return max_ht
def projectile():
# calculating projectile path
r = projectile_range()
for j in range(len(r)):
x = np.linspace(0, r[j], 100)
y.append(x*(np.tan(theta_rad[j])) - ((0.5*g*(x**2))/(u*np.cos(theta_rad[j]))**2))
return y
fig1, ax1 = plt.subplots(1,1)
fig1.suptitle("Projectile Motion Range", fontsize = 10)
ax1.set_xlim([0, round(max(projectile_range()))+1])
ax1.set_ylim([0, round(max(max_height()))+1])
# ax_range, = ax1.plot([], [])
dots, = ax1.plot([], [], 'o')
lines, = ax1.plot([], [], lw = 2)
plot_colour = ["black", "red", "green", "yellow", "blue"]
line_list = []
dot_list = []
print(2)
for index in range(len(theta_rad)):
line_obj = ax1.plot([], [], lw = 2, color = plot_colour[index])[0]
dot_obj = ax1.plot([], [], 'o', color = plot_colour[len(theta_rad)-index-1])[0]
line_list.append(line_obj)
dot_list.append(dot_obj)
print(3)
def initialize():
# initializing projectile range plot
print(4)
for line in line_list:
line.set_data([], [])
for dot in dot_list:
dot.set_data([], [])
print(5)
return dot_list, line_list,
print(6)
def proj_animation(i):
# animation function
print(7)
n = 100
# fr = n
y = np.empty([len(theta_rad), n], dtype = float)
x = np.empty([len(theta_rad), n], dtype = float)
r = projectile_range()
graph_list = []
for j in range(len(r)):
x[j] = np.linspace(0, r[j], n)
y[j] = np.multiply(x[j], np.tan(theta_rad[j])) - ((0.5*g*(np.square(x[j])))/(u*np.cos(theta_rad[j]))**2)
for count, element in enumerate(line_list):
element.set_data(x[count][:i], y[count][:i])
for count, element in enumerate(dot_list):
element.set_data(x[count][i], y[count][i])
graph_list.append(dot_list)
graph_list.append(line_list)
graph_list = [item for sublist in graph_list for item in sublist]
print(8)
return graph_list
proj_anim = mat_anim.FuncAnimation(fig1, proj_animation, frames = fr,
interval = 20, blit = True)
proj_anim.save("projectile_range.mp4", fps = 20, extra_args = ['-vcodec', 'libx264'])
plt.show()
I test the code and it works.

Python / Spyder - Contourf() animation questions. Speed and Colorbar.

I am new to python and recently was able to generate a contourf animation. I know how to generate a colorbar, however I'm unsure as to how to implement a colorbar into the animation.
Also, is there a way to speed up the animation process?
My data is taken from an oscilloscope in a plane of measurement. Each location in the plane of measurement is stored as a file, where the file name is the location of measurement.
Below is my code.
from pylab import *
import matplotlib.animation as animation
# import pylab won't import animation
dr = 4;
dz = 4;
rStart = -72;
rEnd = 72;
zStart = -20;
zEnd = -236;
datatype = dtype('>d')
rspace = arange(rStart,rEnd+dr,dr)
zspace = arange(zStart,zEnd-dz,-dz)
tspace = 1000000 # number of samples
directory = 'D:\OscopeData\\'
data = zeros([len(zspace),len(rspace),tspace], dtype=datatype)
for j in range(0,len(zspace)):
for i in range(0,len(rspace)):
r = 'R' + str(rStart + dr(i))
z = 'Z' + str(zStart - dz(j))
datafile = directory + r + z + 'Ch1.dat'
data[j][i] = fromfile(datafile, dtype = datatype)
fig,ax = subplots()
textsize = 30
def animate(t):
ax.clear
ax.contourf(data[:,:,t],50)
title('Plot Title', fontsize = textsize + 6)
xlabel('R axis', fontsize = textsize)
ylabel('Z axis', fontsize = textsize)
anim = animation.FuncAnimation(fig, animate,50,blit=False)

Resources