I have to solve a problem "Fringes of Young" using integrals in Python with "quad" and "args"
Formula of the intensity on the screen for M(X,Y) for a source size R is the following :
A source point S have the coordinates (xs=0,ys) with -R/2<=ys<=R/2
I need to create a function to calculate the intensity I(X,Y,R) using "args" of "quad".
Then, plot I(0,Y,10e-6) for Y between -0.01 and 0.01, also, I(0,Y,0.002),I(0,Y,0.003),I(0,Y,0.004). Any idea where is my fault?
My code :
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
y_min = -0.01
y_max = +0.01
R = y_max-y_min
y = np.linspace(y_min, y_max, 100)
X = 0
Y = 0
d = 1
D = 10
s = 10
Lambda = 0.5e-3
delta_s = lambda ys,X,Y : np.sqrt(X**2+(Y-d/2)**2+D**2)+np.sqrt((ys-d/2)**2+s**2)- \
np.sqrt(X**2+(Y+d/2)**2+D**2)-np.sqrt((ys+d/2)**2+s**2)
def integrand(y_s,x,y):
value = 2*(1+np.cos(2*np.pi*delta_s(x,y,y_s)/Lambda))
return value
def calcul_XYR(X,Y,R):
compteur = 0
I_XYR = [] # array for I(X,Y,R)
while compteur < len(y-1):
Y = y[compteur]
print(Y)
I_XYR.append(1/R*quad(integrand, -R/2, R/2, args=(X,Y))[0])
compteur+=1
return I_XYR
plt.figure(figsize=(7, 5))
plt.title("Franges de Young - Figure 3")
plt.axis([y_min, 0.015, 0, 4])
plt.xlabel("Y (mm)")
plt.ylabel("Intensity (a.u.)")
plt.plot(y, calcul_XYR(0,Y,1e-6), '-', color="red", label=r'$R=10^{-6}$')
plt.plot(y, calcul_XYR(0,Y,0.002), '-', color="blue", label=r'$R=0.002$')
plt.plot(y, calcul_XYR(0,Y,0.003), '-', color="black", label=r'$R=0.003$')
plt.plot(y, calcul_XYR(0,Y,0.004), '-', color="green", label=r'$R=0.004$')
plt.legend(loc='right', bbox_to_anchor=(1.00, 0.3))
plt.savefig('question 3 figure.pdf', format='pdf')
plt.show()
Result :
Expected :
I'd also like to plot (using imshow with parameters : cmp(gray),vmin,vmax) a 2D image corresponding to I(X,Y,1e-06). (X between -10 to 10).
The main mistake is the order of the parameters to delta_s. It is defined as delta_s = lambda ys, X, Y, but called as delta_s(X, Y, ys).
Also, calcul_XYR doesn't use its parameter Y, so it's better removed. The loop can be written as for Y in y.
Here is the modified code to generate the desired plot:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
y_min = -0.01
y_max = +0.01
#R = y_max - y_min
y = np.linspace(y_min, y_max, 100)
X = 0
Y = 0
d = 1
D = 10
s = 10
Lambda = 0.5e-3
def delta_s(X, Y, ys):
return np.sqrt(X ** 2 + (Y - d / 2) ** 2 + D ** 2) + np.sqrt((ys - d / 2) ** 2 + s ** 2) - \
np.sqrt(X ** 2 + (Y + d / 2) ** 2 + D ** 2) - np.sqrt((ys + d / 2) ** 2 + s ** 2)
def integrand(y_s, x, y):
return 2 * (1 + np.cos(2 * np.pi * delta_s(x, y, y_s) / Lambda))
def calcul_XR(X, R):
I_XYR = [] # array for I(X,Y,R)
for Y in y:
I_XYR.append(1 / R * quad(integrand, -R / 2, R / 2, args=(X, Y))[0])
return I_XYR
plt.figure(figsize=(7, 5))
plt.title("Franges de Young - Figure 3")
plt.axis([y_min, 0.015, 0, 4])
plt.xlabel("Y (mm)")
plt.ylabel("Intensity (a.u.)")
plt.plot(y, calcul_XR(0, 1e-6), '-', color="red", label=r'$R=10^{-6}$')
plt.plot(y, calcul_XR(0, 0.002), '-', color="blue", label=r'$R=0.002$')
plt.plot(y, calcul_XR(0, 0.003), '-', color="black", label=r'$R=0.003$')
plt.plot(y, calcul_XR(0, 0.004), '-', color="green", label=r'$R=0.004$')
plt.legend(loc='right', bbox_to_anchor=(1.00, 0.3))
plt.savefig('question 3 figure.pdf', format='pdf')
plt.show()
The following code displays an image of the function:
x_min = -10
x_max = 10
x = np.linspace(x_min, x_max, 100)
R = 1e-6
plt.figure(figsize=(7, 5))
graphe1 = []
for xi in x:
graphe1.append(calcul_XYR(xi, R))
graphe1 = np.array(graphe1).T #convert to numpy array and transpose
# imshow normally starts displaying at the top `origin='lower'` reverses this;
# the extent is used to tell imshow what the x and y limits of the image are, to correctly put the ticks
# without `aspect='auto'` imshow seems to want to display x and y with the same scale
# interpolation='bilinear' tells to smooth out the pixels
plt.imshow(graphe1, cmap=plt.cm.gray, vmin=None, vmax=None,
extent=[x_min, x_max, y_min, y_max],
aspect='auto', origin='lower', interpolation='bilinear')
plt.xlabel('X')
plt.ylabel('Y')
plt.title(f'R={R}')
plt.show()
Related
After reading Calculus book I think for function that has no trouble to calculate its inverse it is easy to calculate the surface area about x-axis and y-axis. But, if the function is like this: y = (x^6 + 2)/(8x^2)
I can calculate the surface area revolve around x-axis. But not so easy about y-axis. Since I think calculating the inverse of such function is not easy.
This is the code / MWE:
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
x = sy.Symbol("x")
def f(x):
return ((x**6) + 2)/ (8*x ** 2)
def fd(x):
return sy.simplify(sy.diff(f(x), x))
def f2(x):
return sy.sqrt((1 + (fd(x)**2)))
def vx(x):
return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
vxi = sy.Integral(vx(x), (x, 1, 3))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()
n = 100
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
x = np.linspace(1, 3, 3)
y = ((x ** 6) + 2) / (8 * x ** 2)
t = np.linspace(0, np.pi * 2, n)
xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])
ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")
# find the inverse of the function
y_inverse = x
x_inverse = ((y_inverse ** 6) + 2) / ( 8 * x ** 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])
ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ \n Surface Area = {}".format(vxn))
plt.tight_layout()
plt.show()
The question is, can anyone help to calculate the inverse and then continuing with sympy to integrate it and calculate the surface area for this function that is revolved about y-axis?
I have add the assumption of nonnegative for variables x and r so why I can't plot this?
this is my code:
# Calculate the surface area of y = sqrt(r^2 - x^2)
# revolved about the x-axis
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
x = sy.Symbol("x", nonnegative=True)
r = sy.Symbol("r", nonnegative=True)
def f(x):
return sy.sqrt(r**2 - x**2)
def fd(x):
return sy.simplify(sy.diff(f(x), x))
def f2(x):
return sy.sqrt((1 + (fd(x)**2)))
def vx(x):
return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
vxi = sy.Integral(vx(x), (x, -r, r))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()
n = 100
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
x = np.linspace(1, 3, 3)
# Plot the circle
y = np.sqrt(r ** 2 - x ** 2)
t = np.linspace(0, np.pi * 2, n)
xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])
ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")
# find the inverse of the function
y_inverse = x
x_inverse = np.sqrt(r ** 2 - y_inverse ** 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])
ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ \n Surface Area = {}".format(vxn))
plt.tight_layout()
plt.show()
That's because at this line of code:
y = np.sqrt(r ** 2 - x ** 2)
r is still a Sympy's symbol. You need to assign a number to r.
This snippet of code is going to generate the following two pictures, which represents a complex function. Is it possible to apply the colors of the first image to the surface? If so, how?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
def saw_func(x, dx, a, b):
x = x / dx - np.floor(x / dx)
return a + (b - a) * x
def domain_coloring(mag, arg, phaseres=20):
arg[arg < 0] += 2 * np.pi
arg /= (2 * np.pi)
blackp = saw_func(arg, 1 / phaseres, 0.75, 1)
blackm = saw_func(np.log(mag), 2 * np.pi / phaseres, 0.75, 1)
black = blackp * blackm
H = arg
S, V = np.ones_like(H), black
return (hsv_to_rgb(np.dstack([H, S, V])) * 255).astype(np.uint8)
x = y = np.linspace(-2, 2, 500)
x, y = np.meshgrid(x, y)
z = x + 1j * y
f = (z - 1) / (z**2 + z + 1)
mag, arg = np.absolute(f), np.angle(f)
img = domain_coloring(mag, arg)
fig1, ax1 = plt.subplots()
ax1.imshow(
img,
extent = [np.amin(x), np.amax(x), np.amin(y), np.amax(y)],
interpolation = "nearest",
origin = "lower",
)
plt.show()
fig2 = plt.figure()
ax2 = fig2.add_subplot(1, 1, 1, projection="3d")
ax2.plot_surface(x, y, mag)
ax2.set_zlim([0, 10])
plt.show()
This tutorial example uses a parameter facecolors=. The colors need to be rgb values between 0 and 1. The example code uses a 200x200 grid, as 500x500 is rather slow (and also has more problems with artifacts at the asymptotes). rstride and cstride are set to 1 as default plot_surface skips points.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
def saw_func(x, dx, a, b):
x = x / dx - np.floor(x / dx)
return a + (b - a) * x
def domain_coloring(mag, arg, phaseres=20):
arg[arg < 0] += 2 * np.pi
arg /= (2 * np.pi)
blackp = saw_func(arg, 1 / phaseres, 0.75, 1)
blackm = saw_func(np.log(mag), 2 * np.pi / phaseres, 0.75, 1)
black = blackp * blackm
H = arg
S, V = np.ones_like(H), black
return hsv_to_rgb(np.dstack([H, S, V]))
x = y = np.linspace(-2, 2, 200)
x, y = np.meshgrid(x, y)
z = x + 1j * y
f = (z - 1) / (z**2 + z + 1)
mag, arg = np.absolute(f), np.angle(f)
img = domain_coloring(mag, arg)
fig2 = plt.figure()
ax2 = fig2.add_subplot(1, 1, 1, projection="3d")
ax2.plot_surface(x, y, mag, facecolors=img)
ax2.set_zlim([0, 10])
plt.show()
I would like to predict a ball trajectory by fitting its 3d coordinates into a parabola. Below is my code. But instead of a parabola, I got a straight line. If you have any clue about it, please let me know. Thanks!
# draw scatter coordiante
fig = plt.figure()
ax = plt.axes(projection = '3d')
x_list = []
y_list = []
z_list = []
for x in rm_list:
x_list.append(x[0][0])
y_list.append(x[0][1])
z_list.append(x[0][2])
x = np.array(x_list)
y = np.array(y_list)
z = np.array(z_list)
ax.scatter(x, y, z)
# curve fit
def func(x, a, b, c, d):
return a * x[0]**2 + b * x[1]**2 + c * x[0] * x[1] + d
data = np.column_stack([x_list, y_list, z_list])
popt, _ = curve_fit(func, data[:,:2].T, ydata=data[:,2])
a, b, c, d = popt
print('y= %.5f * x ^ 2 + %.5f * y ^ 2 + %.5f * x * y + %.5f' %(a, b, c, d))
x1 = np.linspace(0.3, 0.4, 100)
y1 = np.linspace(0.02, 0.06, 100)
z1 = a * x1 ** 2 + b * y1 ** 2 + c * x1 * y1 + d
ax.plot(x1, y1, z1, color='green')
plt.show()
Update 1
After changing the func to ax^2 + by^2 + cxy + dx + ey + f, I got a parabola but not fitting to the coordinate.
That you have your underlying timestamp data makes the fitting procedure easier:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
from numpy.polynomial import Polynomial
# test data generation with some noise
# here read in your data
np.random.seed(123)
n = 40
x_param = [ 1, 21, -1]
y_param = [12, -3, 0]
z_param = [-3, 0, -2]
px = Polynomial(x_param)
py = Polynomial(y_param)
pz = Polynomial(z_param)
t = np.random.choice(np.linspace (-3000, 2000, 1000)/500, n)
x = px(t) + np.random.random(n)
y = py(t) + np.random.random(n)
z = pz(t) + np.random.random(n)
# here start the real calculations
# draw scatter coordinates of raw data
fig = plt.figure()
ax = plt.axes(projection = '3d')
ax.scatter(x, y, z, label="raw data")
# curve fit function
def func(t, x2, x1, x0, y2, y1, y0, z2, z1, z0):
Px=Polynomial([x2, x1, x0])
Py=Polynomial([y2, y1, y0])
Pz=Polynomial([z2, z1, z0])
return np.concatenate([Px(t), Py(t), Pz(t)])
# curve fit
# start values are not necessary for this example
# but make it your rule to always provide start values for curve_fit
start_vals = [ 1, 10, 1,
10, 1, 1,
-1, -1, -1]
xyz = np.concatenate([x, y, z])
popt, _ = curve_fit(func, t, xyz, p0=start_vals)
print(popt)
#[ 1.58003630e+00 2.10059868e+01 -1.00401965e+00
# 1.25895591e+01 -2.97374035e+00 -3.23358241e-03
# -2.44293562e+00 3.96407428e-02 -1.99671092e+00]
# regularly spaced fit data
t_fit = np.linspace(min(t), max(t), 100)
xyz_fit = func(t_fit, *popt).reshape(3, -1)
ax.plot(xyz_fit[0, :], xyz_fit[1, :], xyz_fit[2, :], color="green", label="fitted data")
ax.legend()
plt.show()
Sample output:
I use matplot3d(ax.bar3d() and ax.plot) to plot two lines around a cuboid, when looking in bird viewbird view, this figure shows the read 3d relationship of all the objects. When looking from sideside view, some part of blue line that behind the green cylinder should be hidden, but this part still can be seen. I tried using parameter alpha, and it failed too. Does any body know how to deal with this ?
My matplotlib version is 2.1.0, and my python version is 3.4.7
# import
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# global set
XMAX = 4
ZMAX = 15
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
print(mpl.__version__)
z = np.linspace(0, ZMAX, 5)
if True:
arrowstartt = np.zeros((3))
arrowstartx = np.zeros((3))
arrowstarty = np.zeros((3))
arrowendt = np.zeros((3))
arrowendx = np.zeros((3))
arrowendy = np.zeros((3))
arrowcolor= 'black'
fontsizes = 25
# x cors
x = (XMAX + 1) / np.max(z) * z
y = 0. * z
zz = 0. * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[0] = x[-1]
arrowstarty[0] = y[-1]
arrowstartt[0] = zz[-1]
ax.text(x[-1], y[-1], zz[-1], "x", color='k', fontsize=fontsizes)
# y cors
x = 0. * z
y = 2 * XMAX / np.max(z) * z
zz = 0. * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[1] = x[-1]
arrowstarty[1] = y[-1]
arrowstartt[1] = zz[-1]
ax.text(x[-1], y[-1], zz[-1]-1, "y", color='k', fontsize=fontsizes)
#z cor
x = 0. * z
y = 0. * z
zz = (XMAX) / np.max(z) * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[2] = x[-1]
arrowstarty[2] = y[-1]
arrowstartt[2] = zz[-1]
ax.text(x[-1], y[-1], zz[-1], "z", color='k', fontsize=fontsizes)
# arrow end
arrowendx = arrowstartx + [1, 0, 0]
arrowendy = arrowstarty + [0, 1, 0]
arrowendt = arrowstartt + [0, 0, 1]
ax.quiver(arrowstartx, arrowstarty, arrowstartt, arrowendx, arrowendy, arrowendt,2, color=arrowcolor, linewidth=1)
# ax.set_xlabel('x')
# ax.set_ylabel('y')
# ax.set_zlabe('z')
# ax.arrow()
''' draw bar as a cylinder '''
if True:
# draw bar
xpos = 0.
ypos = 30.
dx = 1.4
dy = 2
ax.bar3d(xpos, ypos, 0, dx, dy, ZMAX, color='g', zsort='average')
#ax.bar3d(xpos, ypos, 0, dx, dy, ZMAX, alpha=0.8, color='g',zsort='average')
''' draw two lines'''
if True:
# the blue line
y = np.arange(0, 50, 1)
x = np.ones(len(y)) * (-2)
z = np.linspace(0, ZMAX, len(y))
ax.plot(x, y, z, 'b')
#ax.plot(x, y, z, 'b',alpha=0.8)
# the red line
y = np.arange(0, 50, 1)
x = np.ones(len(y)) * 2
z = np.linspace(0, ZMAX, len(y))
ax.plot(x, y, z, 'r')
plt.axis('off')
ax.legend()
plt.show()