When using multidimensional arrays, it is very important to understand the order of the indices, and how they are interpreted by different modules.
The indices of 2-D arrays are ordered in the same way as matrix indices are. Example:
import numpy as np m = np.array([[1,2,3],[4,5,6]]) m
array([[1, 2, 3], [4, 5, 6]])
The first index (here set to 1) counts rows (i.e. it counts from top to bottom). The second index (here set to 0) counts columns (i.e. it counts from left to right). This is exactly the way it is done with matrices.
Note that we can regard the above matrix as a set of rows:
array([4, 5, 6])
We can thus also get element
[1,0] by first extracting the row, then extracting the column:
But when we want to slice, there can be confusing things happening:
array([1, 2, 3])
Any idea why these two ways of slicing give different results?
m interpretation of a 2D array also is related to the concept of "inner index" and "outer index". What does that mean? The point is that a 2D array is, in computer memory, in fact a 1D array. It is merely interpreted as a 2D array. The way to see this is like this:
mflat = m.flatten() mflat
array([1, 2, 3, 4, 5, 6])
The 'flattened' array is the actual array as it is in memory. You see that the rows are concatenated after each other. You can addess the element
m[ivert,ihori] also directly in
ivert, ihori = 1,0 print(m[ivert,ihori]) print(mflat[ivert*3+ihori])
mflat is the actual array (below the surface, so to speak), the 2-D array is just a shape given to that array. With
reshape() we can change the shape of this dataset:
malt = m.reshape(3,2) malt
array([[1, 2], [3, 4], [5, 6]])
Note that this is different from the transpose:
array([[1, 4], [2, 5], [3, 6]])
Another confusing thing can be when we make 2D arrays as maps in an x-y plane. Let's make such a map and see what happens:
x=np.linspace(-1,1,40) y=np.linspace(-0.5,0.5,20) xx,yy=np.meshgrid(x,y) ff=np.cos(xx*7.5)*np.exp(-0.5*((yy-0.25)/0.15)**2)
%matplotlib inline import matplotlib.pyplot as plt plt.imshow(ff)
<matplotlib.image.AxesImage at 0x7f8922cbefd0>
First note, that the y-axis goes from top to bottom (just like with a matrix). This is also how the old-fashioned TV set worked: an electron beam went from left to right (rows), and then from top to bottom. It is also the way we read a book. But it is not how mathematians make a figure: we tend to put the y-axis from bottom to top. You can set this with
<matplotlib.image.AxesImage at 0x7f8922ca1e48>
Now let's have a closer look at the index order:
As you can see by the outcome of
ff.shape: The x-index (which has 40 elements) is right, the y-index (which has 20 elements) is left. So the index-order is
ff[index_y,index_x], i.e. (y,x). This can be confusing, because in mathematics we are used to set the order to (x,y). But from the python perspective this makes sense: x is the "inner index" and y is the "outer index".
So the index ordering is y,x, but the order of the arguments for
np.meshgrid() are x,y (opposite).
You can, if you like, force meshgrid to set the index order also to x,y:
But then you have to be careful when using
imshow(): You now have to use the transpose:
<matplotlib.image.AxesImage at 0x7f8922b479e8>
x=np.linspace(-1,1,40) y=np.linspace(-0.5,0.5,20) z=np.linspace(0,3,10) xx,yy,zz=np.meshgrid(x,y,z) ff=np.cos(xx*7.5)*np.exp(-0.5*((yy-0.25)/0.15)**2)*np.exp(-zz)
(20, 40, 10)
Now things get really confusing! As you see, the index order is now: y,x,z, while the argument order to
meshgrid() remains x,y,z.
Therefore, for 3-D and higher-dimensional arrays, I recommend always to use