从Shapely中的多边形提取点/坐标

114

如何获取/提取定义shapely polygon的点?谢谢!

shapely 多边形的示例

from shapely.geometry import Polygon

# Create polygon from lists of points
x = [list of x vals]
y = [list of y vals]

polygon = Polygon(x,y)
9个回答

132
诀窍是使用Polygon类的方法组合:
from shapely.geometry import Polygon

# Create polygon from lists of points
x = [0.0, 0.0, 1.0, 1.0, 0.0]
y = [0.0, 1.0, 1.0, 0.0, 0.0]

poly = Polygon(zip(x,y))

# Extract the point values that define the perimeter of the polygon
xx, yy = poly.exterior.coords.xy

# Note above return values are of type `array.array` 
assert x == xx.tolist()
assert y == yy.tolist()

如果你想要它们作为坐标对,
assert tuple(poly.exterior.coords) == tuple(zip(x,y))

或者作为一个numpy数组返回
assert np.array_equal(np.array(poly.exterior.coords), np.asarray(tuple(zip(x,y))))

2
这将给出x和y坐标作为单独的列表。要将列表作为单独的(x,y)元组,请使用poly.exterior.coords,如下面@pnklein的答案所示,或者使用sh.get_coordinates(poly)获取数组的数组[x,y]。 - Robbes

77

我花了一些时间才学会多边形有一个外部边界和可能有几个内部边界。我在这里发帖是因为一些答案没有反映出这种区别,虽然公告的原始贴子并没有使用具有内部边界的多边形作为示例。

形成外部边界的点排列在CoordinateSequence中,可以通过以下方式获得:

polygon.exterior.coords

使用len(polygon.exterior.coords)可以找到此对象的长度,并且可以像列表一样索引该对象。例如,要获得第一个顶点,请使用polygon.exterior.coords[0]。请注意,第一个和最后一个点是相同的;如果您想要一个由没有重复点的顶点组成的列表,请使用polygon.exterior.coords[:-1]

您可以将坐标序列(包括重复的顶点)转换为点列表,如下所示:

list(polygon.exterior.coords)

类似地,由形成第一个内部边界的顶点组成的坐标序列可通过polygon.interiors[0].coords获得,而不含重复点的顶点列表可通过polygon.interiors[0].coords[:-1]获得。


你如何获取多边形所包含的所有坐标?也就是说,如何获取多边形内部的所有坐标? - Will.Evo

36
你可以使用shapely的mapping函数:
>>> from shapely.geometry import Polygon, mapping
>>> sh_polygon = Polygon(((0,0), (1,1), (0,1)))
>>> mapping(sh_polygon)
{'type': 'Polygon', 'coordinates': (((0.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)),)}

2
不错。这很好,因为它可以轻松地推广需要这个的例程。 - ryanjdillon
1
如果需要,这也会提供边界框。 - Sam Murphy

14

我用了这个:

list(zip(*p.exterior.coords.xy))

使用以下代码创建多边形:p = Polygon([(0,0),(1,1),(1,0),(0,0)]),返回结果如下:

[(0.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]

8
如果您真的想要构成多边形的漂亮的点对象,而不仅仅是坐标元组,可以按以下方式实现:
points = MultiPoint(polygon.boundary.coords)

2

更新(2017-06-09):

由于最新版本的shapely似乎不再与上一个答案兼容,因此我提出了这个更新。

shapely提供了Numpy数组接口(如文档所述:http://toblerity.org/shapely/project.html

因此,让poly成为一个shapely多边形几何体:

In [2]: type(poly)
Out[2]: shapely.geometry.polygon.Polygon

这个命令将把内容转换成numpy数组:

In [3]: coordinates_array = np.asarray(poly.exterior.coords)

提示:
对于多边形,必须提供外部坐标,因为直接提供几何图形似乎也行不通:

In [4]: coordinates_array = np.asarray(poly)
Out[4]: array(<shapely.geometry.polygon.Polygon object at 0x7f627559c510>, dtype=object)    

2
你可以使用NumPy.array将shapely多边形转换为NumPy数组。我发现使用NumPy数组比使用coords.xy返回的数组更有用,因为坐标是成对的,而不是在两个一维数组中。根据你的应用程序选择更有用的方法。
import numpy as np
x = [1, 2, 3, 4]
y = [9, 8, 7, 6]
polygon = Polygon(x,y)
points = np.array(polygon)

# points is:
[[ 1 9]
 [ 2 8]
 [ 3 7]
 [ 4 6]]

好想法。谢谢!我想当我有一个无序的点组时,我正在使用这个,通过使用coords.xy,我能够提取出一个外部点的有序列表,或者可能是网格的外部点... 我会在有时间的时候尝试一下并回报 :) - ryanjdillon
15
上述代码在使用shapely=1.5.13=py35_0时无法运行。Polygon(x,y)被拒绝。np.array(some_actual_polygon) 的行为也不如所示。 - Masterfool
从Shapely 2.0开始,我们会收到以下警告:C:\ProgramData\Anaconda3\envs\gis\lib\site-packages\IPython\core\interactiveshell.py:3457: ShapelyDeprecationWarning: The array interface is deprecated and will no longer work in Shapely 2.0. Convert the '.coords' to a numpy array instead. 因此,使用points = np.array(polygon.coors)。 - addcolor

2
您可以使用以下两种方法之一。
1)
p = Polygon([(1,0),(1,1),(0,1),(0,0)])
for x,y in p.exterior.coords:
   print(x,y)

上面的代码输出如下。请注意,(1,0)被打印了两次,因为exterior.coords返回一个完成多边形的有序序列。
1.0 0.0
1.0 1.0
0.0 1.0
0.0 0.0
1.0 0.0

2)

p.exterior.coords.xy

它会输出以下内容。
(array('d', [1.0, 1.0, 0.0, 0.0, 1.0]), array('d', [0.0, 1.0, 1.0, 0.0, 0.0]))

1
这两种方法是相同的,并且与我的2013-12-09年回答相同。 - ryanjdillon
@ryanjdillon 嗯,第二个和你的一样。不过我觉得第一个更直观地解包了xy对。 - Roomba
1
问题是如何获取坐标,而不是如何解包元组。我回答这个问题是因为这个答案并没有为如何获取坐标提供额外的信息,并且它不是第一个重复已经存在的答案,比如这个。你的建议最好以对现有答案的评论形式提出。像这样的答案会为人们查找关键信息创建不必要的垃圾。 - ryanjdillon

-1
d0=[]
for n in range(0,len(gdf1['geometry'])):
    try:
        k=(len(gdf1['geometry'][n].geoms))    
        ce+=1
    except:
        d0.append(n)

1
你可能想添加一个说明,解释代码的作用,并且为什么它比其他答案更好。 - BDL
这似乎是在gdf中组成一个几何图形列表,这些图形不是多边形,这与所提出的问题无关。对于这个问题,我可能更愿意使用DataFrame.apply(),就像这个SO问题线程中所建议的那样。 - ryanjdillon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接