Laura
Laura

Reputation: 1882

why is matplotlib plotting the transpose of a matrix in 3D plots?

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

enter image description hereSo, 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

Answers (2)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

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 jth row and the ith 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.

enter image description here

Upvotes: 1

BrenBarn
BrenBarn

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

Related Questions