Python 从 4 点创建椭圆

Python Creating an Oval from 4 points

我正在尝试做一个连接 4 个点的非常基本的形状。我目前有一个看起来像 this 的情节。但是,我似乎找不到可以适当生成连接所有四个点的椭圆的模块。这四个点都会有所不同(它们是测试的结果,旨在显示某人具有多少每个属性)。我发现有很多模块可以创建矩形、椭圆形或圆形,但这些形状中的 none 将始终与点对齐。是否有更通用的模块可以将所有四个点连接成更像椭圆形的形状?

我还看到一些模块可以在两点之间创建弧线,我认为这可能很有用,我可以对所有四个点都这样做。当我尝试这样做时,它需要与弧角相关的输入,我不知道如何计算。非常感谢对此的任何帮助!

这是我用来生成所示图像的代码。

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

下面的做法是interpolating spline通过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()

同样的方法也适用于椭圆形无法适应或太大的情况:

注意to uniquely define an ellipse,需要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))