Related
I am trying to plot but it seems the square root can't work with negative number.
This is the problem I am trying to solve:
this is the errors:
RuntimeWarning: invalid value encountered in sqrt
x2 = ((16/1)*(y-5+2))**(1/2)
/home/browni/LasthrimProjection/Python/plot.py:58: RuntimeWarning: invalid value encountered in sqrt
Y3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.cos(V)
/home/browni/LasthrimProjection/Python/plot.py:59: RuntimeWarning: invalid value encountered in sqrt
Z3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.sin(V)
This is my MWE:
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line y = (3/16)x^2 + 3 and y = (1/16)x^2 + 5
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return (3/16)*(x**2) + 3 - 2
def r2(x):
return (1/16)*(x**2) + 5 - 2
def r3(x):
return ((16/3)*(x - 3 + 2)) ** (1/2)
def r4(x):
return ((16/1)*(x - 5 + 2)) ** (1/2)
def vx(x):
return np.pi*(r2(x)**2 - r1(x)**2)
def vy(x):
return np.pi*(r3(x)**2 - r4(x)**2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 4))
vy = sy.integrate(vy(x), (x, 0, 6))
n = 200
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')
y = np.linspace(0, 6, n)
x1 = ((16/3)*y -3 + 2) ** (1/2)
x2 = ((16/1)*y - 5 + 2) ** (1/2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 4, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = ((3/16) * (U**2) + 3 - 2) * np.cos(V)
Z1 = ((3/16) * (U**2) + 3 - 2) * np.sin(V)
Y2 = ((1/16) * (U**2) + 5 - 2) * np.cos(V)
Z2 = ((1/16) * (U**2) + 5 - 2) * np.sin(V)
Y3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.cos(V)
Z3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.sin(V)
Y4 = (((16/1)*(x - 5 + 2)) ** (1/2)) * np.cos(V)
Z4 = (((16/1)*(x - 5 + 2)) ** (1/2)) * np.sin(V)
ax1.plot(x1, y, label='$y = (3/16)x^2 + 3 - 2$')
ax1.plot(x2, y, label='$y = (1/16)x^2 + 5 - 2$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 6, n)
y1_inverse = np.power((16/3)*(x_inverse - 3 + 2), 1/2)
y2_inverse = np.power((16/1)*(x_inverse - 5 + 2), 1/2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $(3/16)x^2 + 3 - 2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y = (1/16)x^2 + 5 - 2$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
how to fix this?
I have created this code by modification from previous topics.
I put the calculated volume on the volume plot. My questions are:
My plots are correct right?
My volume calculations are correct too right?
Why there will be negative volume? If I put the formula for vx(x) as r1 - r2 it will be negative. Should I put abs (absolute value) instead in the future? So I could careless If I put r1 - r2 or r2 - r1, the numbers is the same, only one has negative sign. What is the significant meaning of negative sign for volume? Do we need a careful thought when calculating volume through integration?
I do not use sympy is sympy better in calculating integral than numpy/scipy?
Thanks.. this is my code / MWE:
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line x - 2y = 0 and y^2 = 4x
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return x/2
def r2(x):
return 2*(x**(1/2))
def r3(x):
return 2*x
def r4(x):
return (x/2)**(2)
def vx(x):
return np.pi*(r2(x)**2 - r1(x)**2)
def vy(x):
return np.pi*(r3(x)**2 - r4(x)**2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 16))
vy = sy.integrate(vy(x), (x, 0, 8))
n = 200
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')
y = np.linspace(0, 8, n)
x1 = (2*y)
x2 = (y / 2) ** (2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 16, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = (2 * U ** (1/2)) * np.cos(V)
Z1 = (2 * U ** (1/2)) * np.sin(V)
Y2 = (U / 2) * np.cos(V)
Z2 = (U / 2) * np.sin(V)
Y3 = ((U / 2) ** (2)) * np.cos(V)
Z3 = ((U / 2) ** (2)) * np.sin(V)
Y4 = (2*U) * np.cos(V)
Z4 = (2*U) * np.sin(V)
ax1.plot(x1, y, label='$y=x/2$')
ax1.plot(x2, y, label='$y=2 \sqrt{x}$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 8, n)
y1_inverse = np.power(2*x_inverse, 1)
y2_inverse = np.power(x_inverse / 2, 2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $y=x/2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y=2 \sqrt{x}$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
Your plots are correct except for the plot at the upper right. The boundary is a little bit off. I change the np.linspace for u to u = np.linspace(0, 8, n). However, the np.linspace of u for bottom right plot is correct, so it remains u = np.linspace(0, 16, n). You can create different variable names for them, but I just simply reassign u again to u itself, and create an X2. I attached the complete code below.
Your volume calculations are correct.
Upper right plot:
Bottom right plot:
It is impossible to have negative volume. You can solve the integrate by hand first and compare it to the numerical results. You can check:
https://math.stackexchange.com/questions/261244/is-there-a-fundamental-reason-that-int-ba-int-ab?rq=1
SymPy is for symbolic computation, but it can also do numerical integration, so does SciPy. My guess is that they both have dependencies on NumPy. I think you are fine as long as you implement them correctly.
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line x - 2y = 0 and y^2 = 4x
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return x / 2
def r2(x):
return 2 * (x ** (1 / 2))
def r3(x):
return 2 * x
def r4(x):
return (x / 2) ** (2)
def vx(x):
return np.pi * (r2(x) ** 2 - r1(x) ** 2)
def vy(x):
return np.pi * (r3(x) ** 2 - r4(x) ** 2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 16))
vy = sy.integrate(vy(x), (x, 0, 8))
n = 200
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')
y = np.linspace(0, 8, n)
x1 = (2 * y)
x2 = (y / 2) ** (2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 16, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = (2 * U ** (1 / 2)) * np.cos(V)
Z1 = (2 * U ** (1 / 2)) * np.sin(V)
Y2 = (U / 2) * np.cos(V)
Z2 = (U / 2) * np.sin(V)
#######################################
u = np.linspace(0, 8, n) # linspace u for the upper right figure should be from 0 to 8 instead of 0 to 16
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X2 = U # created X2 here
Y3 = ((U / 2) ** (2)) * np.cos(V)
Z3 = ((U / 2) ** (2)) * np.sin(V)
Y4 = (2 * U) * np.cos(V)
Z4 = (2 * U) * np.sin(V)
ax1.plot(x1, y, label='$y=x/2$')
ax1.plot(x2, y, label='$y=2 \sqrt{x}$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X2, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X2, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 8, n)
y1_inverse = np.power(2 * x_inverse, 1)
y2_inverse = np.power(x_inverse / 2, 2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $y=x/2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y=2 \sqrt{x}$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
I'd like to create a plot with a specified figure size in which the 3D axes try to use the entire available space while maintaining an equal aspect ratio on all axis.
My current attempt shows a clipping rectangle that hides part of the mesh.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5, 2.5))
ax = fig.add_subplot(projection='3d')
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 1, 0.5]))
u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
ax.set_box_aspect([ub - lb for lb, ub in (getattr(ax, f'get_{a}lim')() for a in 'xyz')])
plt.show()
What can I do?
I copied the code you provided and just add 4 lines at the end.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
plt.close()
fig = plt.figure(figsize=(5, 2.5))
ax = fig.add_subplot(projection='3d')
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 1, 0.5]))
u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
# ax.set_box_aspect([ub - lb for lb, ub in (getattr(ax, f'get_{a}lim')() for a in 'xyz')])
left, right = plt.xlim()
ax.set_zlim(left, right)
ax.set_ylim(left, right)
plt.tight_layout()
I comment out the line ax.set_box_aspect since it gives me an error. The output of the above is:
--- edit ---
I have an idea for a workaround to make it works in matplotlib v3.4.2:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import os
plt.close()
# your code starts here, with a little modification
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(projection='3d')
u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
# set the axes limits
left, right = plt.xlim()
ax.set_zlim(left, right)
ax.set_ylim(left, right)
# zoom in to the plot
ax.dist = 6
# make everything other than the plot itself transparent
fig.patch.set_alpha(0)
ax.patch.set_alpha(0)
ax.axis('off')
plt.tight_layout()
# save plot as image
plt.savefig('plotted.png')
# remove the axes where the image was plotted
ax.remove()
# resize figsize
fig = matplotlib.pyplot.gcf()
fig.set_size_inches(5, 2.5)
# add fake axes for gridlines as in 3d plot to make it look like a real plot
# skip this part if the gridlines are unnecessary
ax_bg = fig.add_subplot(111, projection='3d')
ax_bg.dist = 3
# add axes in cartesian coordinates (xy-plane) for the image
ax = fig.add_subplot(111)
fig.patch.set_alpha(1)
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
im = plt.imread('plotted.png')
h, w, dc = im.shape # (height=500, width=500, depth/color=4)
im_cropped = im[120:390, :, :] # this is manually adjusted
ax.axis('off')
ax.imshow(im_cropped)
# delete the saved image
os.remove('plotted.png')
Output is:
I don't know if it will work in your particular context, but it works for just fulfilling your question.
Let me know if something is unclear.
Win 10 x64 Anaconda Python 2.7
I'm plotting an involute spiral onto a Gaussian surface with the following code..
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Spiral parameters
samNum = 1000
spConst = 10.0
t = np.linspace(0, 6*np.pi, samNum)
# Coordinates of involute spiral on xy-plane
coords = np.zeros([samNum, 3])
coords[:,0] = spConst * (np.cos(t) + t * np.sin(t)) # x coord
coords[:,1] = spConst * (np.sin(t) - t * np.cos(t)) # y coord
# Paramters for 2D Gaussian surface
amp = 200
sigma_x = 75.0
sigma_y = 75.0
theta = np.pi
a = np.cos(theta)**2 / (2 * sigma_x**2) + np.sin(theta)**2 / (2 * sigma_y**2)
b = -np.sin(2 * theta) / (4 * sigma_x**2) + np.sin(2 * theta) / (4 * sigma_y**2)
c = np.sin(theta)**2 / (2 * sigma_x**2) + np.cos(theta)**2 / (2 * sigma_y**2)
# z coords of spiral projected onto Gaussian surface
coords[:,2] = amp * np.exp(-(a * coords[:,0]**2 - 2 * b * coords[:,0]*coords[:,1] + c * coords[:,1]**2)) # z coord
# plot 3D spiral
ax.scatter(coords[:,0], coords[:,1], coords[:,2], s=1, c='k')
# plot lines projecting 3D spiral on to the xy-plane
for p in range(samNum):
ax.plot([coords[p,0], coords[p,0]], [coords[p,1], coords[p,1]], [0, coords[p,2]], color='g', linewidth=0.1)
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
This gives the following output...
I would like to convert the green ribbon into a continuous surface. I have had a look at parametric surfaces in matplotlib but cant get my head around how to covert this into a surface.
So is this possible? Any pointers appreciated.
In principle you have everything you need already there,
t = np.linspace(0, 6*np.pi, samNum)
T, Z = np.meshgrid(t, [0,1])
X = spConst * (np.cos(T) + T* np.sin(T))
Y = spConst * (np.sin(T) - T * np.cos(T))
gives you the X and Y coordinates, and the upper Z coordinate is obtained via Z[1,:] = coords[:,2].
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Spiral parameters
samNum = 1000
spConst = 10.0
t = np.linspace(0, 6*np.pi, samNum)
T, Z = np.meshgrid(t, [0,1])
X = spConst * (np.cos(T) + T* np.sin(T))
Y = spConst * (np.sin(T) - T * np.cos(T))
# Coordinates of involute spiral on xy-plane
coords = np.zeros([samNum, 3])
coords[:,0] = spConst * (np.cos(t) + t * np.sin(t)) # x coord
coords[:,1] = spConst * (np.sin(t) - t * np.cos(t)) # y coord
# Paramters for 2D Gaussian surface
amp = 200
sigma_x = 75.0
sigma_y = 75.0
theta = np.pi
a = np.cos(theta)**2 / (2 * sigma_x**2) + np.sin(theta)**2 / (2 * sigma_y**2)
b = -np.sin(2 * theta) / (4 * sigma_x**2) + np.sin(2 * theta) / (4 * sigma_y**2)
c = np.sin(theta)**2 / (2 * sigma_x**2) + np.cos(theta)**2 / (2 * sigma_y**2)
# z coords of spiral projected onto Gaussian surface
coords[:,2] = amp * np.exp(-(a * coords[:,0]**2 - 2 * b * coords[:,0]*coords[:,1] + c * coords[:,1]**2)) # z coord
Z[1,:] = coords[:,2]
ax.plot_surface(X,Y,Z)
# plot 3D spiral
ax.scatter(coords[:,0], coords[:,1], coords[:,2], s=1, c='k')
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
plt.show()
I'd like to plot pulse propagation in such a way at each step, it plots the pulse shape. In other words, I want a serie of x-z plots, for each values of y. Something like this (without color):
How can I do this using matplotlib (or Mayavi)? Here is what I did so far:
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
surf = ax.plot_wireframe(T, z, abs(U))
Change to:
ax.plot_wireframe(T, z, abs(U), cstride=1000)
and call:
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
will create the following graph:
If you need the curve been filled with white color:
import numpy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
U = numpy.abs(U)
verts = []
for i in xrange(T.shape[0]):
verts.append(zip(T[i, :], U[i, :]))
poly = PolyCollection(verts, facecolors=(1,1,1,1), edgecolors=(0,0,1,1))
ax.add_collection3d(poly, zs=z[:, 0], zdir='y')
ax.set_xlim3d(numpy.min(T), numpy.max(T))
ax.set_ylim3d(numpy.min(z), numpy.max(z))
ax.set_zlim3d(numpy.min(U), numpy.max(U))
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
pyplot.show()