如何用Python在ESRI shapefile中根据特定经纬度查找信息?
我有一个ESRI的shapefile(可以在这里找到:http://pubs.usgs.gov/ds/425/)。我想用Python来查找在特定的经纬度下,这个shapefile里关于地表材料的信息。
解决这个问题的最佳方法是什么呢?
谢谢。
最终解决方案:
#!/usr/bin/python
from osgeo import ogr, osr
dataset = ogr.Open('./USGS_DS_425_SHAPES/Surficial_materials.shp')
layer = dataset.GetLayerByIndex(0)
layer.ResetReading()
# Location for New Orleans: 29.98 N, -90.25 E
point = ogr.CreateGeometryFromWkt("POINT(-90.25 29.98)")
# Transform the point into the specified coordinate system from WGS84
spatialRef = osr.SpatialReference()
spatialRef.ImportFromEPSG(4326)
coordTransform = osr.CoordinateTransformation(
spatialRef, layer.GetSpatialRef())
point.Transform(coordTransform)
for feature in layer:
if feature.GetGeometryRef().Contains(point):
break
for i in range(feature.GetFieldCount()):
print feature.GetField(i)
3 个回答
2
另一种选择是使用Shapely(这是一个基于GEOS的Python库,GEOS是PostGIS的引擎)和Fiona(主要用于读取和写入文件):
import fiona
import shapely
with fiona.open("path/to/shapefile.shp") as fiona_collection:
# In this case, we'll assume the shapefile only has one record/layer (e.g., the shapefile
# is just for the borders of a single country, etc.).
shapefile_record = fiona_collection.next()
# Use Shapely to create the polygon
shape = shapely.geometry.asShape( shapefile_record['geometry'] )
point = shapely.geometry.Point(32.398516, -39.754028) # longitude, latitude
# Alternative: if point.within(shape)
if shape.contains(point):
print "Found shape for point."
需要注意的是,如果多边形很大或很复杂(比如一些国家的海岸线非常不规则的形状文件),进行点在多边形内的测试可能会比较耗时。在某些情况下,使用边界框可以帮助我们快速排除一些不可能的情况,然后再进行更复杂的测试:
minx, miny, maxx, maxy = shape.bounds
bounding_box = shapely.geometry.box(minx, miny, maxx, maxy)
if bounding_box.contains(point):
...
最后,请记住,加载和解析大型或不规则的形状文件需要一些时间(不幸的是,这些类型的多边形在内存中也往往占用较多空间)。
3
可以看看这个Python Shapefile库。
这个库可以帮助你获取几何形状和其他不同的信息。
2
你可以使用Python来调用gdal/ogr这个工具包。下面是一个例子:
from osgeo import ogr
ds = ogr.Open("somelayer.shp")
lyr = ds.GetLayerByName("somelayer")
lyr.ResetReading()
point = ogr.CreateGeometryFromWkt("POINT(4 5)")
for feat in lyr:
geom = feat.GetGeometryRef()
if geom.Contains(point):
sm = feat.GetField(feat.GetFieldIndex("surface_material"))
# do stuff...