plot a cylinder in python - python
I am trying to plot a full cylinder, using a cylindrical mesh grid.
However I just managed to get half a cylinder. Here is my code
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = 1
x = np.linspace(-r, r, 50)
y = np.linspace(-r, r, 50)
X, Y = np.meshgrid(x, y)
Z = (np.pi * -Y**2)
surf = ax.plot_surface(X, Y, Z)
What I would like to obtain is something like this
Could anybody give me some insights on how to do it?
In this post the ax.plot_surface function is called twice. In your case adding a minus sign to the Z does not yet result in a cylinder, but at least you have a top and bottom part.
Related
Want level curve in the xy-plane, but the plot is 3D
I am trying to make a figure to visualize Lagranges multiplier method. This means I want to draw the graph of some function z = f(x,y), but also the constraint g(x,y) = c. Because I want to draw the graph of f, this must obviously be a 3D plot. But the constraint g(x,y) = c is a level curve of g, and should lie in the xy-plane. I am using Python, and here is my current code: import matplotlib.pyplot as plt from matplotlib import cm import numpy as np fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) X = np.arange(-5,5,0.5) Y = X X, Y = np.meshgrid(X, Y) Z = 50 - X**2 - Y**2 surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm) ax.set_zlim(0, 50) g = X**2+Y**2 CS = ax.contour(X,Y,g) plt.show() and this is the output: Current plot I only need one level curve of g in the xy-plane. Now, I have several, and none of them lies at z = 0. Ideally, I should also somehow mark out the points of z=f(x,y) that lies directly over g(x,y) = c. I would really appreciate your feedback!
You need to add the optional argument "offset", so that the contour gets projected to a plane. To be in z=0: CS = ax.contour(X,Y,g, offset = 0) See here.
3D graphing the complex values of a function in Python
This is the real function I am looking to represent in 3D: y = f(x) = x^2 + 1 The complex function would be as follows: w = f(z) = z^2 + 1 Where z = x + iy and w = u + iv. These are four dimentions (x, y, u, v), but one can use u for 3D graphing. We get: f(x + iy) = x^2 + 2xyi - y^2 + 1 So: u = x^2 - y^2 + 1 and v = 2xy This u is what is being used in the code below. import numpy as np import matplotlib.pyplot as plt x = np.linspace(-100, 101, 150) y = np.linspace(-100, 101, 150) X, Y = np.meshgrid(x,y) U = (X**2) - (Y**2) + 1 fig = plt.figure(dpi = 300) ax = plt.axes(projection='3d') ax.plot_surface(X, Y, Z) plt.show() The following images are the side-view of the 3D function and the 2D plot for reference. I do not think they are alike. Likewise, here is the comparison between the 3 side-view and the 2D plot of w = z^3 + 1. They seem to differ as well. I have not been able to find too many resources regarding plotting in 3D using complex numbers. Because of this and the possible discrepancies mentioned before, I think the code must be flawed, but I can't figure out why. I would be grateful if you could correct me or advise me on any changes. The inspiration came from Welch Labs' 'Imaginary Numbers are Real' YouTube series where he shows a jaw-dropping representation of the complex values of the function I have been tinkering with. I was just wondering if anybody could point out any flaws in my reasoning or the execution of my idea since this code would be helpful in explaining the importance of complex numbers to HS students. Thank you very much for your time.
The f(z) = z^2 + 1 projection (that is, side-view) looks OK to me. You can use this technique to add the projections; this code: import numpy as np import matplotlib.pyplot as plt from matplotlib import cm def f(z): return z**2 + 1 def freal(x, y): return x**2 - y**2 + 1 x = np.linspace(-100, 101, 150) y = np.linspace(-100, 101, 150) yproj = 0 # value of y for which to project xu axes xproj = 0 # value of x to project onto yu axes X, Y = np.meshgrid(x,y) Z = X + 1j * Y W = f(Z) U = W.real fig = plt.figure() ax = plt.axes(projection='3d') ## surface ax.plot_surface(X, Y, U, alpha=0.7) # xu projection xuproj = freal(x, yproj) ax.plot(x, xuproj, zs=101, zdir='y', color='red', lw=5) ax.plot(x, xuproj, zs=yproj, zdir='y', color='red', lw=5) # yu projection yuproj = freal(xproj, y) ax.plot(y, yuproj, zs=101, zdir='x', color='green', lw=5) ax.plot(y, yuproj, zs=xproj, zdir='x', color='green', lw=5) # partially reproduce https://www.youtube.com/watch?v=T647CGsuOVU&t=107s x = np.linspace(-3, 3, 150) y = np.linspace(0, 3, 150) X, Y = np.meshgrid(x,y) U = f(X + 1j*Y).real fig = plt.figure() ax = plt.axes(projection='3d') ## surface ax.plot_surface(X, Y, U, cmap=cm.jet) ax.set_box_aspect( (np.diff(ax.get_xlim())[0], np.diff(ax.get_ylim())[0], np.diff(ax.get_zlim())[0])) #ax.set_aspect('equal') plt.show() gives this result: and The axis ticks don't look very good: you can investigate plt.xticks or ax.set_xticks (and yticks, zticks) to fix this. There is a way to visualize complex functions using colour as a fourth dimension; see complex-analysis.com for examples.
Scipy.interpolate and a 3D surface in matplotlib - data seems to be rotated within the axes?
I'm having trouble understanding a strange side effect of interpolating my data. I am plotting a 2D surface onto a 3D grid, this part works fine, however as soon as I tweaked it to include scipy.interpolate I get a strange glitch, (at least I think it is a glitch). Below is an image of two plots, LHS is the original data, RHS the interpolated plot. As you can see I have rotated the RHS so that the similarities between the shapes are clear, but as a result the axis facing us is different; (I have rotated both of these extensively and I'm confident the symmetry in this view is not a coincidence, it looks too similar and they look too different when viewed at the same rotation) To add interpolation to my code I followed the answer to this question: Smooth surface Plot with Pyplot I'll also add my code before and after I added that bit, in the hope that there's something really obvious I've missed ax = fig.add_subplot(111, projection='3d') #y is the sin(beta-alpha) value, x is the tan(beta) value and z is the cross-section in fb y = np.array(Y_list) x = np.array(x_list) X, Y = np.meshgrid(x, y) zs = np.array(z_list) Z = zs.reshape(Y.shape) print(type(Z)) print(Z.shape) ax.plot_surface(X, Y, Z) plt.ylabel(r"$Sin(\beta - \alpha)$") plt.xlabel(r"$Tan(\beta)$") ax.zaxis.set_rotate_label(False) # disable automatic rotation ax.set_zlabel('Cross-section (pb)', rotation=90) #this is the rotation bit for angle in range(0, 360): ax.view_init(30, angle) plt.draw() plt.pause(.001) (Obviously there is code beforehand importing everything such as numpy, scipy etc and getting the data, but this is untouched between the two versions) y = np.array(Y_list) x = np.array(x_list) xstart = float(x[0]) xend = float(x[-1]) ystart = float(y[0]) yend = float(y[-1]) X, Y = np.mgrid[xstart:xend:10j, ystart:yend:22j] zs = np.array(z_list) #Z = zs.reshape(Y.shape) #The following lines perform interpolation tck = interpolate.bisplrep(X, Y, zs, s=0) Znew = interpolate.bisplev(X[:,0], Y[0,:], tck) fig = plt.figure() ax = fig.gca(projection='3d') ax.plot_surface(X, Y, Z) plt.ylabel(r"$Sin(\beta - \alpha)$") plt.xlabel(r"$Tan(\beta)$") ax.zaxis.set_rotate_label(False) # disable automatic rotation ax.set_zlabel('Cross-section (pb)', rotation=90) #this is the rotation bit for angle in range(0, 360): ax.view_init(30, angle) plt.draw() plt.pause(.001) I'm stumped and any help would be appreciated!
How do you create a 3D surface plot with missing values matplotlib?
I am trying to create a 3D surface energy diagram where an x,y position on a grid contains an associated z level. The issue is that the grid is not uniform (ie, there is not a z component for every x,y position). Is there a way to refrain from plotting those values by calling them NaN in the corresponding position in the array? Here is what I have tried so far: import numpy as np from matplotlib import pyplot as plt from mpl_toolkits.mplot3d import Axes3D import pylab from matplotlib import cm #Z levels energ = np.array([0,3.5,1,-0.3,-1.5,-2,-3.4,-4.8]) #function for getting x,y associated z values? def fun(x,y,array): return array[x] #arrays for grid x = np.arange(0,7,0.5) y = np.arange(0,7,0.5) #create grid X, Y = np.meshgrid(x,y) zs = np.array([fun(x,y,energ) for x in zip(np.ravel(X))]) Z = zs.reshape(X.shape) plt3d = plt.figure().gca(projection='3d') #gradients now with respect to x and y, but ideally with respect to z only Gx, Gz = np.gradient(X * Y) G = (Gx ** 2 + Gz ** 2) ** .5 # gradient magnitude N = G / G.max() # normalize 0..1 plt3d.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=cm.jet(N), edgecolor='k', linewidth=0, antialiased=False, shade=False) plt.show() I cannot post image here of this plot but if you run the code you will see it But I would like to not plot certain x,y pairs, so the figure should triangle downward to the minimum. Can this be accomplished by using nan values? Also would like spacing between each level, to be connected by lines. n = np.NAN #energ represents the z levels, so the overall figure should look like a triangle. energ = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,2.6,n,2.97,n,2.6,n,2.97,n,2.6,n,3.58,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,1.09,n,1.23,n,1.09,n,1.23,n,1.7,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,-0.65,n,-0.28,n,-0.65,n,0.33,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,-2.16,n,-2.02,n,-1.55,n,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,-3.9,n,-2.92,n,n,n,n,n,],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,n,-4.8,n,n,n,n,n,n,]]) plt3d = plt.figure().gca(projection='3d') Gx, Gz = np.gradient(X * energ) # gradients with respect to x and z G = (Gx ** 2 + Gz ** 2) ** .5 # gradient magnitude N = G / G.max() # normalize 0..1 x = np.arange(0,13,1) y = np.arange(0,13,1) X, Y = np.meshgrid(x,y) #but the shapes don't seem to match up plt3d.plot_surface(X, Y, energ, rstride=1, cstride=1, facecolors=cm.jet(N), edgecolor='k', linewidth=0, antialiased=False, shade=False ) Using masked arrays generates the following error: local Python[7155] : void CGPathCloseSubpath(CGMutablePathRef): no current point. n = np.NAN energ = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,2.6,n,2.97,n,2.6,n,2.97,n,2.6,n,3.58,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,1.09,n,1.23,n,1.09,n,1.23,n,1.7,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,-0.65,n,-0.28,n,-0.65,n,0.33,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,-2.16,n,-2.02,n,-1.55,n,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,-3.9,n,-2.92,n,n,n,n,n,],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,n,-4.8,n,n,n,n,n,n,]]) x = np.arange(0,13,1) y = np.arange(0,13,1) X, Y = np.meshgrid(x,y) #create masked arrays mX = ma.masked_array(X, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]]) mY = ma.masked_array(Y, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]]) m_energ = ma.masked_array(energ, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]]) plt3d = plt.figure().gca(projection='3d') plt3d.plot_surface(mX, mY, m_energ, rstride=1, cstride=1, edgecolor='k', linewidth=0, antialiased=False, shade=False) plt.show()
I was playing around with the code from this forum post, and I was able to make the graph have missing values. You can try the code yourself! I got it to work using float("nan") for the missing values. import plotly.graph_objects as go import numpy as np x = np.arange(0.1,1.1,0.1) y = np.linspace(-np.pi,np.pi,10) #print(x) #print(y) X,Y = np.meshgrid(x,y) #print(X) #print(Y) result = [] for i,j in zip(X,Y): result.append(np.log(i)+np.sin(j)) result[0][0] = float("nan") upper_bound = np.array(result)+1 lower_bound = np.array(result)-1 fig = go.Figure(data=[ go.Surface(z=result), go.Surface(z=upper_bound, showscale=False, opacity=0.3,colorscale='purp'), go.Surface(z=lower_bound, showscale=False, opacity=0.3,colorscale='purp')]) fig.show()
Plotting image Red channel by intensity
Okay, So i'm trying to take the red channel of an image, and plot it (preferably 3d) to an image. The image is 480x640 (or thereabouts), and is taken from a webcam. I'm currently using scipy, numpy, and python to get the image, extract he red channel, and process it. That all works. However, when i try to plot it, 2 different problems occur, depending on how I try to plot: 1) Width mismatch, it doesn't like that the image isn't square. 2) It only plots one row of the image (x val = 0, all y vals). I've attached the relevent code. Comments are everywhere, for when i try different ways. fig = plt.figure() #ax = Axes3D(fig) #ax = fig.add_subplot(111, projection='3d') X = [range(480), range(480)] Y = [range(480), range(480)] #X = range(len(self.R)) #Y = range(len(self.R)) ''' surf = ax.plot_surface(X, Y, np.resize(self.R, (480, 480)) , rstride=1, cstride=10, cmap=cm.jet, linewidth=0, antialiased=False) ax.set_zlim3d(0.0, 255.0) ax.w_zaxis.set_major_locator(LinearLocator(100)) ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f')) m = cm.ScalarMappable(cmap=cm.jet) m.set_array(self.frame_in) fig.colorbar(m) np.savetxt("tmp.txt", self.R) ''' #np.savetxt("tmp.out", self.R[0]) #np.savetxt("tmp.out1", self.R[1]) #np.savetxt("tmp.txt", self.frame_in, "[ %s ]", "\t") #plt.subplot(212) #x, y = self.R.shape #x = range(x) #y = range(y) #X, Y = np.meshgrid(x, y) plt.scatter(X, Y, self.R) #plt.pcolormesh(self.R) #plt.colorbar() #ax.scatter(x, y, self.R, c='r', marker='o') plt.show() I can clean up the code if needed, but i wanted everyone to see the multiple ways i've tried. Am i missing something really stupid simple? It doesn't make sense that it will work with the first row, and not all of them. Thanks in advance!
Try using pyplot.imshow: plt.cmap('Reds') plt.imshow(self.R) plt.show()