I have 2 1D arrays with the values of x and y, and also a 2D array with the values of z for each point where the columns correspond to the x values and the rows to the y values. Is there any way to get a plot_surface with this data? when I try to do it it returns me no plot. Here is the code: (calculate_R is a function I made for the program)
x=np.arange(0,10,1)
y=np.arange(0,1,0.2)
lx= len(x)
ly=len(y)
z=np.zeros((lx,ly))
for i in range(lx):
for j in range(ly):
z[i,j]=calculate_R(y[j],x[i])
fig = plt.figure()
ax = Axes3D(fig)
x, y = np.meshgrid(x, y)
ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap='hot')
You forgot to call plt.show() to display your plot.
Note that you might be able to exploit numpy vectorization to speed up the calculation of z:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
x = np.arange(0,10,1)
y = np.arange(0,1,0.2)
xs, ys = np.meshgrid(x, y)
# z = calculate_R(xs, ys)
zs = xs**2 + ys**2
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_surface(xs, ys, zs, rstride=1, cstride=1, cmap='hot')
plt.show()
Here, I used a simple function, since you didn't supply a fully working example.
Related
I have computed a lot (~5000) of 3d points (x,y,z) in a quite complicated way so I have no function such that z = f(x,y). I can plot the 3d surface using
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
surf = ax.plot_trisurf(X, Y, Z, cmap=cm.coolwarm, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
I would like to plot this also in 2d, with a colorbar indicating the z-value. I know there is a simple solution using ax.contour if my z is a matrix, but here I only have a vector.
Attaching the plot_trisurf result when rotated to xy-plane. This is what I what like to achieve without having to rotate a 3d plot. In this, my variable surface_points is an np.array with size 5024 x 3.
I had the same problems in one of my codes, I solved it this way:
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pylab as plt
from matplotlib import cm
N = 10000
surface_points = np.random.rand(N,3)
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
nx = 10*int(np.sqrt(N))
xg = np.linspace(X.min(), X.max(), nx)
yg = np.linspace(Y.min(), Y.max(), nx)
xgrid, ygrid = np.meshgrid(xg, yg)
ctr_f = griddata((X, Y), Z, (xgrid, ygrid), method='linear')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.contourf(xgrid, ygrid, ctr_f, cmap=cm.coolwarm)
plt.show()
You could use a scatter plot to display a projection of your z color onto the x-y axis.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
N = 10000
surface_points = np.random.rand(N,3)
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
# fig = plt.figure()
# ax = fig.add_subplot(projection='3d')
# surf = ax.plot_trisurf(X, Y, Z, cmap=cm.coolwarm, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
fig = plt.figure()
cmap = cm.get_cmap('coolwarm')
color = cmap(Z)[..., :3]
plt.scatter(X,Y,c=color)
plt.show()
Since you seem to have a 3D shape that is hollow, you could split the projection into two like if you cur the shape in two pieces.
fig = plt.figure()
plt.subplot(121)
plt.scatter(X[Z<0.5],Y[Z<0.5],c=color[Z<0.5])
plt.title('down part')
plt.subplot(122)
plt.scatter(X[Z>=0.5],Y[Z>=0.5],c=color[Z>+0.5])
plt.title('top part')
plt.show()
I'd like to create a 3D plot from an equation with x and y, similar to Google's 3D graph.
An example:
input: sin(sqrt(x**2 + y**2))
output (3D plot):
The Z will obviously be equal to the given input, but how will x and y be calculated? Thanks for any help given!
You can start by creating a meshgrid for your X and Y. Then compute your Z by doing Z=np.sin(np.sqrt(X**2 + Y**2)). Finally, you can plot the surface by using the matplotlib function ax.plot_surface(X, Y, Z).
You can find the code below:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
N_points=100
x = np.linspace(-10, 10, N_points)
y = np.linspace(-10, 10, N_points)
X, Y = np.meshgrid(x, y)
Z=np.sin(np.sqrt(X**2 + Y**2))
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.plot_surface(X, Y, Z)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
And the output of this code gives:
I am trying to produce a 3D surface plot where X and Y are values between -50 and 50, and Z is calculated by a function depending on X and Y.
This function takes a vector as a parameter in the form of an np array. The vector's first row is a value from X and the second a value from Y. All combinations of X and Y should produce a Z value, hence the meshgrid.
Here is my implementation, for Z I am currently creating a vector where the first row is the entire dataset of X, and the second the entire dataset of Y. This is of course incorrect.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
import matplotlib.pyplot as plt
def myFunction(v):
return v.dot(np.array([1, 2]))
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.linspace(-50,50, 100)
Y = np.linspace(-50,50, 100)
X, Y = np.meshgrid(X, Y)
Z = myFunction(np.array([X, Y])) # <-- Here is the problem
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.Greens,
linewidth=0, antialiased=False)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
I hope I have made sense,
Thanks
You would probably like to supply an array with all x values in the frst column and all y values in the second column to the function. That would ensure to have the dimensions match for the dot product. The result can then be reshaped to the shape of the mesh.
Z = myFunction(np.array([X.flatten(), Y.flatten()]).T).reshape(X.shape)
Complete example:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
import matplotlib.pyplot as plt
def myFunction(v):
return v.dot(np.array([1, 2]))
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.linspace(-50,50, 100)
Y = np.linspace(-50,50, 100)
X, Y = np.meshgrid(X, Y)
Z = myFunction(np.array([X.flatten(), Y.flatten()]).T).reshape(X.shape)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.Greens,
linewidth=0, antialiased=False)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Currently when I animate a surface in matplotlib, I generate snapshots manually and stitch together with ImageMagick. This is similar to the standard matplotlib animation in that it does not transition between the two frames.
Can I ease (in D3js terminology, and I'm sure of industry terminology more broadly - linear/cubic easing) during the transition? Or, is there a function in numpy to interpolate between two frames (the two surfaces) and end with a transition?
A simple example would be transitioning from the matplotlib example to any modification of the surface.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
to
Z = np.sin(2*R)
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
You could evaluate np.sin(a * R) for a range of a values using broadcasting:
n = 10 # or however many intermediate arrays you want
a = np.linspace(1, 2, n)
interp_z = np.sin(a[:, None, None] * R[None]) # an (n, 40, 40) array
Now you can plot each of the intermediate arrays, save it as an image, then stitch the images together however you like:
for i, Z in enumerate(interp_z):
ax.plot_surface(X, Y, Z, ...)
fig.savefig('image_{}.png'.format(i))
I've had a look at matplotlib's examples of 3d plots, but none of these give me what I want to plot, something like:
The plot shows a series of measurements on the y-axis (N) and each measurement has an intensity spectrum (p/2hk_L), i.e. N is fixed for each line you see in the graph. What is the easiest function to use to plot data like this?
Here is a try:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.linspace(-50,50,100)
y = np.arange(25)
X,Y = np.meshgrid(x,y)
Z = np.zeros((len(y),len(x)))
for i in range(len(y)):
damp = (i/float(len(y)))**2
Z[i] = 5*damp*(1 - np.sqrt(np.abs(x/50)))
Z[i] += np.random.uniform(0,.1,len(Z[i]))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1000, color='w', shade=False, lw=.5)
ax.set_zlim(0, 5)
ax.set_xlim(-51, 51)
ax.set_zlabel("Intensity")
ax.view_init(20,-120)
plt.show()