Question

matplotlib ellipse englobing points

How to find the ideal angle to place all the points in the ellipse ? I would like to create an ellipse which surrounds all the points on the graph, ellipse with the minimum size (it means that the furthest points will be on the graph of the ellipse).

'

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Ellipse

# Données des points (abscisses et ordonnées)
x = [1, 2, 3, 4, 5]
y = [7, 12, 15, 19, 25]

# Calculer les moyennes des abscisses et ordonnées
centre_x = np.mean(x)
centre_y = np.mean(y)

# Calculer les écarts entre chaque point et le centre
dx = np.abs(x - centre_x)
dy = np.abs(y - centre_y)

# Trouver les valeurs maximales des écarts
max_dx = np.max(dx)
max_dy = np.max(dy)

# Utiliser ces valeurs pour définir la largeur et la hauteur de l'ellipse
largeur = 2 * max_dx
hauteur = 2 * max_dy

# Calculer l'angle idéal (en radians)
angle_rad = np.arctan2(max_dy, max_dx)

# Convertir l'angle en degrés
angle_deg = np.degrees(angle_rad)

# Créer l'ellipse
ellipse = Ellipse((centre_x, centre_y), largeur, hauteur, angle=angle_deg, fill=False, color='red')

# Créer un nuage de points avec des couleurs aléatoires pour chaque point
plt.scatter(x, y, c=np.random.rand(len(x), 3))

# Ajouter l'ellipse au graphique
plt.gca().add_patch(ellipse)

# Afficher le graphique
plt.show()

'

I have the size of the ellipse, but don't find an angle that matches to do that.

 3  61  3
1 Jan 1970

Solution

 2

IIUC, you want the Minimum Volume Enclosing Ellipsoid. If so, you can use mvee from QInfer:

import matplotlib.pyplot as plt
import numpy as np
from qinfer.utils import mvee
from scipy import linalg


def get_mvee(points):
    A, centroid = mvee(points)
    *_, D, V = linalg.svd(A)
    radii = 1 / np.sqrt(D)

    u = np.linspace(0, 2 * np.pi, 100)
    x = radii[0] * np.cos(u)
    y = radii[1] * np.sin(u)

    return V.T @ np.vstack([x, y]) + centroid[:, None]


x = [1, 2, 3, 4, 5]
y = [7, 12, 15, 19, 25]
points = np.c_[x, y]
ellipse = get_mvee(points)

fig, ax = plt.subplots()
ax.scatter(*points.T, marker=".", color="r", zorder=3)
ax.plot(*ellipse)
ax.patch.set_facecolor("whitesmoke")
ax.grid(True)

plt.show();

enter image description here

2024-06-29
Timeless