vampiretap
vampiretap

Reputation: 361

How to give float indexes to numpy ndarray?

In a time series data, I have (x,y) coordinates for an object that evolve over a 2-D grid. For example:

(41.797, 34.0),
(42.152, 34.56),
(42.383, 36.07),
(42.505, 37.97)

How do I index the array in a way that array[x,y]=object_id. Subsequently, I'd need to go through this time-indexed 2-D grid again, and index array[x',y']=object_id_2. Where x' and y' are like a list above.

Upvotes: 2

Views: 3384

Answers (2)

Mr Squid
Mr Squid

Reputation: 1296

It is possible to index a numpy array using floating point indices, you just need to interpolate between values. Here is code that will do that, using bilinear interpolation (taken from this gist)

def subsample_image(coords, img):
    """
    Given a list of floating point coordinates (Nx2) in the image,
    return the pixel value at each location using bilinear interpolation.
    """
    if len(img.shape) == 2:
        img = np.expand_dims(img, 2)
    xs, ys = coords[:, 0], coords[:, 1]
    pxs = np.floor(xs).astype(int)
    pys = np.floor(ys).astype(int)
    dxs = xs-pxs
    dys = ys-pys
    wxs, wys = 1.0-dxs, 1.0-dys
    
    weights =  np.multiply(img[pys, pxs, :].T      , wxs*wys).T
    weights += np.multiply(img[pys, pxs+1, :].T    , dxs*wys).T
    weights += np.multiply(img[pys+1, pxs, :].T    , wxs*dys).T
    weights += np.multiply(img[pys+1, pxs+1, :].T  , dxs*dys).T
    return weights

Upvotes: 2

OHHH
OHHH

Reputation: 1051

There are a few problems here.

First, you can't index by floats because it doesn't make any sense. Second, if you could, there is a problem with the way floats are interpreted/calculated (the reason why sometimes your results are like 3.99999999 instead of 4).

My recommendation is to index your values using a dictionary rounded to a certain number of decimals. This way you will ensure your data always matches!

Since you cannot map stuff by immutable keys, you need a tuple.

An example of how this would work:

mydict = {}

a = (41.797, 34.0)
object_a = 'A'
b = (42.152, 34.56)
object_b 'B'

mydict[round(a[0], 3), round(a[1], 3)] = object_a
mydict[round(b[0], 3), round(b[1], 3)] = object_b

print ( my_dict[round(a[0], 3), round(a[1], 3)] )
print ( my_dict[round(b[0], 3), round(b[1], 3)] )

>> 'A'
>> 'B'

If you want to update the object you simply use the rounded tuple

mydict[round(a[0], 3), round(a[1], 3)] = 'CHICKEN'


print ( my_dict[round(a[0], 3), round(a[1], 3)] )
print ( my_dict[round(b[0], 3), round(b[1], 3)] )

>> 'CHICKEN'
>> 'B'

If the code gets too messy, just add a function to round tuples:

def round_tuple(tupl, decimals=3):
    return round(tupl[0], decimals), round(tupl[1], decimals)

This way you just do this:
target = round_tuple(tup)
mydict[target] = 'CHICKEN'

Upvotes: 1

Related Questions