我使用matplotlib 1.15.1,我尝试生成这样的散点图:
椭圆有固定尺寸,用中心坐标,宽度,高度和角度绘制(从外面提供):我不知道它们的等距是什么。
g_ell_center = (0.8882, 0.8882)
g_ell_width = 0.36401857095483
g_ell_height = 0.16928136341606
g_ellipse = patches.Ellipse(g_ell_center, g_ell_width, g_ell_height, angle=angle, fill=False, edgecolor='green', linewidth=2)
这个省略号应标记我的情节上的正常和半正常数据。 然后,我有一个~500点的数组,必须根据它们所属的椭圆进行着色。所以我尝试用contains_point方法检查每个点:
colors_array = []
colors_scheme = ['green', 'yellow', 'black']
for point in points_array:
if g_ellipse.contains_point(point, radius=0):
colors_array.append(0)
elif y_ellipse.contains_point(point, radius=0):
colors_array.append(1)
else:
colors_array.append(2)
最后,得出了一些观点:
plt.scatter(x_array, y_array, s=10, c=[colors_scheme[x] for x in colors_array], edgecolor="k", linewidths=0.3)
但contains_point非常慢!对于300点散点图,它工作了5分钟,我必须并行生成数千个散点图。也许有更快的方法? 附:整个项目绑定到matplotlib,我不能使用其他库。
答案 0 :(得分:9)
考虑到椭圆的中心,宽度,高度和角度,这种方法应测试一个点是否在椭圆内。您可以找到相对于椭圆中心的点x和y坐标,然后将使用该角度的坐标转换为沿长轴和短轴的坐标。最后,您可以找到该点与单元格中心的归一化距离,其中椭圆上的距离为1,内部小于1,外部大于1。
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
fig,ax = plt.subplots(1)
ax.set_aspect('equal')
# Some test points
x = np.random.rand(500)*0.5+0.7
y = np.random.rand(500)*0.5+0.7
# The ellipse
g_ell_center = (0.8882, 0.8882)
g_ell_width = 0.36401857095483
g_ell_height = 0.16928136341606
angle = 30.
g_ellipse = patches.Ellipse(g_ell_center, g_ell_width, g_ell_height, angle=angle, fill=False, edgecolor='green', linewidth=2)
ax.add_patch(g_ellipse)
cos_angle = np.cos(np.radians(180.-angle))
sin_angle = np.sin(np.radians(180.-angle))
xc = x - g_ell_center[0]
yc = y - g_ell_center[1]
xct = xc * cos_angle - yc * sin_angle
yct = xc * sin_angle + yc * cos_angle
rad_cc = (xct**2/(g_ell_width/2.)**2) + (yct**2/(g_ell_height/2.)**2)
colors_array = []
for r in rad_cc:
if r <= 1.:
# point in ellipse
colors_array.append('green')
else:
# point not in ellipse
colors_array.append('black')
ax.scatter(x,y,c=colors_array,linewidths=0.3)
plt.show()
注意,整个脚本需要0.6秒才能运行并处理500个点。这包括创建和保存数字等。
在我的macbook pro上计算点的距离和颜色需要0.00017秒。
答案 1 :(得分:2)
您当前的实施应该只调用contains_point
25,000到50,000次,这不是很多。所以,我猜测contains_point
的实现是针对精确而非速度的。
由于你有一个点的分布,其中只有一小部分将在任何给定的椭圆中,因此大多数很少会在任何给定的椭圆附近,你可以很容易地使用直角坐标作为捷径来确定是否点足够接近椭圆,值得调用if point.x >= ellipse_left and point.x <= ellipse_right and _
point.y >= ellipse_top and point.y <= ellipse_bottom:
if ellipse.contains_point(point, radius=0):
... use the contained point here
。
计算椭圆的左右x坐标和顶部和底部y坐标,可能需要一些填充来解释渲染差异,然后检查点是否在那些内,例如下面的伪代码:< / p>
contains_point
这种方法消除了大多数点的昂贵计算,允许简单的比较而不是排除明显的不匹配,同时保持计算的准确性,其中点足够接近它可能在椭圆中。如果是只有1%的点位于给定椭圆附近的任何位置,这种方法将消除99%的import org.joda.time.*;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.LocalDate;
LocalTime startTime2;
LocalTime airTime2;
LocalTime foamTime2;
LocalTime scTime22;
firstTime = airTime2;
secondTime = localTime;
return firstTime.compareTo(secondTime);
调用,而是用更快的比较替换它们。