What is the purpose of meshgrid in Python / NumPy? - python
Can someone explain to me what is the purpose of meshgrid function in Numpy? I know it creates some kind of grid of coordinates for plotting, but I can't really see the direct benefit of it.
I am studying "Python Machine Learning" from Sebastian Raschka, and he is using it for plotting the decision borders. See input 11 here.
I have also tried this code from official documentation, but, again, the output doesn't really make sense to me.
x = np.arange(-5, 5, 1)
y = np.arange(-5, 5, 1)
xx, yy = np.meshgrid(x, y, sparse=True)
z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
h = plt.contourf(x,y,z)
Please, if possible, also show me a lot of real-world examples.
The purpose of meshgrid is to create a rectangular grid out of an array of x values and an array of y values.
So, for example, if we want to create a grid where we have a point at each integer value between 0 and 4 in both the x and y directions. To create a rectangular grid, we need every combination of the x and y points.
This is going to be 25 points, right? So if we wanted to create an x and y array for all of these points, we could do the following.
x[0,0] = 0 y[0,0] = 0
x[0,1] = 1 y[0,1] = 0
x[0,2] = 2 y[0,2] = 0
x[0,3] = 3 y[0,3] = 0
x[0,4] = 4 y[0,4] = 0
x[1,0] = 0 y[1,0] = 1
x[1,1] = 1 y[1,1] = 1
...
x[4,3] = 3 y[4,3] = 4
x[4,4] = 4 y[4,4] = 4
This would result in the following x and y matrices, such that the pairing of the corresponding element in each matrix gives the x and y coordinates of a point in the grid.
x = 0 1 2 3 4 y = 0 0 0 0 0
0 1 2 3 4 1 1 1 1 1
0 1 2 3 4 2 2 2 2 2
0 1 2 3 4 3 3 3 3 3
0 1 2 3 4 4 4 4 4 4
We can then plot these to verify that they are a grid:
plt.plot(x,y, marker='.', color='k', linestyle='none')
Obviously, this gets very tedious especially for large ranges of x and y. Instead, meshgrid can actually generate this for us: all we have to specify are the unique x and y values.
xvalues = np.array([0, 1, 2, 3, 4]);
yvalues = np.array([0, 1, 2, 3, 4]);
Now, when we call meshgrid, we get the previous output automatically.
xx, yy = np.meshgrid(xvalues, yvalues)
plt.plot(xx, yy, marker='.', color='k', linestyle='none')
Creation of these rectangular grids is useful for a number of tasks. In the example that you have provided in your post, it is simply a way to sample a function (sin(x**2 + y**2) / (x**2 + y**2)) over a range of values for x and y.
Because this function has been sampled on a rectangular grid, the function can now be visualized as an "image".
Additionally, the result can now be passed to functions which expect data on rectangular grid (i.e. contourf)
Courtesy of Microsoft Excel:
Actually the purpose of np.meshgrid is already mentioned in the documentation:
np.meshgrid
Return coordinate matrices from coordinate vectors.
Make N-D coordinate arrays for vectorized evaluations of N-D scalar/vector fields over N-D grids, given one-dimensional coordinate arrays x1, x2,..., xn.
So it's primary purpose is to create a coordinates matrices.
You probably just asked yourself:
Why do we need to create coordinate matrices?
The reason you need coordinate matrices with Python/NumPy is that there is no direct relation from coordinates to values, except when your coordinates start with zero and are purely positive integers. Then you can just use the indices of an array as the index.
However when that's not the case you somehow need to store coordinates alongside your data. That's where grids come in.
Suppose your data is:
1 2 1
2 5 2
1 2 1
However, each value represents a 3 x 2 kilometer area (horizontal x vertical). Suppose your origin is the upper left corner and you want arrays that represent the distance you could use:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
where v is:
array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])
and h:
array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])
So if you have two indices, let's say x and y (that's why the return value of meshgrid is usually xx or xs instead of x in this case I chose h for horizontally!) then you can get the x coordinate of the point, the y coordinate of the point and the value at that point by using:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
That makes it much easier to keep track of coordinates and (even more importantly) you can pass them to functions that need to know the coordinates.
A slightly longer explanation
However, np.meshgrid itself isn't often used directly, mostly one just uses one of similar objects np.mgrid or np.ogrid.
Here np.mgrid represents the sparse=False and np.ogrid the sparse=True case (I refer to the sparse argument of np.meshgrid). Note that there is a significant difference between
np.meshgrid and np.ogrid and np.mgrid: The first two returned values (if there are two or more) are reversed. Often this doesn't matter but you should give meaningful variable names depending on the context.
For example, in case of a 2D grid and matplotlib.pyplot.imshow it makes sense to name the first returned item of np.meshgrid x and the second one y while it's
the other way around for np.mgrid and np.ogrid.
np.ogrid and sparse grids
>>> import numpy as np
>>> yy, xx = np.ogrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
As already said the output is reversed when compared to np.meshgrid, that's why I unpacked it as yy, xx instead of xx, yy:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6), sparse=True)
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
This already looks like coordinates, specifically the x and y lines for 2D plots.
Visualized:
yy, xx = np.ogrid[-5:6, -5:6]
plt.figure()
plt.title('ogrid (sparse meshgrid)')
plt.grid()
plt.xticks(xx.ravel())
plt.yticks(yy.ravel())
plt.scatter(xx, np.zeros_like(xx), color="blue", marker="*")
plt.scatter(np.zeros_like(yy), yy, color="red", marker="x")
np.mgrid and dense/fleshed out grids
>>> yy, xx = np.mgrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
The same applies here: The output is reversed compared to np.meshgrid:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6))
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
Unlike ogrid these arrays contain all xx and yy coordinates in the -5 <= xx <= 5; -5 <= yy <= 5 grid.
yy, xx = np.mgrid[-5:6, -5:6]
plt.figure()
plt.title('mgrid (dense meshgrid)')
plt.grid()
plt.xticks(xx[0])
plt.yticks(yy[:, 0])
plt.scatter(xx, yy, color="red", marker="x")
Functionality
It's not only limited to 2D, these functions work for arbitrary dimensions (well, there is a maximum number of arguments given to function in Python and a maximum number of dimensions that NumPy allows):
>>> x1, x2, x3, x4 = np.ogrid[:3, 1:4, 2:5, 3:6]
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
x1
array([[[[0]]],
[[[1]]],
[[[2]]]])
x2
array([[[[1]],
[[2]],
[[3]]]])
x3
array([[[[2],
[3],
[4]]]])
x4
array([[[[3, 4, 5]]]])
>>> # equivalent meshgrid output, note how the first two arguments are reversed and the unpacking
>>> x2, x1, x3, x4 = np.meshgrid(np.arange(1,4), np.arange(3), np.arange(2, 5), np.arange(3, 6), sparse=True)
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
# Identical output so it's omitted here.
Even if these also work for 1D there are two (much more common) 1D grid creation functions:
np.arange
np.linspace
Besides the start and stop argument it also supports the step argument (even complex steps that represent the number of steps):
>>> x1, x2 = np.mgrid[1:10:2, 1:10:4j]
>>> x1 # The dimension with the explicit step width of 2
array([[1., 1., 1., 1.],
[3., 3., 3., 3.],
[5., 5., 5., 5.],
[7., 7., 7., 7.],
[9., 9., 9., 9.]])
>>> x2 # The dimension with the "number of steps"
array([[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.]])
Applications
You specifically asked about the purpose and in fact, these grids are extremely useful if you need a coordinate system.
For example if you have a NumPy function that calculates the distance in two dimensions:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
And you want to know the distance of each point:
>>> ys, xs = np.ogrid[-5:5, -5:5]
>>> distances = distance_2d(1, 2, xs, ys) # distance to point (1, 2)
>>> distances
array([[9.21954446, 8.60232527, 8.06225775, 7.61577311, 7.28010989,
7.07106781, 7. , 7.07106781, 7.28010989, 7.61577311],
[8.48528137, 7.81024968, 7.21110255, 6.70820393, 6.32455532,
6.08276253, 6. , 6.08276253, 6.32455532, 6.70820393],
[7.81024968, 7.07106781, 6.40312424, 5.83095189, 5.38516481,
5.09901951, 5. , 5.09901951, 5.38516481, 5.83095189],
[7.21110255, 6.40312424, 5.65685425, 5. , 4.47213595,
4.12310563, 4. , 4.12310563, 4.47213595, 5. ],
[6.70820393, 5.83095189, 5. , 4.24264069, 3.60555128,
3.16227766, 3. , 3.16227766, 3.60555128, 4.24264069],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6. , 5. , 4. , 3. , 2. ,
1. , 0. , 1. , 2. , 3. ],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128]])
The output would be identical if one passed in a dense grid instead of an open grid. NumPys broadcasting makes it possible!
Let's visualize the result:
plt.figure()
plt.title('distance to point (1, 2)')
plt.imshow(distances, origin='lower', interpolation="none")
plt.xticks(np.arange(xs.shape[1]), xs.ravel()) # need to set the ticks manually
plt.yticks(np.arange(ys.shape[0]), ys.ravel())
plt.colorbar()
And this is also when NumPys mgrid and ogrid become very convenient because it allows you to easily change the resolution of your grids:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above
However, since imshow doesn't support x and y inputs one has to change the ticks by hand. It would be really convenient if it would accept the x and y coordinates, right?
It's easy to write functions with NumPy that deal naturally with grids. Furthermore, there are several functions in NumPy, SciPy, matplotlib that expect you to pass in the grid.
I like images so let's explore matplotlib.pyplot.contour:
ys, xs = np.mgrid[-5:5:200j, -5:5:200j]
density = np.sin(ys)-np.cos(xs)
plt.figure()
plt.contour(xs, ys, density)
Note how the coordinates are already correctly set! That wouldn't be the case if you just passed in the density.
Or to give another fun example using astropy models (this time I don't care much about the coordinates, I just use them to create some grid):
from astropy.modeling import models
z = np.zeros((100, 100))
y, x = np.mgrid[0:100, 0:100]
for _ in range(10):
g2d = models.Gaussian2D(amplitude=100,
x_mean=np.random.randint(0, 100),
y_mean=np.random.randint(0, 100),
x_stddev=3,
y_stddev=3)
z += g2d(x, y)
a2d = models.AiryDisk2D(amplitude=70,
x_0=np.random.randint(0, 100),
y_0=np.random.randint(0, 100),
radius=5)
z += a2d(x, y)
Although that's just "for the looks" several functions related to functional models and fitting (for example scipy.interpolate.interp2d,
scipy.interpolate.griddata even show examples using np.mgrid) in Scipy, etc. require grids. Most of these work with open grids and dense grids, however some only work with one of them.
Suppose you have a function:
def sinus2d(x, y):
return np.sin(x) + np.sin(y)
and you want, for example, to see what it looks like in the range 0 to 2*pi. How would you do it? There np.meshgrid comes in:
xx, yy = np.meshgrid(np.linspace(0,2*np.pi,100), np.linspace(0,2*np.pi,100))
z = sinus2d(xx, yy) # Create the image on this grid
and such a plot would look like:
import matplotlib.pyplot as plt
plt.imshow(z, origin='lower', interpolation='none')
plt.show()
So np.meshgrid is just a convenience. In principle the same could be done by:
z2 = sinus2d(np.linspace(0,2*np.pi,100)[:,None], np.linspace(0,2*np.pi,100)[None,:])
but there you need to be aware of your dimensions (suppose you have more than two ...) and the right broadcasting. np.meshgrid does all of this for you.
Also meshgrid allows you to delete coordinates together with the data if you, for example, want to do an interpolation but exclude certain values:
condition = z>0.6
z_new = z[condition] # This will make your array 1D
so how would you do the interpolation now? You can give x and y to an interpolation function like scipy.interpolate.interp2d so you need a way to know which coordinates were deleted:
x_new = xx[condition]
y_new = yy[condition]
and then you can still interpolate with the "right" coordinates (try it without the meshgrid and you will have a lot of extra code):
from scipy.interpolate import interp2d
interpolated = interp2d(x_new, y_new, z_new)
and the original meshgrid allows you to get the interpolation on the original grid again:
interpolated_grid = interpolated(xx[0], yy[:, 0]).reshape(xx.shape)
These are just some examples where I used the meshgrid there might be a lot more.
Short answer
The purpose of meshgrid is to help replace slow Python loops by faster vectorized operations available in NumPy library. meshgrid role is to prepare 2D arrays required by the vectorized operation.
Basic example showing the principle
Let's say we have two sequences of values,
a = [2,7,9,20]
b = [1,6,7,9]
and we want to perform an operation on each possible pair of values, one taken from the first list, one taken from the second list. We also want to store the result. For example, let's say we want to get the sum of the values for each possible pair.
Slow and laborious method
c = []
for i in range(len(b)):
row = []
for j in range(len(a)):
row.append (a[j] + b[i])
c.append (row)
print (c)
Result:
[[3, 8, 10, 21],
[8, 13, 15, 26],
[9, 14, 16, 27],
[11, 16, 18, 29]]
Fast and easy method
i,j = np.meshgrid (a,b)
c = i + j
print (c)
Result:
[[ 3 8 10 21]
[ 8 13 15 26]
[ 9 14 16 27]
[11 16 18 29]]
You can see from this basic illustration how the explicit slow Python loops have been replaced by hidden faster C loops in Numpy library. This principle is widely used for 3D operations, included colored pixel maps. The common example is a 3D plot.
Common use: 3D plot
x = np.arange(-4, 4, 0.25)
y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
(Borrowed from this site)
meshgrid is used to create pairs of coordinates between -4 and +4 with .25 increments in each direction X and Y. Each pair is then used to find R, and Z from it. This way of preparing "a grid" of coordinates is frequently used in plotting 3D surfaces, or coloring 2D surfaces.
Meshgrid under the hood
The two arrays prepared by meshgrid are:
(array([[ 2, 7, 9, 20],
[ 2, 7, 9, 20],
[ 2, 7, 9, 20],
[ 2, 7, 9, 20]]),
array([[1, 1, 1, 1],
[6, 6, 6, 6],
[7, 7, 7, 7],
[9, 9, 9, 9]]))
These arrays are created by repeating the values provided, either horizontally or vertically. The two arrays are shape compatible for a vector operation.
Origin
numpy.meshgrid comes from MATLAB, like many other NumPy functions. So you can also study the examples from MATLAB to see meshgrid in use, the code for the 3D plotting looks the same in MATLAB.
meshgrid helps in creating a rectangular grid from two 1-D arrays of all pairs of points from the two arrays.
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 1, 2, 3, 4])
Now, if you have defined a function f(x,y) and you wanna apply this function to all the possible combination of points from the arrays 'x' and 'y', then you can do this:
f(*np.meshgrid(x, y))
Say, if your function just produces the product of two elements, then this is how a cartesian product can be achieved, efficiently for large arrays.
Referred from here
Basic Idea
Given possible x values, xs, (think of them as the tick-marks on the x-axis of a plot) and possible y values, ys, meshgrid generates the corresponding set of (x, y) grid points---analogous to set((x, y) for x in xs for y in yx). For example, if xs=[1,2,3] and ys=[4,5,6], we'd get the set of coordinates {(1,4), (2,4), (3,4), (1,5), (2,5), (3,5), (1,6), (2,6), (3,6)}.
Form of the Return Value
However, the representation that meshgrid returns is different from the above expression in two ways:
First, meshgrid lays out the grid points in a 2d array: rows correspond to different y-values, columns correspond to different x-values---as in list(list((x, y) for x in xs) for y in ys), which would give the following array:
[[(1,4), (2,4), (3,4)],
[(1,5), (2,5), (3,5)],
[(1,6), (2,6), (3,6)]]
Second, meshgrid returns the x and y coordinates separately (i.e. in two different numpy 2d arrays):
xcoords, ycoords = (
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]),
array([[4, 4, 4],
[5, 5, 5],
[6, 6, 6]]))
# same thing using np.meshgrid:
xcoords, ycoords = np.meshgrid([1,2,3], [4,5,6])
# same thing without meshgrid:
xcoords = np.array([xs] * len(ys)
ycoords = np.array([ys] * len(xs)).T
Note, np.meshgrid can also generate grids for higher dimensions. Given xs, ys, and zs, you'd get back xcoords, ycoords, zcoords as 3d arrays. meshgrid also supports reverse ordering of the dimensions as well as sparse representation of the result.
Applications
Why would we want this form of output?
Apply a function at every point on a grid:
One motivation is that binary operators like (+, -, *, /, **) are overloaded for numpy arrays as elementwise operations. This means that if I have a function def f(x, y): return (x - y) ** 2 that works on two scalars, I can also apply it on two numpy arrays to get an array of elementwise results: e.g. f(xcoords, ycoords) or f(*np.meshgrid(xs, ys)) gives the following on the above example:
array([[ 9, 4, 1],
[16, 9, 4],
[25, 16, 9]])
Higher dimensional outer product: I'm not sure how efficient this is, but you can get high-dimensional outer products this way: np.prod(np.meshgrid([1,2,3], [1,2], [1,2,3,4]), axis=0).
Contour plots in matplotlib: I came across meshgrid when investigating drawing contour plots with matplotlib for plotting decision boundaries. For this, you generate a grid with meshgrid, evaluate the function at each grid point (e.g. as shown above), and then pass the xcoords, ycoords, and computed f-values (i.e. zcoords) into the contourf function.
Behind the scenes:
import numpy as np
def meshgrid(x , y):
XX = []
YY = []
for colm in range(len(y)):
XX.append([])
YY.append([])
for row in range(len(x)):
XX[colm].append(x[row])
YY[colm].append(y[colm])
return np.asarray(XX), np.asarray(YY)
Lets take dataset of #Sarsaparilla's answer as example:
y = [7, 6, 5]
x = [1, 2, 3, 4]
xx, yy = meshgrid(x , y)
and it outputs:
>>> xx
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
>>> yy
array([[7, 7, 7, 7],
[6, 6, 6, 6],
[5, 5, 5, 5]])
Related
Numpy arrays with rows meeting 3 conditions involving the matching of elements
This question has three related parts. Consider the numpy array sample, P, having 4 columns. import numpy as np P = np.array([-4, 5, 2, -3], [-5, 6, 0, -5], [-6, 5, -2, 5], [1, -2, 1, -2], [2, -4, -6, 8], [-4, 9, -4, 2], [0, -8, -8, 1]]) I'm hoping to learn how to build three new arrays: a) P1: This is P where the first element of a row has a match in the last 3 elements. b) P2: This is P where the first 2 elements of a row have a match in the last 2 elements. c) P3: This is P where the first 3 elements of a row have a match in the last element. The outcomes, for the small sample array, would be: P1 = [[-5, 6, 0, -5], [1, -2, 1, -2], [-4, 9, -4, 2]] P2 = [[-5, 6, 0, -5], [-6, 5, -2, 5], [1, -2, 1, -2], [-4, 9, -4, 2], [0, -8, -8, 1]] P3 = [-5, 6, 0, -5], [-6, 5, -2, 5], [1, -2, 1, -2]]
P1 and P3 are constructed the same way: P1mask = (P[:, 0:1] == P[:, 1:]).any(axis=1) P3mask = (P[:, -1:] == P[:, :-1]).any(axis=1) P1 = P[P1mask, :] P3 = P[P3mask, :] The only really interesting thing here is that I'm indexing the columns as slices 0:1 and -1: instead of just 0 and -1 to preserve shape and enable broadcasting. P2 can be constructed in a similar manner, although the solution is not very general: P2mask = (P[:, 0:1] == P[:, 2:]).any(axis=1) | (P[:, 1:2] == P[:, 2:]).any(axis=1) P2 = P[P2mask, :] A more general solution would be to broadcast the two segments together with a new dimension so that the comparison done with | manually above can be automated: split = 2 P2mask = (P[:, :split, None] == P[:, None, split:]).any(axis=(1, 2)) P2 = P[P2mask, :] P1 and P3 are just the cases for split = 1 and split = 3, respectively.
You want to select all rows that fulfill a given condition, so you need to iterate over the rows of P, build a boolean array and apply it to the rows of P. In your case, the easiest way I can think of to check if there are shared elements, is to create two sets and check if their intersection is empty or not. This can be done via set.isdisjoint. Final code: P1 = P[[not set(row[:1]).isdisjoint(row[1:]) for row in P], :] Analogous for P2 and P3.
Subtract a different number from each column in an array
Assuming I have the following array in Python: x = np.array(([1,2,3,4],[5,6,7,8],[9,10,11,12])) x Which looks like: array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) I have an array mu, which is the mean of each of the columns of array x mu = x.mean(axis =0) Which looks like: array([5., 6., 7., 8.]) Now, I want a new array x_demean, where the first column gets subtracted by its own mean, second column by its own mean, and so one. The result should look like: array([[ -4, -4, -4, -4], [ 0, 0, 0, 0], [ 4, 4, 4, 4])
x-mu is all you need to get what you want. If you want output strictly as integers, do (x-mu).astype(int) Output array([[-4, -4, -4, -4], [ 0, 0, 0, 0], [ 4, 4, 4, 4]])
You can use simple x - mu which provides the desired output. You can use the proper subtract() method of numpy also. Refer the docs here. Try this code: import numpy as np x1 = np.array(([1,2,3,4],[5,6,7,8],[9,10,11,12])) mu = x1.mean(axis =0) x_demean = np.subtract(x1, mu) print(x_demean) #use x_demean.astype(int) if you want integer array
Evaluate a RegularGridInterpolator on an another regular grid
I'm having trouble understanding how to shape data to evaluate an interpolated view of an nD-array, using scipy.interpolate.RegularGridInterpolator Considering A a (n1,n2,n3)-shaped numpy array, indexed along the following coordinates : x = np.linspace(0, 10, 5) # n1 = 5 y = np.linspace(-1, 1, 10) # n2 = 10 z = np.linspace(0, 500, 1000) # n3 = 1000 For this example, you can generate A = ex_array with this bit of code from the documentation : def f(x,y,z): return 2 * x**3 + 3 * y**2 - z ex_array = f(*np.meshgrid(x, y, z, indexing='ij', sparse=True)) Let's imagine I want to interpolate the entire array along each axis. This is done with : from scipy.interpolate import RegularGridInterpolator interpolated = RegularGridInterpolator((x,y,z), ex_array) Now, the part where my brain starts to hurt hard : In order to evaluate this interpolator object at any given coordinates, you have to __call__ it on said point like so : evaluated_pts = interpolated((0,1,0)) # evaluate at (x,y,z) = (5,0.5,300) print(evaluated_pts) In order to evaluate it on several points, you can iterate like this : pts = ((5,0.5,_z) for _z in np.linspace(100,200,50)) evaluated_pts = interpolated(pts) Now, what if I want to use the same logic as above, and evaluate on an entire new grid, such as : new_x = np.linspace(2, 3, 128) new_y = np.linspace(-0.1, 0.1, 100) new_z = np.linspace(350, 400, 256) As you can see now, it's not as straightforward as interpolated(new_x, new_y, new_z), and I tried to use np.meshgrid but could not figure it out. Ideally, I'd want to output a new (128, 100, 256) array in this example.
RegularGridInterpolator input values are located on a grid. The grid points are defined using a tuple of "ticks" along each axis, for instance ((x0, x1, ..., xn), (y0, y1, ..., xm), (z0, z1, ..., zk) ) in 3D. The values are given as an nd-array of shape (n, m, k) in this case. To evaluate the interpolated function, the assumption that the points are on a grid is no more required. Then, the asked points are defined as a list of points (actually an array of coordinates): ((x1, y1, z1), (x2, y2, z2), ... (xP, yP, zP)) i.e. a nd-array of shape (Number of points, Number of dimension). To evaluate the interpolation on a new grid, it must be constructed using meshgrid. reshape and transpose are used to transform arrays from one shape to another (see this question). For example: x = [0, 1, 2] y = [3, 4] z = [5, 6, 7, 8] xyz_grid = np.meshgrid(x, y, z, indexing='ij') xyz_list = np.reshape(xyz_grid, (3, -1), order='C').T xyz_list ̀xyz_list could be used to call the interpolation function and it looks like that: array([[0, 3, 5], [0, 3, 6], [0, 3, 7], [0, 3, 8], [0, 4, 5], [0, 4, 6], [0, 4, 7], [0, 4, 8], [1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 3, 8], [1, 4, 5], [1, 4, 6], [1, 4, 7], [1, 4, 8], [2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 3, 8], [2, 4, 5], [2, 4, 6], [2, 4, 7], [2, 4, 8]])
Making an array from multiple elements from different arrays
I want to make a new array out of different numbers from each array. This is an example: import numpy as np a=[[0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10],[0,1,2,3,4,5,6,7,8,9,10]] b=[[0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10],[0,1,2,3,4,5,6,7,8,9,10]] c=[[0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10],[0,1,2,3,4,5,6,7,8,9,10]] d=[] for c in range (0,2): d.append([]) for s in range (0,10): d[c] =np.concatenate((a[c][s],b[c][s],c[c][s])) print(d) when I print 'd', it gives me a TypeError: 'int' object is not subscriptable. Is this due to the concatenante function? or can I use stack? I want the outcome to be something like: d[0][0]= [0,0,0] having the first term from each array. d[0][0] is indexing to a file and a row. that's why I want this format.
Numpy is an incredibly powerful library so I would recommend always using it to manipulate your arrays first before you use for loops. You should look up what numpy axes and shapes mean. The array d that you want seems to be 3D, but the arrays a, b and c are 2D. Therefore we will first expand the dimensons of the three arrays. Then we can easily concatenate them on this new dimension. The following code achieves what you want: import numpy as np # First convert the lists themselves to numpy arrays. a = np.array([[0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]) # Shape: (2, 11) b = np.array([[0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]) # Shape: (2, 11) c = np.array([[0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]) # Shape: (2, 11) # Print the shape of the arrays print(a.shape, b.shape, c.shape) # Add an additional dimension to the three arrays along a new axis. # axis 0 and axis 1 already exist. So we create it along axis 2. a_ = np.expand_dims(a, axis=2) # Shape: (2, 11, 1) b_ = np.expand_dims(b, axis=2) # Shape: (2, 11, 1) c_ = np.expand_dims(c, axis=2) # Shape: (2, 11, 1) # Print the shape of the arrays print(a_.shape, b_.shape, c_.shape) # Concatenate all three arrays along the last axis i.e. axis 2. d = np.concatenate((a_, b_, c_), axis=2) # Shape: (2, 11, 3) # Print d[0][0] to check if it is [0, 0, 0] print(d[0][0]) You should print the individual arrays a, a_ and d to check what kind of transformations are taking place.
How to plot a 2D figure form a 4D array
I want to plot a 2D figure which is a plane-cut from a 4D array. for example: In[1]: x = [0, 1, 2] y = [3, 4, 5] z = [6, 7, 8] f = [9, 10, 11] X, Y, Z, F = meshgrid(x, y, z, f) #create 4D grid Out[1]: array([[[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2]]], [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2]]], [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2]]]]) In[2]: A = X + 1j*Y + Z + 1j* F Out[2]: array([[[[ 6.+12.j, 6.+13.j, 6.+14.j], [ 7.+12.j, 7.+13.j, 7.+14.j], [ 8.+12.j, 8.+13.j, 8.+14.j]], [[ 7.+12.j, 7.+13.j, 7.+14.j], [ 8.+12.j, 8.+13.j, 8.+14.j], [ 9.+12.j, 9.+13.j, 9.+14.j]], [[ 8.+12.j, 8.+13.j, 8.+14.j], [ 9.+12.j, 9.+13.j, 9.+14.j], [ 10.+12.j, 10.+13.j, 10.+14.j]]], [[[ 6.+13.j, 6.+14.j, 6.+15.j], [ 7.+13.j, 7.+14.j, 7.+15.j], [ 8.+13.j, 8.+14.j, 8.+15.j]], [[ 7.+13.j, 7.+14.j, 7.+15.j], [ 8.+13.j, 8.+14.j, 8.+15.j], [ 9.+13.j, 9.+14.j, 9.+15.j]], [[ 8.+13.j, 8.+14.j, 8.+15.j], [ 9.+13.j, 9.+14.j, 9.+15.j], [ 10.+13.j, 10.+14.j, 10.+15.j]]], [[[ 6.+14.j, 6.+15.j, 6.+16.j], [ 7.+14.j, 7.+15.j, 7.+16.j], [ 8.+14.j, 8.+15.j, 8.+16.j]], [[ 7.+14.j, 7.+15.j, 7.+16.j], [ 8.+14.j, 8.+15.j, 8.+16.j], [ 9.+14.j, 9.+15.j, 9.+16.j]], [[ 8.+14.j, 8.+15.j, 8.+16.j], [ 9.+14.j, 9.+15.j, 9.+16.j], [ 10.+14.j, 10.+15.j, 10.+16.j]]]]) Now the shape of A is (3, 3, 3, 3) Now my question is how to plot 2D figure from this 4D array which is (Y=0 and F = 0), and is this the right way to plot a plane-cut from a 4D figure?
A plane cut with the shape n x m from a spacial figure in 3D grids (surf plot) may be plotted using matplotlib.pyplot.imshow. If it is not a surf plot, however, you may use plot, but you have to calculate the contour of your figure from the desired dimensions. from matplotlib.pyplot import imshow, show imshow(variable, interpolation='none') show() The shape may also adjusted as follows: # Given |variable| is an object of type numpy.array: var_reshaped = variable.reshape(int(variable.size/2), -1) This creates a square-shaped output from the data. You should be vigilant when reshaping an array to ensure that the integrity of the shape is not compromised. That is, you must make sure m x n of your reshaped array is identical to the two dimensions you're extracting your plane from (any double combination of x, y or z). Also, you cannot take a plane directly from 4D. You must extract a 3D array first, and then a 2D one. For instance, imagine an MRI with 10 exposures (4D: 10 x 50 x 50 x 50). You must first extract one exposure (3D: 50 x 50 x 50), and then attempt to display that a slice (2D: 50 x 50).