Hilemonstoer
Hilemonstoer

Reputation: 1447

Is there a multi-dimensional version of arange/linspace in numpy?

I would like a list of 2d NumPy arrays (x,y) , where each x is in {-5, -4.5, -4, -3.5, ..., 3.5, 4, 4.5, 5} and the same for y.

I could do

x = np.arange(-5, 5.1, 0.5)
y = np.arange(-5, 5.1, 0.5)

and then iterate through all possible pairs, but I'm sure there's a nicer way...

I would like something back that looks like:

[[-5, -5],
 [-5, -4.5],
 [-5, -4],
 ...
 [5, 5]]

but the order does not matter.

Upvotes: 127

Views: 154811

Answers (13)

Shreyash Kashyap
Shreyash Kashyap

Reputation: 93

You can try in the following manner:

import numpy as np
arr = np.reshape(np.arange(10), (2,5))
print(arr)

Here, 10 is the range of numbers you want to include (with 10 being exclusive) and (2,5) being the number of rows and columns of the 2D matrix.

Upvotes: 0

Dan Boschen
Dan Boschen

Reputation: 312

You can take advantage of Numpy's broadcasting rules to create grids simply. For example here is what I do when I want to do the equivalent of np.reshape (which is another fine option) on a linear array counting from 1 to 24:

row = np.array([1,2,3,4,5,6])
col = np.array([0,6,12,18])
grid = col[:, None] +row[None, :]

The result is:

array([[ 1,  2,  3,  4,  5,  6],
       [ 7,  8,  9, 10, 11, 12],
       [13, 14, 15, 16, 17, 18],
       [19, 20, 21, 22, 23, 24]])

Note np.newaxis is an alias for None and is used to expand the dimension of an Numpy array. Many prefer np.newaxis instead of None as I have used for its readability.

Here I used a sum to combine the grid, so it will be the row plus the first column element to make the first row in the result, then the same row plus the second column element to make the second row in the result etc. Other arithmetic operations can be used for any grid desired when the contents are based on two arrays like this.

As described, the above is identical to the result returned by reshape as given below, but the broadcasting option provides greater flexibility for other options so is worth noting.

np.reshape(np.arange(1,25),(4,6))

Upvotes: 1

leo
leo

Reputation: 106

Here's my solution for creating coordinate grids from arrays using only numpy (I had to come up with a solution that works with vmap in jax):

def grid(*args):
  return np.stack(np.meshgrid(*args, indexing='ij'), axis=-1)

Now grid([1,2,3], [4,5,6]) will give you:

array([[[1, 4],
        [1, 5],
        [1, 6]],

       [[2, 4],
        [2, 5],
        [2, 6]],

       [[3, 4],
        [3, 5],
        [3, 6]]])

You can combine this with linspace as follows to get 2D coordinate grids:

def lingrid(x_start, x_stop, x_steps, y_start, y_stop, y_steps):
  a = np.linspace(x_start, x_stop, x_steps)
  b = np.linspace(y_start, y_stop, y_steps)
  return grid(a, b)

E.g., lingrid(0, 1, 3, 0, 2, 3) gives you:

array([[[0. , 0. ],
        [0. , 1. ],
        [0. , 2. ]],

       [[0.5, 0. ],
        [0.5, 1. ],
        [0.5, 2. ]],

       [[1. , 0. ],
        [1. , 1. ],
        [1. , 2. ]]])

Upvotes: 0

liedji
liedji

Reputation: 789

This is an elegant way of doing it:

xy = [(i,j) for i in np.linspace(1,4,4) for j in np.linspace(0,2,3)]

Here is the print(xy) output:

[(1.0, 0.0),
 (1.0, 1.0),
 (1.0, 2.0),
 (2.0, 0.0),
 (2.0, 1.0),
 (2.0, 2.0),
 (3.0, 0.0),
 (3.0, 1.0),
 (3.0, 2.0),
 (4.0, 0.0),
 (4.0, 1.0),
 (4.0, 2.0)]

Upvotes: 3

momo668
momo668

Reputation: 443

I still did it with Linspace because I prefer to stick to this command.

You can create like the following format: np.linspace(np.zeros(width)[0], np.full((1,width),-1)[0], height)

np.linspace(np.zeros(5)[0],np.full((1,5),-1)[0],5)

Output the following:

array([[ 0.  ,  0.  ,  0.  ,  0.  ,  0.  ],
       [-0.25, -0.25, -0.25, -0.25, -0.25],
       [-0.5 , -0.5 , -0.5 , -0.5 , -0.5 ],
       [-0.75, -0.75, -0.75, -0.75, -0.75],
       [-1.  , -1.  , -1.  , -1.  , -1.  ]])

Add .tranpose() then you get:

array([[ 0.  , -0.25, -0.5 , -0.75, -1.  ],
      [ 0.  , -0.25, -0.5 , -0.75, -1.  ],
      [ 0.  , -0.25, -0.5 , -0.75, -1.  ],
      [ 0.  , -0.25, -0.5 , -0.75, -1.  ],
      [ 0.  , -0.25, -0.5 , -0.75, -1.  ]])

Upvotes: 2

cb1986ster
cb1986ster

Reputation: 9

It is not super fast solution, but works for any dimension

import numpy as np
def linspace_md(v_min,v_max,dim,num):
    output = np.empty( (num**dim,dim)  )
    values = np.linspace(v_min,v_max,num)
    for i in range(output.shape[0]):
        for d in range(dim):
            output[i][d] = values[( i//(dim**d) )%num]
    return output

Upvotes: 0

farenorth
farenorth

Reputation: 10781

You can use np.mgrid for this, it's often more convenient than np.meshgrid because it creates the arrays in one step:

import numpy as np
X,Y = np.mgrid[-5:5.1:0.5, -5:5.1:0.5]

For linspace-like functionality, replace the step (i.e. 0.5) with a complex number whose magnitude specifies the number of points you want in the series. Using this syntax, the same arrays as above are specified as:

X, Y = np.mgrid[-5:5:21j, -5:5:21j]

You can then create your pairs as:

xy = np.vstack((X.flatten(), Y.flatten())).T

As @ali_m suggested, this can all be done in one line:

xy = np.mgrid[-5:5.1:0.5, -5:5.1:0.5].reshape(2,-1).T

Best of luck!

Upvotes: 115

Fırat Korkmaz
Fırat Korkmaz

Reputation: 533

This is just what you are looking for:

matr = np.linspace((1,2),(10,20),10)

This means:

For the first column; from 1 of (1,2) to 10 of (10,20), put the increasing 10 numbers.

For the second column; from 2 of (1,2) to 20 of (10,20), put the incresing 10 numbers.

And the result will be:

[[ 1.  2.]
 [ 2.  4.]
 [ 3.  6.]
 [ 4.  8.]
 [ 5. 10.]
 [ 6. 12.]
 [ 7. 14.]
 [ 8. 16.]
 [ 9. 18.]
 [10. 20.]]

You may also keep only one column's values increasing, for example, if you say that:

matr = np.linspace((1,2),(1,20),10)

The first column will be from 1 of (1,2) to 1 of (1,20) for 10 times which means that it will stay as 1 and the result will be:

[[ 1.  2.]
 [ 1.  4.]
 [ 1.  6.]
 [ 1.  8.]
 [ 1. 10.]
 [ 1. 12.]
 [ 1. 14.]
 [ 1. 16.]
 [ 1. 18.]
 [ 1. 20.]]

Upvotes: 50

Martin
Martin

Reputation: 3385

Based on this example, you can make any dim you want

def linspace3D(point1,point2,length):
    v1 = np.linspace(point1[0],point2[0],length)
    v2 = np.linspace(point1[1],point2[1],length)
    v3 = np.linspace(point1[2],point2[2],length)
    line = np.zeros(shape=[length,3])
    line[:,0]=v1
    line[:,1]=v2
    line[:,2]=v3
    return line

Upvotes: -1

Pranav Joshi
Pranav Joshi

Reputation: 157

We can use arrange function as:

z1 = np.array([np.array(np.arange(1,5)),np.array(np.arange(1,5))])
print(z1)
o/p=> [[1 2 3 4]
       [1 2 3 4]]

Upvotes: 5

chthonicdaemon
chthonicdaemon

Reputation: 19810

If you just want to iterate through pairs (and not do calculations on the whole set of points at once), you may be best served by itertools.product to iterate through all possible pairs:

import itertools

for (xi, yi) in itertools.product(x, y):
    print(xi, yi)

This avoids generating large matrices via meshgrid.

Upvotes: 8

uhoh
uhoh

Reputation: 3745

Not sure if I understand the question - to make a list of 2-element NumPy arrays, this works:

import numpy as np
x = np.arange(-5, 5.1, 0.5)
X, Y = np.meshgrid(x, x)
Liszt = [np.array(thing) for thing in zip(X.flatten(), Y.flatten())] # for python 2.7

zip gives you a list of tuples, and the list comprehension does the rest.

Upvotes: 1

tmdavison
tmdavison

Reputation: 69173

I think you want 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.

import numpy as np
x = np.arange(-5, 5.1, 0.5)
y = np.arange(-5, 5.1, 0.5)
X,Y = np.meshgrid(x,y)

you can convert that to your desired output with

XY=np.array([X.flatten(),Y.flatten()]).T

print XY
array([[-5. , -5. ],
       [-4.5, -5. ],
       [-4. , -5. ],
       [-3.5, -5. ],
       [-3. , -5. ],
       [-2.5, -5. ],
       ....
       [ 3. ,  5. ],
       [ 3.5,  5. ],
       [ 4. ,  5. ],
       [ 4.5,  5. ],
       [ 5. ,  5. ]])

Upvotes: 20

Related Questions