我使用matplotlib.patches.ellipse创建了一个椭圆,如下所示:
patch = mpatches.Ellipse(center, major_ax, minor_ax, angle_deg, fc='none', ls='solid', ec='g', lw='3.')
我想要的是此补丁中包含的所有整数坐标的列表。 即如果我要将此椭圆与同一网格上的每个整数点一起绘制,那么椭圆中会包含多少个这些点?
我试过看看我是否可以提取椭圆的方程式,这样我就可以遍历每个点,看看它是否属于直线,但我似乎找不到明显的方法来做到这一点,它变成了因为椭圆的长轴可以以任何角度定向,所以更复杂。执行此操作的信息必须存储在某个地方的补丁中,但我似乎无法找到它。
对此的任何建议都将非常感激。
答案 0 :(得分:4)
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()
这将为您提供如下结果:
答案 1 :(得分:2)
如果您真的想使用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
对渲染器依赖性的评论。
为了找到更可靠的边界框,您可以:
在绘图坐标中创建水平和垂直向量(它们的位置不重要,([0,0],[1,0])和([0,0],[0,1])会这样做)
将这些矢量转换为椭圆坐标(get_transform
等)
在椭圆坐标系中找到(即椭圆是原点周围的单位圆的系统)圆的四个切线与这两个向量平行
找到矢量的交点(4个交点,但2个对角线就够了)
将交叉点转换回绘图坐标
这将给出准确的(但当然受数值精度限制)方形边界框。
但是,您可以使用简单的近似值:
换句话说,所有可能的点都在一个方形边界框内,它位于x0 + -m / 2,y0 + -m / 2之间,其中(x0,y0)是椭圆的中心,m是长轴。 / p>
答案 2 :(得分:0)
我想提供另一种使用Path
对象的contains_points()
方法而不是contains_point()
的解决方案:
首先获取椭圆的坐标并将其变为Path
对象:
elpath=Path(el.get_verts())
(请注意el.get_paths()
由于某种原因无法工作。)
然后拨打路径contains_points()
:
validcoords=elpath.contains_points(coords)
下面我将比较@ tacaswell的解决方案(方法1),@ Drv&#39; s(方法2)和我自己的(方法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()
方法更慢。坐标变换方法比我的更快,但是当你获得不规则形状的轮廓/多边形时,这种方法仍然有效。
最后结果图: