0

I am new to python, and I can't figure out how to find the minimum distance from a given lat/lon point (which is not given from the grid, but selected by me) to a find the closest indices of a lat/lon point on a grid.

Basically , I am reading in an ncfile that contains 2D coordinates:

coords = 'coords.nc'
fh = Dataset(coords,mode='r')
lons = fh.variables['latitudes'][:,:]
lats = fh.variables['longitudes'][:,:]
fh.close()

>>> lons.shape
(94, 83)
>>> lats.shape
(94, 83)

I want to find the indices in the above grid for the nearest lat lon to the below values:

sel_lat=71.60556
sel_lon=-161.458611

I tried to make lat/lon pairs in order to use the scipy.spatial.distance function, but I still am having problems because I did not set up the input arrays to the format it wants, but I don't understand how to do that:

latLon_pairsGrid = np.vstack(([lats.T],[lons.T])).T

>>> latLon_pairsGrid.shape
(94, 83, 2)

distance.cdist([sel_lat,sel_lon],latLon_pairsGrid,'euclidean')

Any help or hints would be appreciated

8
  • 1
    show us what lons and lats look like and what are their types. Even better: gives us an example that we can run in our computers and the expected output. Commented Oct 12, 2016 at 23:10
  • @cd98 I'm not sure what you mean by an example, but maybe I wasn't clear enough in my question. The sel_lat, sel_lon values are given above, and those are the coordinates I need to find the nearest corresponding indices for on the grid from the 'coords.nc' file. The lons.shape = (93,83) and same with the lats.shape. And so that means the latLon_pairsGrid I made is a (93,83,2). I hope this is clear enough, I'm not sure what else to add Commented Oct 12, 2016 at 23:28
  • "does not have the format it wants" can you print the error please Commented Oct 12, 2016 at 23:36
  • also can you try to do lats.T.as_matrix() and lons.T.as_matrix() to your arrays inside of the np.vstack to convert them to pure numpy arrays instead of pandas stuff Commented Oct 12, 2016 at 23:38
  • @Julius I'm not using pandas, when I do lats.T.as_matrix() it gives the error ` >>> lats.T.as_matrix() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'numpy.ndarray' object has no attribute 'as_matrix' ` For the error received in the distance.cdist command in the last line of my question it returns: ` 2027, in cdist raise ValueError('XA must be a 2-dimensional array.') ` Commented Oct 12, 2016 at 23:49

2 Answers 2

3

Checkout the pyresample package. It provides spatial nearest neighbour search using a fast kdtree approach:

import pyresample
import numpy as np

# Define lat-lon grid
lon = np.linspace(30, 40, 100)
lat = np.linspace(10, 20, 100)
lon_grid, lat_grid = np.meshgrid(lon, lat)
grid = pyresample.geometry.GridDefinition(lats=lat_grid, lons=lon_grid)

# Generate some random data on the grid
data_grid = np.random.rand(lon_grid.shape[0], lon_grid.shape[1])

# Define some sample points
my_lons = np.array([34.5, 36.5, 38.5])
my_lats = np.array([12.0, 14.0, 16.0])
swath = pyresample.geometry.SwathDefinition(lons=my_lons, lats=my_lats)

# Determine nearest (w.r.t. great circle distance) neighbour in the grid.
_, _, index_array, distance_array = pyresample.kd_tree.get_neighbour_info(
    source_geo_def=grid, target_geo_def=swath, radius_of_influence=50000,
    neighbours=1)

# get_neighbour_info() returns indices in the flattened lat/lon grid. Compute
# the 2D grid indices:
index_array_2d = np.unravel_index(index_array, grid.shape)

print "Indices of nearest neighbours:", index_array_2d
print "Longitude of nearest neighbours:", lon_grid[index_array_2d]
print "Latitude of nearest neighbours:", lat_grid[index_array_2d]
print "Great Circle Distance:", distance_array

There is also a shorthand method for directly obtaining the data values at the nearest grid points:

data_swath = pyresample.kd_tree.resample_nearest(
    source_geo_def=grid, target_geo_def=swath, data=data_grid,
    radius_of_influence=50000)
print "Data at nearest grid points:", data_swath
Sign up to request clarification or add additional context in comments.

Comments

1

I think I found an answer, but it is a workaround that avoids calculating distance between the chosen lat/lon and the lat/lons on the grid. This doesn't seem completely accurate because I am never calculating distances, just the closest difference between lat/lon values themselves.

I used the answer to the question find (i,j) location of closest (long,lat) values in a 2D array

a = abs(lats-sel_lat)+abs(lons-sel_lon)
i,j = np.unravel_index(a.argmin(),a.shape)

Using those returned indices i,j, I can then find on the grid the coordinates that correspond most closely to my selected lat, lon value:

>>> lats[i,j]
71.490295
>>> lons[i,j]
-161.65045

1 Comment

You're minimizing an L1 metric, also called Manhattan distance, which is not totally unreasonable and cheaper to compute than the usual L2 metric a=sqrt(dx**2+dy**2). And like you said, you're computing distance in the lat/lon domain, not geodesic or Cartesian distances, which would require coordinate transformations. If you're going to query multiple points and speed is an issue, definitely check out @Funkensieper's answer or other tree-based approaches.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.