9

I am trying to map a straight line on a set of points in a grid. the data is in a list of x, y, z coordinates. I think map_coordinates is what i want, however i do not undestand the form of the inputs and outputs... any help would be much appreciated.

list = [[x1, y1, z1]
        [x2, y2, z2]
        ...
        [xn, yn, zn]]

the values I am trying to look up are x and y values.

look_up_values= [[x1, y1]
                 [x2, y2]
                 ...
                 [xn, yn]]

My question, why does map_coordinates expect a (2,2) array and what information is in the output ( a 2 value list).

here is a workable example:

from scipy.ndimage.interpolation import map_coordinates
import numpy as np
in_data = np.array([[0.,0.,0.]
                    ,[0.,1.,.2]
                    ,[0.,2.,.4]
                    ,[1.,0.,.2]
                    ,[1.,3.,.5]
                    ,[2.,2.,.7]])
z = map_coordinates(in_data, np.array([[1.,1.],[1.,2.]]), order=1)
print z #I do not understand this output...
#[1. .2]

if i had to guess i would say its interpolating between 2 points on the grid, buy what then would the output mean?

Yojimbo
  • 448
  • 1
  • 3
  • 10

4 Answers4

9

The output of map_coordinates is an interpolation of the value of the original array at the coordinates you've specified.

In your example you input [[1, 1], [1, 2]]. This means you want the interpolated value at two locations: the point x=1,y=1 and x=1,y=2. It needs two arrays because each array is the x- and y-coordinates. I.e. there are two coordinates you've asked for: x-coordinates at 1,1 and y-coordinates at 1,2.

The specific example you've chosen is a bit confusing because it looks like [1, 1] corresponds to [x0, y0] this interpretation is incorrect - it actually corresponds to [x0, x1]. This becomes clear with more than 2 points: The general format is [[x0, x1, x2, ...], [y0, y1, y2, ...]].

Your inputs can be as long or short as you like, but the arrays must be the same length since they are coupled.

joe
  • 3,752
  • 1
  • 32
  • 41
James
  • 437
  • 1
  • 6
  • 16
  • that makes sense to me, but what is the output saying? so i would expect it to give a z value or a x y z value if i understand correctly...but it seems to be xy? – Yojimbo Feb 13 '15 at 19:06
  • For 2D arrays, there's no "z" value, but if I understand you correctly you want the actual value of the array at the given coordinate. The output is correlated to the input array such that first element of the output is the value at the first input coordinates. You can use something like ``np.concatenate`` to create a [x,y,value] array. – James Feb 13 '15 at 19:26
  • 1
    Thanks man, i think that that map_coordinates did not do what i thought it did. so I went with griddata which is an interpolation function. thanks for spending the time on this for me. – Yojimbo Feb 16 '15 at 15:59
  • My pleasure. I use ``map_coordinates`` regularly, but it took me a while to figure out some of its subtleties too =) – James Feb 17 '15 at 16:08
  • 1
    *+1 Aha moment!* Your first sentence is exactly what I needed. Much easier for me to understand than "The array of coordinates is used to find, for each point in the output, the corresponding coordinates in the input." from [documentation](http://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.interpolation.map_coordinates.html). – uhoh Sep 24 '15 at 01:50
7

Let me try to answer first examining a step by step 1d interpolation case:

import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import numpy as np

### 1d example of interpolation ###

in_data_x = np.array([1., 2., 3., 4., 5., 6.])
in_data_y = np.array([1.5, 2., 2.5, 3.,  3.5,  4.])  # y = .5 x - 1
f = interp1d(in_data_x, in_data_y, kind='linear')

print(f)
# f in all of the points of the grid (in_data_x): output coincides with in_data_y

    
print(f(1), f(1.), f(1.5), f(2.), f(2.5), f(3.))
# f in a point outside the grid:
print(f(1.8))
# this is equal to y = .5 x - 1 for x = 1.8, up to some point.
assert round(0.5 * 1.8 + 1, ndigits=10) == round(f(1.8), ndigits=10)

# plot up to this point
xnew = np.arange(1, 6, 0.1)
ynew = f(xnew)
plt.plot(in_data_x, in_data_y, 'o', xnew, ynew, '-')
# close the image to move forward.
plt.show()

### another 1d example of interpolation ###

in_data_x = np.array([1., 2., 3., 4., 5., 6.])
in_data_y = np.array([-1.8, -1.2, -0.2, 1.2, 3., 5.2])  # y = .2 x**2 - 2
f = interp1d(in_data_x, in_data_y, kind='cubic')

print(f)
# f in all of the points of the grid (in_data_x): output coincides with in_data_y
print(f(1), f(1.), f(1.5), f(2.), f(2.5), f(3.))
# f in a point outside the grid:
print(f(1.8))
# this is equal to y = .2 x**2 - 2 for x = 1.8, up to some precision.
assert round(0.2 * 1.8 ** 2 - 2, ndigits=10) == round(f(1.8), ndigits=10)

# plot up to this point
xnew = np.arange(1, 6, 0.1)
ynew = f(xnew)
plt.plot(in_data_x, in_data_y, 'o', xnew, ynew, '-')
plt.show()

The function interp1d provides you an interpolator that gives you the value that interpolates with some kind of algorithm (in this case linear) the function passing through x = [1., 2., 3., 4., 5., 6.] y = [-1.8, -1.2, -0.2, 1.2, 3., 5.2].

map_coordinates does the same. When your data have more than one dimension. First main difference is that the results is not an interpolator, but it is an array. Second main difference is that the x coordinates are given by the matrix coordinates of the dimension of your data. Third difference is that the input must be given as a column vector. See this example

from scipy.ndimage.interpolation import map_coordinates
import numpy as np


in_data = np.array([[0., -1., 2.],
                    [2., 1., 0.],
                    [4., 3., 2.]])  # z = 2.*x - 1.*y

# want the second argument as a column vector (or a transposed row)
# see on some points of the grid:
print('at the point 0, 0 of the grid the function z is: ')
print(map_coordinates(in_data, np.array([[0., 0.]]).T, order=1))
print('at the point 0, 1 of the grid the function z is: ')
print(map_coordinates(in_data, np.array([[0., 1.]]).T, order=1))
print('at the point 0, 2 of the grid the function z is: ')
print(map_coordinates(in_data, np.array([[0., 2.]]).T, order=1))

# see some points outside the grid
print()
print('at the point 0.2, 0.2 of the grid, with linear interpolation z is:')
print(map_coordinates(in_data, np.array([[.2, .2]]).T, order=1))
print('and it coincides with 2.*.2 - .2')
print()
print('at the point 0.2, 0.2 of the grid, with cubic interpolation z is:')
print(map_coordinates(in_data, np.array([[0.2, .2]]).T, order=3)

Finally answering your question, you gave as input

in_data = np.array([[0., 0., 0.],
                    [0., 1., .2],
                    [0., 2., .4],
                    [1., 0., .2],
                    [1., 3., .5],
                    [2., 2., .7]])

That is a function z(x,y) computed on the grid given by the matrix coordinates: z(0, 0) = 0. z(2, 2) = .7 Asking

z = map_coordinates(in_data, np.array([[1., 1.], [1., 2.]]), order=1)

means asking z(1,1) and z(1,2), where the second input array is read by column.

z = map_coordinates(in_data, np.array([[.5, .5]]).T, order=1)

means asking z(0.5, 0.5). Note the transpose .T in the input. Hope it does make sense and it is helpful.

SeF
  • 3,864
  • 2
  • 28
  • 41
  • I have some difficulty understanding the coordinates. I would expect x,y,z to be the 0th, 1st and 2nd element in the rows. In the middle code block it is written the z= 2.*x-1.*y, but it does not match the third data. At the end it was written that z(2,2)=.4, but in_ata's last row is [2,2,.7]. – Horror Vacui Jun 26 '20 at 18:51
  • @HorrorVacui It is in fact a typo. Thanks for catching it. – SeF Jun 28 '20 at 22:14
0

x and y coordinates refer to vector indices.

So for col 2 and row 2 = z=2*2-2=-2 instead 2

Simas Joneliunas
  • 2,890
  • 20
  • 28
  • 35
0
in_data = np.array([[0., -1., -2.],
                [2., 1., 0.],
                [4., 3., 2.]])  # z = 2.*x - 1.*y

                                # z array's values 
                                # y = col 
                                # x = row  
# want the second argument as a column vector (or a transposed row)
# see on some points of the grid:

print('at the row 0 and col 0 of the grid the function z is: ')
print(ndimage.map_coordinates(in_data, np.array([[0., 0.]]).T, order=1,mode='nearest'))
print('at the row 0 and col 1 of the grid the function z is: ')
print(ndimage.map_coordinates(in_data, np.array([[0., 1.]]).T, order=1,mode='nearest'))