【问题标题】:Find nearest location coordinates in Land using python使用python查找Land中最近的位置坐标
【发布时间】:2020-01-14 15:15:45
【问题描述】:

地理编码 API 不返回海洋坐标的位置信息。对于这些记录,我想找到具有有效位置信息的最近可能坐标(即最近的陆地坐标) 下面是通过坐标获取位置信息的代码

import requests    
request_url = "https://api.mapbox.com/geocoding/v5/mapbox.places/{0}%2C{1}.json?access_token={2}&types=country&limit=1".format(lng,lat,key)
response = requests.get(request_url)
output = response.json()

我不知道找到最近的位置。我也是 Python 新手

样本输出:

{'type': 'FeatureCollection',
 'query': [32.12, 54.21],
 'features': [{'id': 'country.10008046970720960',
   'type': 'Feature',
   'place_type': ['country'],
   'relevance': 1,
   'properties': {'short_code': 'ru', 'wikidata': 'Q159'},
   'text': 'Russia',
   'place_name': 'Russia',
   'bbox': [19.608673, 41.185353, 179.9, 81.961618],
   'center': [37.61667, 55.75],
   'geometry': {'type': 'Point', 'coordinates': [37.61667, 55.75]}}],
 'attribution': 'NOTICE: © 2020 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained. POI(s) provided by Foursquare.'}

坐标为海洋时的输出:

{'type': 'FeatureCollection',
 'query': [0, 0],
 'features': [],
 'attribution': 'NOTICE: © 2020 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained. POI(s) provided by Foursquare.'}

【问题讨论】:

  • 你能分享一下output的样子吗?

标签: python geocode


【解决方案1】:

使用Haversine Formula根据经纬度查找最近的点(例如城市)。

def dist_between_two_lat_lon(*args):
    from math import asin, cos, radians, sin, sqrt
    lat1, lat2, long1, long2 = map(radians, args)

    dist_lats = abs(lat2 - lat1) 
    dist_longs = abs(long2 - long1) 
    a = sin(dist_lats/2)**2 + cos(lat1) * cos(lat2) * sin(dist_longs/2)**2
    c = asin(sqrt(a)) * 2
    radius_earth = 6378 # the "Earth radius" R varies from 6356.752 km at the poles to 6378.137 km at the equator.
    return c * radius_earth

def find_closest_lat_lon(data, v):
    try:
        return min(data, key=lambda p: dist_between_two_lat_lon(v['lat'],p['lat'],v['lon'],p['lon']))
    except TypeError:
        print('Not a list or not a number.')
    
# city = {'lat_key': value, 'lon_key': value}  # type:dict()
new_york = {'lat': 40.712776, 'lon': -74.005974}
washington = {'lat': 47.751076,  'lon': -120.740135}
san_francisco = {'lat': 37.774929, 'lon': -122.419418}

city_list = [new_york, washington, san_francisco]

city_to_find = {'lat': 29.760427, 'lon': -95.369804}  # Houston
print(find_closest_lat_lon(city_list, city_to_find))

产量:

{'lat': 47.751076, 'lon': -120.740135}  # Corresponds to Washington

假设您从 mapbox 获得了四个 json 答案,并将它们保存在一个列表中:

json_answers = list()  # = []

json_answers.append({'type': 'FeatureCollection', 
'query': [32.12, 54.21],
'features': [{'id': 'country.10008046970720960',
'type': 'Feature',
'place_type': ['country'],
'relevance': 1,
'properties': {'short_code': 'ru', 'wikidata': 'Q159'},
'text': 'Russia',
'place_name': 'Russia',
'bbox': [19.608673, 41.185353, 179.9, 81.961618],
'center': [37.61667, 55.75],
'geometry': {'type': 'Point', 'coordinates': [37.61667, 55.75]}}],
'attribution': 'NOTICE: ...'})

# I changed only the 'coordinates' value for this example
json_answers.append({'type': 'FeatureCollection', 
'query': [32.12, 54.21],
'features': [{'id': 'country.10008046970720960',
'type': 'Feature',
'place_type': ['country'],
'relevance': 1,
'properties': {'short_code': 'ru', 'wikidata': 'Q159'},
'text': 'Russia',
'place_name': 'Russia',
'bbox': [19.608673, 41.185353, 179.9, 81.961618],
'center': [37.61667, 55.75],
'geometry': {'type': 'Point', 'coordinates': [38.21667, 56.15]}}],
'attribution': 'NOTICE: ...'})

# I changed only the 'coordinates' value for this example
json_answers.append({'type': 'FeatureCollection', 
'query': [32.12, 54.21],
'features': [{'id': 'country.10008046970720960',
'type': 'Feature',
'place_type': ['country'],
'relevance': 1,
'properties': {'short_code': 'ru', 'wikidata': 'Q159'},
'text': 'Russia',
'place_name': 'Russia',
'bbox': [19.608673, 41.185353, 179.9, 81.961618],
'center': [37.61667, 55.75],
'geometry': {'type': 'Point', 'coordinates': [33.21667, 51.15]}}],
'attribution': 'NOTICE: ...'})

# The last answer is "null"
json_answers.append({'type': 'FeatureCollection',
'query': [0, 0],
'features': [],
'attribution': 'NOTICE: ...'})

coord_list = []
for answer in json_answers:
    if answer['features']:  # check if ['features'] is not empty
        # I'm not sure if it's [lat, lon] or [lon, lat] (you can verify it on mapbox)
        print(f"Coordinates in [lat, lon]: {answer['features'][0]['geometry']['coordinates']}")
        lat = answer['features'][0]['geometry']['coordinates'][0]
        lon = answer['features'][0]['geometry']['coordinates'][1]

        temp_dict = {'lat': lat, 'lon': lon}
        coord_list.append(temp_dict)

print(f"coord_list = {coord_list}")

point_to_find = {'lat': 37.41667, 'lon': 55.05}  # Houston
print(f"point_to_find = {point_to_find}")
print(f"find_closest_lat_lon = {find_closest_lat_lon(coord_list, point_to_find)}")

产量:

{'lat': 47.751076, 'lon': -120.740135}
Coordinates in [lat, lon]: [37.61667, 55.75]
Coordinates in [lat, lon]: [38.21667, 56.15]
Coordinates in [lat, lon]: [33.21667, 51.15]

coord_list = [{'lat': 37.61667, 'lon': 55.75}, {'lat': 38.21667, 'lon': 56.15}, {'lat': 33.21667, 'lon': 51.15}]

point_to_find = {'lat': 37.41667, 'lon': 55.05}

find_closest_lat_lon = {'lat': 38.21667, 'lon': 56.15}

【讨论】:

  • 谢谢拉斐尔,这看起来不错。我想为此我们需要列出所有主要城市及其坐标。但在我们的业务中,它可以是一个小镇或任何地方。当它的海洋/海洋时,json 响应中返回的特征为空。我想获得返回非零结果的最近坐标
  • 此功能适用于所有地球,您可以在mapbox的精度范围内搜索,如果是1m,则可以在1m精度范围内找到最近的距离。作为示例,我调用了函数 find_closest_city()。如果您在海洋的 JSON 中有null,请不要调用 find_closest_city()。您能否举例说明您要计算的两点和预期结果?
  • 假设 lat, lng = 50.677168, 0.305130 。这是英文频道。我们应该在 50.734998, 0.239263 Eastbourne, England 的某个地方获得最近的坐标
  • 那你有水中的坐标吗?我认为您需要在全球(或您想要的区域)进行扫描,首先保存所有水上和陆地上的坐标。我用更多示例更新了我的答案。我猜place_type 键会告诉你它是土地还是其他东西。逻辑很简单,但需要更多的数据来处理。
  • 感谢拉斐尔的回复。我正在寻找如何获取外套线的所有纬度、经度坐标的列表
【解决方案2】:

在 python 中使用reverse_geocode 库来获取与国家最近的城市。

例子:

import reverse_geocode

coordinates = (-37.81, 144.96), (31.76, 35.21)

reverse_geocode.search(coordinates)

结果:

[{'city': '墨尔本', 'code': 'AU', 'country': 'Australia'}, {'city': 'Jerusalem', 'code': 'IL', 'country': 'Israel'}]

【讨论】:

  • 我遇到错误coordinates = (-37.81, 144.96), (31.76, 35.21) reverse_geocode.search(coordinates) UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 429: character maps to
  • 我必须进去pypi.org/project/reverse-geocodepip3 install reverse-geocode
  • 加一个coordinates = (-37.81, 144.96),最后需要逗号,否则报错。
【解决方案3】:

这是一个未优化的解决方案。

函数的底层发生了什么:

  1. 对一个点运行GeoPy 反向查找。
  2. 如果找到该点,则返回其国家名称。
  3. 如果未找到该点,请在world_geometry 变量中搜索最近的陆地点。
  4. 对该最近点执行反向查找。
  5. 返回该点的国家名称(如果存在)或地区名称(如果没有国家名称)。
from geopy.geocoders import Nominatim
from shapely.ops import nearest_points

def country_lookup(query, geocoder, land_geometry):
    
    try:
        loc = geocoder.reverse((query.y, query.x))
        return loc.raw['address']['country']
    except (KeyError, AttributeError):
        _, p2 = nearest_points(query, land_geometry)
        loc = geocoder.reverse((p2.y, p2.x)).raw['address']
        if 'country' in loc.keys():
            return loc['country']
        else:
            return loc['locality']
        
# get world (or any land) geometry, instantiate geolocator service
world = gp.read_file(gp.datasets.get_path('naturalearth_lowres'))
world_geometry = world.geometry.unary_union
geolocator = Nominatim(user_agent="GIW")

# Create a column of country names from points in a GDF's geometry.
gdf['country'] = gdf.geometry.apply(country_lookup, args=(geolocator, world_geometry))

结果的准确性取决于您提供的土地几何形状的准确性。比如geopandas的世界几何就很不错了。除了巴哈马群岛中一些最小的岛屿之外,我能够找到所有国家的名称。那些它找不到的被函数标记为“百慕大三角”,这对我来说已经足够了。

【讨论】:

    【解决方案4】:

    要试用的不同包是 reverse_geocoder,它将返回最近的城市、州和国家。似乎比 reverse_geocode 包好。

    import reverse_geocoder as rg
    coordinates = (29,-84.1),(37,-125) #Both located in the ocean
    rg.search(coordinates) 
    

    输出:

    [OrderedDict([('lat', '29.67106'),
                  ('lon', '-83.38764'),
                  ('name', 'Steinhatchee'),
                  ('admin1', 'Florida'),
                  ('admin2', 'Taylor County'),
                  ('cc', 'US')]),
     OrderedDict([('lat', '38.71519'),
                  ('lon', '-123.45445'),
                  ('name', 'Sea Ranch'),
                  ('admin1', 'California'),
                  ('admin2', 'Sonoma County'),
                  ('cc', 'US')])]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-04
      • 2017-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      相关资源
      最近更新 更多