Verifique si los puntos están dentro de la elipse más rápido que el método de WITH_Puntos

Uso matplotlib 1.15.1 e bash generar diagtwigs de dispersión como este:

ejemplo

Los puntos suspensivos tienen tamaños de arreglos y se dibujan con las coordenadas del centro, el ancho, la altura y el ángulo (proporcionados desde el exterior): No tengo idea de cuáles son sus ecuaciones.

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) 

Estas elipses deben marcar datos normales y semi-normales en mi ttwig. Luego, tengo una serie de ~ 500 puntos que deben ser coloreados según la elipse a la que pertenecen. Así que traté de verificar cada punto con el métodonos_puntos:

 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) 

Finalmente, se dibujan puntos:

 plt.scatter(x_array, y_array, s=10, c=[colors_scheme[x] for x in colors_array], edgecolor="k", linewidths=0.3) 

¡Pero si contiene_puntos es extremadamente lento! Funcionó durante 5 minutos para un diagtwig de dispersión de 300 puntos, y tengo que generar miles de ellos en paralelo. Tal vez hay un enfoque más rápido? El proyecto PS completo está vinculado a matplotlib, no puedo usar otras bibliotecas.

Este enfoque debe probar si un punto está dentro de una elipse, dado el centro, el ancho, la altura y el ángulo de la elipse. Encuentra las coordenadas x e y del punto en relación con el centro de la elipse, luego transformas las que usan el ángulo para que sean las coordenadas a lo largo de los ejes mayor y menor. Finalmente, encuentra la distancia normalizada del punto desde el centro de la celda, donde una distancia de 1 estaría en la elipse, menos de 1 está dentro y más de 1 está afuera.

 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() 

introduzca la descripción de la imagen aquí

Tenga en cuenta que este script completo tarda 0,6 segundos en ejecutarse y procesar 500 puntos. Eso incluye crear y guardar la figura, etc.

El cálculo de las distancias y los colores del punto toma 0.00017 segundos en mi macbook pro.

Su implementación actual solo debería ser una acción de acción de contains_point 25,000 a 50,000 veces, lo que no es mucho. Entonces, supongo que la implementación de contains_point está orientada hacia la precisión en lugar de la velocidad.

Ya que tiene una distribución de puntos donde solo un pequeño porcentaje estará en una elipse dada, y por lo tanto, la mayoría rara vez estará cerca de una elipse dada, puede usar fácilmente las coordenadas rectangulares como atajo para determinar si el punto está cerca suficiente para que la elipse valga la pena llamar a contains_point .

Calcule las coordenadas x izquierda y derecha y las coordenadas y superior e inferior de la elipse, posiblemente con un poco de relleno para tener en cuenta las diferencias de representación, luego verifique si el punto está dentro de ellas, como el siguiente pseudocódigo:

 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 

Este enfoque elimina cálculos costosos para la mayoría de los puntos, permitiendo comparaciones simples en lugar de descartar los desajustes obvios, al tiempo que conserva la precisión de los cálculos donde el punto está lo suficientemente cerca como para que pueda estar en la elipse. Si, por ejemplo, solo el 1% de sus puntos se encuentran cerca de una elipse determinada, este enfoque eliminará el 99% de sus llamadas contains_point y, en su lugar, los reemplazará con comparaciones mucho más rápidas.