Reputation: 1882
I am trying to plot a 3D surface using matplotlib's mpl_toolkits.mplot3d plot_surface function. My Z variable (a function f(x,y)) is pretty complicated and I cannot write it as a function of X and Y once I meshed them, so I computed it as a 2D array using a loop that goes through the x and y variables and stores everything in a matrix, Z. I am passing this array Z to the call of the plot_surface function, but I keep getting the wrong plot, basically because I expect the figure of Z but get the figure corresponding to Z.transpose.
I was able to do a much simpler example that reproduces my problem below:
X = range(5)
Y = range(5)
X,Y = np.meshgrid(X,Y)
mysol = np.array([[1,1,1,1,1],[2,2,2,2,2],[3,3,3,3,3],[4,4,4,4,4],[5,5,5,5,5]])
fig1 = plt.figure(1)
ax = fig1.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, mysol, rstride=1, cstride=1, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
So, I expect that this produces a plane so that when x=0, I get mysol[0,:] = [1,1,1,1,1] (the first row of my matrix mysol). Instead, if I look at the graph produced by this code, when x=0, I get the first column of the matrix (mysol[:,0] = [1,2,3,4,5].
I understand that the problem is fixed if I plot mysol.transpose() as opposed to mysol, but I am trying to understand the logic here. So, why is matplotlib doing this? I would expect it to plot the array row-wise, not column-wise. Where is my mistake?
Thanks in advance
Upvotes: 0
Views: 2178
Reputation: 339580
Matplotlib uses numpy and is very closely related to numpy's conventions.
Indexing a numpy array is such that a[j,i]
gives you the entry in the j
th row and the i
th column. Therefore j
is the vertical coordinate, i
is the horizontal one. Identifying
horizontal <-> x <-> i
vertical <-> y <-> j
ensures that any image is acutally exactly looking like the printed version of the array on paper; which makes it quite comfortable to work with those 2D arrays.
This is exactly what you see in the picture.
Upvotes: 1
Reputation: 251548
Look at the result of your meshgrid
:
>>> np.meshgrid(range(5), range(5))
[array([[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]),
array([[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]])]
The first array is what you assigned to X, the second is what you assigned to Y. You can see that X increases across the columns, whereas Y increases down the rows.
So the answer to your question is that meshgrid by default returns XY coordinates, not row-column coordinates. Usually XY coordinates is what you want if you're doing math on the coordinates. But you can make meshgrid return matrix-style coordinates by passing the indexing='ij'
argument if that's what you want.
Upvotes: 2