我使用matplotlib.patches.ellipse创建了一个椭圆,如下所示:
patch = mpatches.Ellipse(center, major_ax, minor_ax, angle_deg, fc='none', ls='solid', ec='g', lw='3.')
我想要的是这个补丁中包含的所有整数坐标的列表。即如果我要将此椭圆与同一网格上的每个整数点一起绘制,那么椭圆中会包含多少个这些点?
我试过看看我是否可以提取椭圆的方程,这样我就可以遍历每个点,看看它是否属于直线,但我似乎无法找到一个明显的方法来做到这一点,它变得更加复杂,因为主要椭圆的轴可以以任何角度定向。执行此操作的信息必须存储在某个地方的补丁中,但我似乎无法找到它。
对此有任何建议将非常感激。
Ellipse
对象有一个方法contains_point
,如果该点在椭圆中,则返回1,其他为0。
窃听@DrV的答案:
import matplotlib.pyplot as plt
import matplotlib.patches
import numpy as np
# create an ellipse
el = matplotlib.patches.Ellipse((50,-23), 10, 13.7, 30, facecolor=(1,0,0,.2), edgecolor='none')
# calculate the x and y points possibly within the ellipse
y_int = np.arange(-30, -15)
x_int = np.arange(40, 60)
# create a list of possible coordinates
g = np.meshgrid(x_int, y_int)
coords = list(zip(*(c.flat for c in g)))
# create the list of valid coordinates (from untransformed)
ellipsepoints = np.vstack([p for p in coords if el.contains_point(p, radius=0)])
# just to see if this works
fig = plt.figure()
ax = fig.add_subplot(111)
ax.add_artist(el)
ep = np.array(ellipsepoints)
ax.plot(ellipsepoints[:,0], ellipsepoints[:,1], 'ko')
plt.show()
这将给你如下结果:
如果你真的想使用matplotlib
提供的方法,那么:
import matplotlib.pyplot as plt
import matplotlib.patches
import numpy as np
# create an ellipse
el = matplotlib.patches.Ellipse((50,-23), 10, 13.7, 30, facecolor=(1,0,0,.2), edgecolor='none')
# find the bounding box of the ellipse
bb = el.get_window_extent()
# calculate the x and y points possibly within the ellipse
x_int = np.arange(np.ceil(bb.x0), np.floor(bb.x1) + 1, dtype='int')
y_int = np.arange(np.ceil(bb.y0), np.floor(bb.y1) + 1, dtype='int')
# create a list of possible coordinates
g = np.meshgrid(x_int, y_int)
coords = np.array(zip(*(c.flat for c in g)))
# create a list of transformed points (transformed so that the ellipse is a unit circle)
transcoords = el.get_transform().inverted().transform(coords)
# find the transformed coordinates which are within a unit circle
validcoords = transcoords[:,0]**2 + transcoords[:,1]**2 < 1.0
# create the list of valid coordinates (from untransformed)
ellipsepoints = coords[validcoords]
# just to see if this works
fig = plt.figure()
ax = fig.add_subplot(111)
ax.add_artist(el)
ep = np.array(ellipsepoints)
ax.plot(ellipsepoints[:,0], ellipsepoints[:,1], 'ko')
似乎工作:
(放大显示,即使是悬挂在边缘的点也在里面。)
这里的要点是matplotlib
处理椭圆作为变换圆(平移,旋转,缩放,任何仿射)。如果反向应用变换,则结果是原点的单位圆,并且检查点是否在该范围内非常简单。
只是一句警告:get_window_extent
可能不是非常可靠,因为它似乎使用圆的样条近似。另外,请参阅tcaswell
对渲染器依赖性的评论。
为了找到更可靠的边界框,您可以:
get_transform
等)这将给出准确的(但当然受数值精度限制)方形边界框。
但是,您可以使用简单的近似值:
换句话说,所有可能的点都在方形边界框内,该方框在x0 + -m / 2,y0 + -m / 2之间,其中(x0,y0)是椭圆的中心,m是长轴。
我想提供另一个使用Path
对象的contains_points()
方法而不是contains_point()
的解决方案:
首先获取椭圆的坐标并使其成为Path
对象:
elpath=Path(el.get_verts())
(请注意,el.get_paths()
由于某种原因不起作用。)
然后调用路径的contains_points()
:
validcoords=elpath.contains_points(coords)
下面我将比较@ tacaswell的解决方案(方法1),@ Drv's(方法2)和我自己的方法3(方法3)(我将椭圆放大了约5倍):
import numpy
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib.path import Path
import time
#----------------Create an ellipse----------------
el=Ellipse((50,-23),50,70,30,facecolor=(1,0,0,.2), edgecolor='none')
#---------------------Method 1---------------------
t1=time.time()
for ii in range(50):
y=numpy.arange(-100,50)
x=numpy.arange(-30,130)
g=numpy.meshgrid(x,y)
coords=numpy.array(zip(*(c.flat for c in g)))
ellipsepoints = numpy.vstack([p for p in coords if el.contains_point(p, radius=0)])
t2=time.time()
print 'time of method 1',t2-t1
#---------------------Method 2---------------------
t2=time.time()
for ii in range(50):
y=numpy.arange(-100,50)
x=numpy.arange(-30,130)
g=numpy.meshgrid(x,y)
coords=numpy.array(zip(*(c.flat for c in g)))
invtrans=el.get_transform().inverted()
transcoords=invtrans.transform(coords)
validcoords=transcoords[:,0]**2+transcoords[:,1]**2<=1.0
ellipsepoints=coords[validcoords]
t3=time.time()
print 'time of method 2',t3-t2
#---------------------Method 3---------------------
t3=time.time()
for ii in range(50):
y=numpy.arange(-100,50)
x=numpy.arange(-30,130)
g=numpy.meshgrid(x,y)
coords=numpy.array(zip(*(c.flat for c in g)))
#------Create a path from ellipse's vertices------
elpath=Path(el.get_verts())
# call contains_points()
validcoords=elpath.contains_points(coords)
ellipsepoints=coords[validcoords]
t4=time.time()
print 'time of method 3',t4-t3
#---------------------Plot it ---------------------
fig,ax=plt.subplots()
ax.add_artist(el)
ep=numpy.array(ellipsepoints)
ax.plot(ellipsepoints[:,0],ellipsepoints[:,1],'ko')
plt.show(block=False)
我得到了这些执行时间:
time of method 1 62.2502269745
time of method 2 0.488734006882
time of method 3 0.588987112045
所以contains_point()
方法慢得多。坐标变换方法比我的快,但是当你获得不规则形状的轮廓/多边形时,这种方法仍然有效。
最后结果图: