Python, создающий овал из 4 точек

#python #matplotlib #shapes

#python #matplotlib #формы

Вопрос:

Я пытаюсь создать очень простую форму, соединяющую 4 точки. В настоящее время у меня есть график, который выглядит так. Однако, похоже, я не могу найти модуль, который может соответствующим образом сгенерировать овал, соединяющий все четыре точки. Все четыре точки будут отличаться (они являются результатами теста, предназначенного для того, чтобы показать, сколько у кого-то каждого атрибута). Я нашел много модулей для создания прямоугольников, эллипсов или кругов, но ни одна из этих фигур не будет последовательно совмещаться с точками. Существует ли более универсальный модуль, который может соединять все четыре точки в форме, больше похожей на овал?

Я также видел некоторые модули, которые могли бы создать дугу между двумя точками, что, как мне показалось, может быть полезным, я мог бы сделать это для всех четырех точек. Когда я попытался это сделать, потребовались входные данные, связанные с углом дуги, который я бы не знал, как вычислить. Любая помощь по этому вопросу очень ценится!

Вот код, который я использую для создания показанного изображения.

 import matplotlib.pyplot as plt
import numpy as np

# Axes go from 0 to 100%
fig,ax = plt.subplots(figsize=(15,12))

x = [-40,-20,20,20]
y = [-40,20,20,-20]

plt.scatter(x,y)
ax.fill_between([-100, 0],-100,0,alpha=0.3, color='#1F98D0')  # blue
ax.fill_between([0, 100], -100, 0, alpha=0.3, color='#F9D307')  # yellow
ax.fill_between([-100, 0], 0, 100, alpha=0.3, color='#F38D25')  # orange
ax.fill_between([0, 100], 0, 100, alpha=0.3, color='#DA383D')  # red
plt.axis('off')
plt.show()
  

Ответ №1:

Следующий подход создает интерполирующий сплайн через 4 точки для создания «базовой формы». Преимущество заключается в том, что это также работает, когда имеется 3 или более 4 точек.

 import matplotlib.pyplot as plt
from scipy import interpolate
import numpy as np

fig, ax = plt.subplots(figsize=(15, 12))

x = [-40, -20, 20, 20]
y = [-40, 20, 20, -20]

ax.scatter(x, y, zorder=3)
ax.fill_between([-100, 0], -100, 0, alpha=0.3, color='#1F98D0')  #blue
ax.fill_between([0, 100], -100, 0, alpha=0.3, color='#F9D307')  #yellow
ax.fill_between([-100, 0], 0, 100, alpha=0.3, color='#F38D25')  #orange
ax.fill_between([0, 100], 0, 100, alpha=0.3, color='#DA383D')  #red

tck, u = interpolate.splprep([x   x[:1], y   y[:1]], s=0, per=True)
unew = np.linspace(0, 1, 100)
basic_form = interpolate.splev(unew, tck)
ax.plot(basic_form[0], basic_form[1], color='lime', lw=2)
ax.fill(basic_form[0], basic_form[1], color='lime', alpha=0.3)

ax.axis('off')
plt.show()
  

результирующий график

Тот же подход также работает, когда овальную форму невозможно уместить или она слишком велика:

разные положения точек

Обратите внимание, что для однозначного определения эллипса требуется 5 точек (но не каждые 5 случайных точек могут соответствовать эллипсу). Если вам действительно нужен эллипс, найти наименьший из 4 точек довольно сложно.

Здесь начинается подход, который определяет эллипс как точки, в которых сумма расстояний до двух фокусов ( (x0,y0) и (x1,y1) ) является постоянной a . Затем можно было бы найти некоторый минимум, a для которого существует решение.

 from sympy import symbols, sqrt, Eq, nsolve

a, x0, y0, x1, y1, xi, yi = symbols('a x0 y0 x1 y1 xi yi', real=True)
ellipse = Eq(sqrt((xi - x0) ** 2   (yi - y0) ** 2)   sqrt((xi - x1) ** 2   (yi - y1) ** 2), a)

x = [-40, -20, 20, 20]
y = [-40, 20, 20, -20]

ai = 85
sol = nsolve([ellipse.subs(xi, i).subs(yi, j).subs(a, ai) for i, j in zip(x, y)], (x0, y0, x1, y1), (-10, 0, 10, 0))