Plot NumPy ndarray into a 3D surface - python

I have a numpy.ndarray of size 200x200. I want to plot it as a 3D surface where x and y are indexes of the array and z is the value of that array element. Is there any easy way to do it or do I have to transform my array into a long list?

For example using matplotlib:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
#your index
x = np.linspace(1, 200, 200);
y = np.linspace(1, 200, 200)
X, Y = np.meshgrid(x, y); #making a grid from it
fig = plt.figure()
ax = fig.gca(projection='3d')
R = np.sqrt(X**2 + Y**2) #make some calculations on the grid
Z = np.sin(R) #some more calculations
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-5, 5)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
However, as your array is already quite large, you might want to consider a different plotting tool like mayavi. matplotlib usually puts a copy of your complete array into the plot. That's memory demanding when dealing with big data. But I'm not sure, whether mayavi does the same or not.

You can also use mayavi and plot your array as a plane with different colors representing the values. It would look like this:
import numpy
from mayavi import mlab
mlab.imshow(yourarray)
mlab.show()
Alternative you can create points with an elevation from the ground plane and get a fitting plane through the points. See here:http://docs.enthought.com/mayavi/mayavi/auto/example_surface_from_irregular_data.html#example-surface-from-irregular-data
What is best for you depends on the continuity of your data.

If what you want is to plot a 3D surface on top of a 2D grid what you could do is something similar to this:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# create some fake data
array_distribution3d = np.ones((200, 200))
array_distribution3d[0:25, 0:25] = -1
# create the meshgrid to plot on
x = np.arange(0, array_distribution3d.shape[0])
y = np.arange(0, array_distribution3d.shape[1])
# here are the x,y and respective z values
X, Y = np.meshgrid(x, y)
z = []
for i in range(0, array_distribution3d.shape[0]):
z_y = []
for j in range(0, array_distribution3d.shape[1]):
z_y.append(array_distribution3d[i, j])
z.append(z_y)
Z = np.array(z)
# create the figure, add a 3d axis, set the viewing angle
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')
ax.view_init(45, 60)
# here we create the surface plot
ax.plot_surface(X, Y, Z)
However, to the best of my knowledge, this kind of data can be plotted as a colourmap.
This can be plotted as follows:
import numpy as np
import os.path
import matplotlib.pyplot as plt
array_distribution = np.ones((200, 200))
array_distribution[0:25, 0:25] = -1
fig = plt.imshow(array_distribution)
plt.colorbar(fraction=0.035, pad=0.035, ticks=[-1., 0., 1.])
axes = plt.gca()
axes.set_ylim([0, 200])
figure = plt.gcf()
file = os.path.join('demo1.png')
figure.savefig(file, dpi=250)
plt.close('all')
print('done')

Related

Plot 3d points (x,y,z) in 2d plot with colorbar

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()

printing a gridsearch in 3D for hyperparameter visualization

Trying to visualize hyperparamt and the result of them, I CAN NOT get to plot them in a 3d plot
I try to build a function as:
PlotGridSearch(grid,xparam,yparam,zlabels):
to be called as
gs= GridSearchCV(DecisionTreeClassifier()
,HyperParams
, scoring='accuracy'
, cv=50).fit(train_data,train_labels)
PlotGridSearch(gs
,'param_max_depth'
,'param_max_leaf_nodes'
,'mean_test_score')
But I can get to convert the mean_test_score columns to the necesary matrix (2 dimensional arrray) with the correct labels stracted from param_max_depth y param_max_leaf_nodes
any tips ?
There's a nice official documentation about 3D surface matplotlib plot.
# This import registers the 3D projection, but is otherwise unused.
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import
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()
If you are running python in Jupyter Notebook, you can use %matplotlib notebook to make it interactive.
And in your case, if you want to get the proper X,Y and Z, you could get the values from gs.cv_results_, which is:
m = len(param_grid['max_depth'])
n = len(param_grid['max_leaf_nodes'])
X = np.reshape(gs.cv_results_['param_max_depth'].data,[n,m]) # do mind the order of reshape, it might diff
Y = np.reshape(gs.cv_results_['param_max_leaf_nodes'].data,[n,m])
Z = np.reshape(gs.cv_results_['mean_test_score'],[n,m])

3D Surface Plot where z is a function that takes a vector formed from x and y

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()

meshgrid with 2d array as input

I have a 2D array of floats, each cell representing a magnitude at the col/row of said array and would like to create a surface plot and contour for it.
How do I use meshgrid on this 2D array?
My apologies for this simple - I am new to both Python and numpy.
Is this what you're looking for?
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# Generate fake data
x = np.linspace(-1, 1, 500)
y = np.linspace(-1, 1, 500)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2))
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
ax1.plot_surface(X, Y, Z, alpha=0.05, color="w")
ax1.contour(X, Y, Z, zorder=10)
plt.show()
All these functions are described in the mplot3d tutorial

Python plotting 2d data on to 3d axes

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()

Categories