Патчи имеют тест на наличие точек или нет: contains_point
и даже для массивов точек: contains_points
Просто для игры у меня есть фрагмент кода для вас, который вы можете добавить междучасть, в которой вы добавляете свои патчи и кодовый блок #Sorting the coordinates into bins
.
Он добавляет два дополнительных (прозрачных) эллипса для расчета, будут ли дуги содержать точки, если они были полностью закрытыми эллипсами.Тогда ваш расчет бина - это просто логическая комбинация тестов, если точка принадлежит большому овалу, левому или правому эллипсу или имеет положительную или отрицательную x-координату.
ov1 = mpl.patches.Ellipse(ang1, 70, 110, alpha=0)
ov2 = mpl.patches.Ellipse(ang2, 70, 110, alpha=0)
ax.add_patch(ov1)
ax.add_patch(ov2)
for px, py in zip(X, Y):
in_oval = Oval.contains_point(ax.transData.transform(([px, py])), 0)
in_left = ov1.contains_point(ax.transData.transform(([px, py])), 0)
in_right = ov2.contains_point(ax.transData.transform(([px, py])), 0)
on_left = px < 0
on_right = px > 0
if in_oval:
if in_left:
n_bin = 1
elif in_right:
n_bin = 4
elif on_left:
n_bin = 2
elif on_right:
n_bin = 3
else:
n_bin = -1
else:
n_bin = -1
print('({:>2}/{:>2}) is {}'.format(px, py, 'in Bin ' +str(n_bin) if n_bin>0 else 'outside'))
Вывод:
(24/94) is in Bin 3
(15/61) is in Bin 3
(71/76) is in Bin 4
(72/83) is in Bin 4
( 6/69) is in Bin 3
(13/86) is in Bin 3
(77/78) is outside
(52/57) is in Bin 4
(52/45) is in Bin 4
(62/94) is in Bin 4
(46/82) is in Bin 4
(43/74) is in Bin 4
(31/56) is in Bin 4
(35/70) is in Bin 4
(41/94) is in Bin 4
Обратите внимание, что вы все равно должны решить, как определять ячейки, когда точки имеют координату x = 0 - в тот момент, когда они равны снаружи, так как on_left
и on_right
оба не чувствуют ответственности за них...
PS: Благодаря @ImportanceOfBeingErnest за подсказку к необходимому преобразованию: https://stackoverflow.com/a/49112347/8300135
Примечание: для всех следующих РЕДАКТИРОВАНИЙ вам потребуется import numpy as np
РЕДАКТИРОВАТЬ: Функция для подсчета распределения бина на X, Y
массив ввода:
def bin_counts(X, Y):
bc = dict()
E = Oval.contains_points(ax.transData.transform(np.array([X, Y]).T), 0)
E_l = ov1.contains_points(ax.transData.transform(np.array([X, Y]).T), 0)
E_r = ov2.contains_points(ax.transData.transform(np.array([X, Y]).T), 0)
L = np.array(X) < 0
R = np.array(X) > 0
bc[1] = np.sum(E & E_l)
bc[2] = np.sum(E & L & ~E_l)
bc[3] = np.sum(E & R & ~E_r)
bc[4] = np.sum(E & E_r)
return bc
приведет к этому результату:
bin_counts(X, Y)
Out: {1: 0, 2: 0, 3: 4, 4: 10}
EDIT2: множество строк в двух 2D-массивах для X и Y:
np.random.seed(42)
X = np.random.randint(-80, 80, size=(100, 10))
Y = np.random.randint(0, 120, size=(100, 10))
с циклом по всем строкам:
for xr, yr in zip(X, Y):
print(bin_counts(xr, yr))
результат:
{1: 1, 2: 2, 3: 6, 4: 0}
{1: 1, 2: 0, 3: 4, 4: 2}
{1: 5, 2: 2, 3: 1, 4: 1}
...
{1: 3, 2: 2, 3: 2, 4: 0}
{1: 2, 2: 4, 3: 1, 4: 1}
{1: 1, 2: 1, 3: 6, 4: 2}
EDIT3: для возврата не количества точек в каждом бине, а массива с четырьмя массивами, содержащимиng x, y-координаты точек в каждом бине, используйте следующее:
X = [24,15,71,72,6,13,77,52,52,62,46,43,31,35,41]
Y = [94,61,76,83,69,86,78,57,45,94,82,74,56,70,94]
def bin_points(X, Y):
X = np.array(X)
Y = np.array(Y)
E = Oval.contains_points(ax.transData.transform(np.array([X, Y]).T), 0)
E_l = ov1.contains_points(ax.transData.transform(np.array([X, Y]).T), 0)
E_r = ov2.contains_points(ax.transData.transform(np.array([X, Y]).T), 0)
L = X < 0
R = X > 0
bp1 = np.array([X[E & E_l], Y[E & E_l]]).T
bp2 = np.array([X[E & L & ~E_l], Y[E & L & ~E_l]]).T
bp3 = np.array([X[E & R & ~E_r], Y[E & R & ~E_r]]).T
bp4 = np.array([X[E & E_r], Y[E & E_r]]).T
return [bp1, bp2, bp3, bp4]
print(bin_points(X, Y))
[array([], shape=(0, 2), dtype=int32), array([], shape=(0, 2), dtype=int32), array([[24, 94],
[15, 61],
[ 6, 69],
[13, 86]]), array([[71, 76],
[72, 83],
[52, 57],
[52, 45],
[62, 94],
[46, 82],
[43, 74],
[31, 56],
[35, 70],
[41, 94]])]
... и снова, чтобы применить это к большим 2D-массивам, просто итерируйте по ним:
np.random.seed(42)
X = np.random.randint(-100, 100, size=(100, 10))
Y = np.random.randint(-40, 140, size=(100, 10))
bincol = ['r', 'g', 'b', 'y', 'k']
for xr, yr in zip(X, Y):
for i, binned_points in enumerate(bin_points(xr, yr)):
ax.scatter(*binned_points.T, c=bincol[i], marker='o' if i<4 else 'x')
![enter image description here](https://i.stack.imgur.com/7n0ZE.png)