上一个问题的答案“使用cartopy检查地理坐标点是陆地还是海洋”请参阅https://stackoverflow.com/questions/asktitle=Checking%20if%20a%20geocoordinate%20point%20is%20land%20or%20ocean%20using%20cartopy%20and%20Natural%20Earth%2010m%20data建议使用以下代码确定地理坐标“is_land”:
import cartopy.io.shapereader as shpreader
import shapely.geometry as sgeom
from shapely.ops import unary_union
from shapely.prepared import prep
land_shp_fname = shpreader.natural_earth(resolution='50m',
category='physical', name='land')
land_geom =
unary_union(list(shpreader.Reader(land_shp_fname).geometries()))
land = prep(land_geom)
def is_land(x, y):
return land.contains(sgeom.Point(x, y))
当自然地球“物理”“地”shapefile的分辨率更改为“10m”时,此代码将返回地理坐标(0,0)的“True”意外结果。
>>> print(is_land(0, 0))
True
这是自然地球形状文件数据或形状实用程序代码的问题吗?
print shapely.__version__
1.6.4.post1
好奇。我肯定已经看到了unary_union
产生无效几何形状的情况。在这种情况下运行land_geom.is_valid
会花费大量时间,但确实表明它是一个有效的几何体。如果有疑问,GEOS / Shapely的常见技巧是缓冲0,这通常会导致改进的几何体表示我们之前以改进形式存在的几何体。这样做也声称产生有效的几何。
不幸的是,结果仍然是......查询继续报告有0,0的土地......
在这一点上,我有点失落。如果有疑问,总是值得一看数据。为了理智,我检查了Google maps to confirm that there is definitely no land at 0, 0。接下来,我使用以下代码查看了我们生成的几何体:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
ax = plt.subplot(1, 2, 1, projection=ccrs.PlateCarree())
ax.add_geometries([b], ccrs.PlateCarree(), facecolor='green', edgecolor='none')
ax = plt.subplot(1, 2, 2, projection=ccrs.PlateCarree())
ax.add_geometries([b], ccrs.PlateCarree(), facecolor='green', edgecolor='none')
box_size = 5e-2
ax.set_extent([-box_size, box_size, -box_size, box_size])
ax.xaxis.set_visible(True)
ax.yaxis.set_visible(True)
看哪,看起来有一块约1平方公里的完美方形土地,正好位于0,0!阴谋理论家会高兴地认为,这可能是主流媒体用于对外星人进行军事研究和猫王之家的一块真正的土地,但我怀疑更平常的答案是数据中存在一个错误(或者可能在读取数据的工具中。
接下来,我使用fiona进行了快速调查,看看它是否也加载了给定区域的几何:
import fiona
c = fiona.open(land_shp_fname)
hits = list(c.items(bbox=(-0.01, -0.01, 0.01, 0.01)))
len(hits)
hits
结果是明确的......这里确实存在一个几何体,它甚至比图中暗示的要小(可能是由于缓冲区的浮点容差?):
[(9,
{'type': 'Feature',
'id': '9',
'geometry': {'type': 'Polygon',
'coordinates': [[(-0.004789435546374336, -0.004389928165484299),
(-0.004789435546374336, 0.00481690381926197),
(0.004328009720073429, 0.00481690381926197),
(0.004328009720073429, -0.004389928165484299),
(-0.004789435546374336, -0.004389928165484299)]]},
'properties': OrderedDict([('featurecla', 'Null island'),
('scalerank', 100),
('min_zoom', 100.0)])})]
快速搜索这个地方“Null Island”的名字,令我惊恐的是,这是一个故意的数据怪癖...... https://en.wikipedia.org/wiki/Null_Island和https://blogs.loc.gov/maps/2016/04/the-geographical-oddity-of-null-island/详细介绍了Null Island从深处(实际上近5000米)的崛起。
那么我们还有什么可以接受这个怪癖并承认0,0的土地呢?好吧,我们可以尝试过滤掉它......
所以拿你的代码,并调整一点:
land_shp_fname = shpreader.natural_earth(
resolution='10m', category='physical', name='land')
land_geom = unary_union(
[record.geometry
for record in shpreader.Reader(land_shp_fname).records()
if record.attributes.get('featurecla') != "Null island"])
land = prep(land_geom)
def is_land(x, y):
return land.contains(sgeom.Point(x, y))
我们最终得到一个功能,以1:10,000,000比例(10米)评估自然地球数据集,以确定一个点是海洋还是陆地,而不考虑来自自然地球数据集的零岛怪。
>>> print(is_land(0, 0))
False
Null Island已被添加为故障排除国家/地区。
http://www.naturalearthdata.com/blog/natural-earth-version-1-3-release-notes/