santobedi
santobedi

Reputation: 858

Generating 3-D surface plot with data from different sized grid points in python

I learned to merge mesh grid points from two rectangles in python from this question. The merged grid points are:

enter image description here

Here each grid points contains their respective values and I want to plot a 3-D surface plot of it. For the full grid (without blank spot), I'd write the following code:

fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
x=np.arange(0,10,1)
y=np.arange(0,12,1)
X, Y = np.meshgrid(x,y)
print (Y)
Z = gridValue.reshape(X.shape)
cset = ax.pcolormesh(X, Y, Z, cmap=cm.coolwarm, linewidth =0, antialiased = False)
ax.clabel(cset, fontsize=9, inline=1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('σ ')
fig.colorbar(cset, shrink=0.5, aspect =5)
plt.show()

When I try to plot the grid values (80 points) with above code, I get an obvious error:

ValueError: cannot reshape array of size 80 into shape (12,10)

I'm expecting the following figure (not exactly but similar way) as the final 3-D surface plot:

enter image description here

How can I draw a 3-D surface plot is my situation?

Thank you.

EDIT: I tried to plot using the following code snippet:

fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
x1=np.arange(0,2,1)
x2 = np.arange(0,10,1)
y1 =np.arange(0,5,1)
y2=np.arange(5,12,1)
Y1, X1 = np.meshgrid(x1,y1)
Y2, X2 = np.meshgrid(x2,y2)
gridValue1 = gridValue[:10]
gridValue2 = gridValue[10:]
Z1 = gridValue1.reshape(X1.shape)
Z2 = gridValue2.reshape(X2.shape)
cset1 = ax.plot_surface(X1, Y1, Z1, cmap=cm.coolwarm, linewidth =0, antialiased = False)
cset2 = ax.plot_surface(X2, Y2, Z2, cmap=cm.coolwarm, linewidth =0, antialiased = False)
ax.clabel(cset1, fontsize=9, inline=1)
ax.clabel(cset2, fontsize=9, inline=1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('σ ')
plt.show()

I got following figure with this code:

enter image description here

Now the problem is to illustrate the figure. The color code (red color for high value, blue color for low value) is not valid any longer. Because the gridValues of blue gird points (in the first figure) are high, so most of them should have red color in the surface plot. So merging two individual 3-D surface plots is not the solution to my problem. Any help, please!

Upvotes: 1

Views: 580

Answers (1)

JE_Muc
JE_Muc

Reputation: 5774

If your gridValue array is larger than your meshgrid with (12,10) you need to interpolate gridValue to the correct shape. In your case, since I guess that you want to plot the shown shapes with 80 points, you need to construct an array for gridValue with the shape of the meshgrid and then distribute your 80 grid values to the correct positions of the gridValue array with shape (12,10). How you can do the distribution fully depends on the information that you have, thus unluckily I can't help you with that. But for example considering a y-sorted sequential distribution of the blue and green grids:

gridValue_new = np.zeros_like(X)
gridValue_new[:, 0] = gridValue[:12]
gridValue_new[:, 1] = gridValue[12:24]
gridValue_new.reshape(-1)[:8, 2:] = gridValue[24:]

The first two ligns distributing points could also be rewritten using reshape().

If you want to plot it in 2d, use pcolormesh. For 3d-plotting, using ax.plot_surface() will fit your needs. If you want to plot both grids in one axis, do the following:

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt

X, Y = np.meshgrid(np.arange(0, 10, 1), np.arange(0, 12, 1))
X1 = X[5:, :]
Y1 = Y[5:, :]
X2 = X[0:5, 0:2]
Y2 = Y[0:5, 0:2]
Z1 = np.random.rand(7, 10)  # generating some random grid values
Z2 = np.random.rand(5, 2)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X1, Y1, Z1)
ax.plot_surface(X2, Y2, Z2)

To get the correct colorbar, get the min/max values of your array:

vmin = gridValue.min()
vmax = gridValue.max()

and pass both as argument to plot_surface():

cset1 = ax.plot_surface(X1, Y1, Z1, cmap=cm.coolwarm, linewidth =0, antialiased = False, vmin=vmin, vmax=vmax)
cset2 = ax.plot_surface(X2, Y2, Z2, cmap=cm.coolwarm, linewidth =0, antialiased = False, vmin=vmin, vmax=vmax)

So your full code will look like this:

fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
x1=np.arange(0,2,1)
x2 = np.arange(0,10,1)
y1 =np.arange(0,5,1)
y2=np.arange(5,12,1)
Y1, X1 = np.meshgrid(x1,y1)
Y2, X2 = np.meshgrid(x2,y2)
gridValue1 = gridValue[:10]
gridValue2 = gridValue[10:]
Z1 = gridValue1.reshape(X1.shape)
Z2 = gridValue2.reshape(X2.shape)
vmin = gridValue.min()
vmax = gridValue.max()
cset1 = ax.plot_surface(X1, Y1, Z1, cmap=cm.coolwarm, linewidth =0, antialiased = False, vmin=vmin, vmax=vmax)
cset2 = ax.plot_surface(X2, Y2, Z2, cmap=cm.coolwarm, linewidth =0, antialiased = False, vmin=vmin, vmax=vmax)
ax.clabel(cset1, fontsize=9, inline=1)
ax.clabel(cset2, fontsize=9, inline=1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('σ ')
plt.show()

Upvotes: 2

Related Questions