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