I want to create a grid of sampling points in 4 dimensions. I want the points to span from 0 to 10 with equal spacing in each direction. I tried a few iterations of np.mes
OK, so @QuangHoang's answer is:
QH = np.stack(np.meshgrid(*[x]*MD), axis=-1).reshape(-1, MD)
While yours is:
KJ = np.meshgrid(*[x for ____ in range(MD)])[0].reshape(MD, x.size ** MD // MD).T
What's the difference? Well for starters:
QH.shape
Out: (160000, 4)
KJ.shape
Out: (40000, 4)
You're missing some points. Exactly 1/4 of them, in fact. Why?
KJ = np.meshgrid(*[x for ____ in range(MD)])[0].reshape(MD, x.size ** MD // MD)
^^^
You calculate 4 arrays, but only use one of them. Let's look at that array:
grid_0 = np.meshgrid(*[x for ____ in range(MD)])[0]
grid_0
[[[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
...,
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ]],
[[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
...,
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579]],
[[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
...,
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158]],
...,
[[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
...,
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842]],
[[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
...,
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421]],
[[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
...,
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ]]],
...
[[[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
...,
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ]],
[[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
...,
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579],
[ 0.52631579, 0.52631579, 0.52631579, ..., 0.52631579,
0.52631579, 0.52631579]],
[[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
...,
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158],
[ 1.05263158, 1.05263158, 1.05263158, ..., 1.05263158,
1.05263158, 1.05263158]],
...,
[[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
...,
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842],
[ 8.94736842, 8.94736842, 8.94736842, ..., 8.94736842,
8.94736842, 8.94736842]],
[[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
...,
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421],
[ 9.47368421, 9.47368421, 9.47368421, ..., 9.47368421,
9.47368421, 9.47368421]],
[[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
...,
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ],
[10. , 10. , 10. , ..., 10. ,
10. , 10. ]]]]
And its shape:
grid_0.shape
Out: (20, 20, 20, 20)
Basically, it's a 20 x 20 x 20 cube filled with x[i]
for 0=<i<20.
I can't upload pictures from my current location, but this code will show the effect
import matplotlib.pyplot as plt
plt.plot(grid_0.flatten())
plt.plot(grid_0[0].flatten())
It's basically 20 sets of stairs, and the first set of stairs starts at 0 for the first 400 points. And ends with 10 for the last 100 points. This is why when you reshape it to:
grid_0.reshape(MD, x.size ** MD // MD).T
your first 100 points are [0,0,0,0] and your last 100 are [10, 10, 10 ,10]
In addition:
plt.plot(np.meshgrid(*[x for ____ in range(MD)])[-1][0,0].flatten())
plt.plot(np.meshgrid(*[x for ____ in range(MD)])[-2][0,0].flatten())
on a 2D scale it's easy to see that one dimension is moving stepwise while the other is moving continuously, creating the grid. By losing the 3 other dimesnions, you lose the grid and are left with stairs.
Now let's look at how you should have done it:
QH = np.stack(np.meshgrid(*[x]*MD), axis=-1).reshape(-1, MD)
Notice it doesn't use only the first dimension, but all of them.
By stacking those dimensions on the last axis you make sure every combination is in that axis (in this case it's the 5th dimension before reshaping). It's important to stack on the last axis becasue numpy
reshapes based on broadcasting rules - last dimension first. This way the last dimension is maintained through the reshape from (20,20,20,20,4) to (160000, 4).
meshgrid
returns the coordinates in the corresponding arrays. In your case for 4 dimensions:
xx, yy, zz, ww = np.meshgrid(x, y, z, w)
That means, xx
will contains all the x
coordinates while yy
all the y
coordinates and so on. Further more xx.shape == yy.shape == ...
and is equal to the number of points on the grid.
To get your desired result, might be stack
:
# point as rows
out = np.stack(np.meshgrid(*[x]*MD), axis=-1).reshape(-1, MD)
array([[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0.52631579],
[ 0. , 0. , 0. , 1.05263158],
...,
[10. , 10. , 10. , 8.94736842],
[10. , 10. , 10. , 9.47368421],
[10. , 10. , 10. , 10. ]])
# or point as columns
out = np.stack(np.meshgrid(*[x]*MD).reshape(MD, -1)
array([[ 0. , 0. , 0. , ..., 10. , 10. , 10. ],
[ 0. , 0. , 0. , ..., 10. , 10. , 10. ],
[ 0. , 0. , 0. , ..., 10. , 10. , 10. ],
[ 0. , 0.52631579, 1.05263158, ..., 8.94736842, 9.47368421, 10. ]])
It looks quite complitated to imagine what was done in Quang's answer so I decided to visualise these tricks in case x
consists of two points: