import pandas as pd
import numpy as np
from sympy import *
import matplotlib.pyplot as plt

np.random.seed(42)
# Création des données
n = 20
# Variable 1 : base aléatoire selon loi normale
var1 = np.random.normal(50, 15, n)
# Variable 2 : fortement corrélée avec var1 (corrélation ~0.9)
var2 = var1 * 0.9 + np.random.normal(0, 5, n)
# Variable 3 : faiblement corrélée avec les autres (corrélation ~0.2)
var3 = np.random.normal(30, 10, n) + 0.2 * var1 + 0.1 * var2
# Création du DataFrame
df = pd.DataFrame({'Variable1': var1,'Variable2': var2,'Variable3': var3})
# Générer le code LaTeX pour le tableau
latex_code = df.to_latex(
    index=True,
    caption="Tableau de données original (20 individus, 3 variables)",
    label="tab:donnees_brutes",
    position='h',
    column_format='|c|c|c|c|',
    escape=True
)
# Arrondir les valeurs à 2 décimales
df = df.round(2)
# Centrage et réduction manuelle
df_standardized = (df - df.mean()) / df.std()
df_standardized.corr().round(3)
# Transformation en matrice SymPy
# Récupérer la matrice de corrélation numpy
corr_numpy = df_standardized.corr().values
# Créer la matrice SymPy
corr_sympy = Matrix(corr_numpy)
A = corr_sympy
# Pour une meilleure lisibilité, on peut arrondir
corr_sympy_rounded = corr_sympy.applyfunc(lambda x: Float(x, 3))
A = corr_sympy_rounded
# 2. Calcul des valeurs propres et vecteurs propres
eigs = A.eigenvects()  # [(val_propre, multiplicité, [vecteurs_propres])]
# 3. Trier les valeurs propres dans l'ordre décroissant
eigs_sorted = sorted(eigs, key=lambda x: x[0], reverse=True)
# 4. déterminer la matrice diagonale D formée des valeurs propres 
# et P la matrice de passage qui est orthogonale
D = Matrix.diag(*[ev[0] for ev in eigs_sorted])
P = Matrix.hstack(*[ev[2][0].normalized() for ev in eigs_sorted])
VectPropres = P.columnspace()
# Créer les coordonnées des vecteurs propres
x,y,z = VectPropres[0][0],VectPropres[0][1],VectPropres[0][2]
xx,yy,zz = VectPropres[1][0],VectPropres[1][1],VectPropres[1][2]
xxx,yyy,zzz = VectPropres[2][0],VectPropres[2][1],VectPropres[2][2]
# Les données centrées réduites transformées en matrice
Donnees = Matrix(df_standardized.values)
#  Calculer et convertir les projections en nombres 
projections1,projections2=[],[]
for j in range(20):
    a=Donnees[j,:]
    c=P**(-1)*a.transpose()
    c,d=c[0],c[1]
    projections1.append(float(c.evalf()))
    projections2.append(float(d.evalf()))
# Création du graphique
plt.figure(figsize=(10, 8))
plt.scatter(projections1, projections2, alpha=0.7, s=60, color='blue')
# Ajout des labels et titre
plt.xlabel('Composante 1', fontsize=12)
plt.ylabel('Composante 2', fontsize=12)
plt.title('Graphique des projections des individus', fontsize=14)
# Ajout des lignes de référence pour le centre (0,0)
plt.axhline(y=0, color='gray', linestyle='--', alpha=0.7)
plt.axvline(x=0, color='gray', linestyle='--', alpha=0.7)
# Ajout des numéros pour chaque point
for i, (x, y) in enumerate(zip(projections1, projections2)):
    plt.annotate(str(i+1), (x, y), xytext=(5, 5), textcoords='offset points',fontsize=9, alpha=0.8)
# Ajustement des limites pour mieux voir les points et Grille pour meilleure lisibilité
plt.xlim(min(projections1)-0.5, max(projections1)+0.5)
plt.ylim(min(projections2)-0.5, max(projections2)+0.5)
plt.grid(True, alpha=0.3)
plt.savefig("./Figures/figure.png")
