agritech-api / src /utils /plot_utils.py
github-actions
Deploy API from GitHub Actions
42dfbed
Raw
History Blame Contribute Delete
12.3 kB
"""plot_utils.py
Ce module contient des fonctions utilitaires pour la visualisation des données, notamment des graphiques linéaires, histogrammes, boxplots, scatterplots et heatmaps de corrélation, ainsi que des fonctions spécifiques pour visualiser les résultats d'une analyse en composantes principales (ACP).
Les fonctions incluent :
- lineplot_graphic : pour visualiser les tendances de plusieurs variables au fil du temps ou d'une autre variable
- histrogram_graphic : pour visualiser la distribution d'une variable
- boxplot_graphic : pour visualiser la distribution d'une variable en fonction d'une autre variable
- scatterplot_graphic : pour visualiser la relation entre deux variables
- pearson_heatmap_graphic : pour visualiser la corrélation entre les variables d'un dataframe en utilisant la méthode de Pearson
- spearman_heatmap_graphic : pour visualiser la corrélation entre les variables d'un dataframe en utilisant la méthode de Spearman
'un dataframe en utilisant la méthode de Spearman
- heatmap_by_group : pour visualiser la corrélation entre les variables d'un dataframe en fonction d'une variable de regroupement
- plot_pca_projection : pour visualiser la projection des données dans le plan défini par les composantes principales
- plot_scree : pour visualiser l'éboulis des valeurs propres (scree plot) pour l'ACP
- plot_correlation_circle : pour visualiser le cercle des corrélations pour les composantes principales
"""
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
def lineplot_graphic(df: pd.DataFrame, x: str, y_list: list, title: str, xlabel: str, ylabel: str, hue: str=None):
"""
graphiques linéaire pour visualiser le pourcentage des valeurs pour un axe x et plusieurs axes y
df: dataframe contenant les données à visualiser
x: nom de la colonne à utiliser pour l'axe x
y_list: liste des colonnes à utiliser pour les axes y
hue: nom de la colonne à utiliser pour colorer les points (optionnel)
title: titre du graphique
xlabel: label de l'axe x
ylabel: label de l'axe y
"""
try:
plt.figure(figsize=(12, 6))
for y in y_list:
if hue is not None:
sns.lineplot(data=df, x=x, y=y, hue=hue)
else:
sns.lineplot(data=df, x=x, y=y, label=y)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.legend()
plt.show()
except ImportError as e:
print("Erreur d'importation : ", e)
return
def histrogram_graphic(df: pd.DataFrame, x: str, title: str, xlabel: str, ylabel: str):
"""
graphique histogramme pour visualiser la distribution d'une variable
df: dataframe contenant les données à visualiser
x: nom de la colonne à utiliser pour l'axe x
title: titre du graphique
xlabel: label de l'axe x
ylabel: label de l'axe y
"""
try:
plt.figure(figsize=(12, 6))
sns.histplot(data=df, x=x, kde=True)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.show()
except ImportError as e:
print("Erreur d'importation : ", e)
return
def boxplot_graphic(df: pd.DataFrame, x: str, y: str=None, title: str="", xlabel: str="", ylabel: str=""):
"""
graphique boxplot pour visualiser la distribution d'une variable en fonction d'une autre variable
df: dataframe contenant les données à visualiser
x: nom de la colonne à utiliser pour l'axe x
y: nom de la colonne à utiliser pour l'axe y optionnel
title: titre du graphique
xlabel: label de l'axe x
ylabel: label de l'axe y
"""
try:
plt.figure(figsize=(12, 6))
sns.boxplot(data=df, x=x, y=y)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.show()
except ImportError as e:
print("Erreur d'importation : ", e)
return
def scatterplot_graphic(df: pd.DataFrame, x: str, y: str, title: str, xlabel: str, ylabel: str, hue: str=None):
"""
graphique scatterplot pour visualiser la relation entre deux variables
df: dataframe contenant les données à visualiser
x: nom de la colonne à utiliser pour l'axe x
y: nom de la colonne à utiliser pour l'axe y
title: titre du graphique
xlabel: label de l'axe x
ylabel: label de l'axe y
hue: nom de la colonne à utiliser pour colorer les points (optionnel)
"""
try:
plt.figure(figsize=(12, 6))
sns.scatterplot(data=df, x=x, y=y, hue=hue)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.show()
except ImportError as e:
print("Erreur d'importation : ", e)
return
def spearman_heatmap_graphic(df: pd.DataFrame, cols: list, title: str):
"""
graphique heatmap pour visualiser la corrélation entre les variables d'un dataframe
df: dataframe contenant les données à visualiser
cols: liste des colonnes à utiliser pour le calcul de la corrélation
title: titre du graphique
"""
try:
plt.figure(figsize=(12, 6))
corr = df[cols].corr(method='spearman')
sns.heatmap(corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1, mask=np.triu(corr))
plt.title(title)
plt.show()
except ImportError as e:
print("Erreur d'importation : ", e)
return
def pearson_heatmap_graphic(df: pd.DataFrame, cols: list, title: str):
"""
graphique heatmap pour visualiser la corrélation entre les variables d'un dataframe
df: dataframe contenant les données à visualiser
cols: liste des colonnes à utiliser pour le calcul de la corrélation
title: titre du graphique
"""
try:
plt.figure(figsize=(12, 6))
corr = df[cols].corr(method='pearson')
sns.heatmap(corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1, mask=np.triu(corr))
plt.title(title)
plt.show()
except ImportError as e:
print("Erreur d'importation : ", e)
return
def heatmap_by_group(df, group_col, cols, method="pearson"):
""" Affiche une heatmap de corrélation pour chaque groupe défini par group_col
df: dataframe contenant les données à visualiser
group_col: nom de la colonne à utiliser pour regrouper les données
cols: liste des colonnes à utiliser pour le calcul de la corrélation
method: méthode de corrélation ("pearson" ou "spearman")
"""
groups = df[group_col].unique()
n = len(groups)
fig, axes = plt.subplots(nrows=n//2 + n%2, ncols=2, figsize=(14, 5*n//2))
axes = axes.flatten()
for i, group in enumerate(groups):
df_group = df[df[group_col] == group]
corr = df_group[cols].corr(method=method)
sns.heatmap(
corr,
ax=axes[i],
annot=True,
cmap="coolwarm",
vmin=-1,
vmax=1,
mask=np.triu(corr)
)
axes[i].set_title(f"{method.capitalize()} - {group}")
# supprime les axes vides
for j in range(i+1, len(axes)):
fig.delaxes(axes[j])
plt.tight_layout()
plt.show()
def plot_pca_projection(X_pca, df, label_col="item", hue_col=None, pc1=1, pc2=2, title=None):
"""
affiche la projection des données dans le plan défini par les composantes principales spécifiées.
arguments:
- X_pca : array-like, les données transformées dans l'espace des composantes principales
- df : pd.DataFrame, le DataFrame original contenant les données
- label_col : str, le nom de la colonne à utiliser pour les étiquettes des points (par défaut "item")
- hue_col : str, le nom de la colonne à utiliser pour la coloration des points (par défaut None)
- pc1 : int, le numéro de la première composante principale à afficher (par défaut 1)
- pc2 : int, le numéro de la deuxième composante principale à afficher (par défaut 2)
- title : str, le titre du graphique (par défaut None, affichera un titre générique)
"""
try:
pca_df = pd.DataFrame({
f"PC{pc1}": X_pca[:, pc1 - 1],
f"PC{pc2}": X_pca[:, pc2 - 1],
label_col: df[label_col].values
})
if hue_col is not None:
pca_df[hue_col] = df[hue_col].values
plt.figure(figsize=(10, 7))
if hue_col is not None:
# détecter si numérique
if pd.api.types.is_numeric_dtype(pca_df[hue_col]):
sc = plt.scatter(
pca_df[f"PC{pc1}"],
pca_df[f"PC{pc2}"],
c=pca_df[hue_col],
cmap="viridis",
alpha=0.7
)
cbar = plt.colorbar(sc)
cbar.set_label(hue_col)
else:
# catégoriel
sns.scatterplot(
data=pca_df,
x=f"PC{pc1}",
y=f"PC{pc2}",
hue=hue_col,
alpha=0.7
)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
else:
# fallback : label_col
sns.scatterplot(
data=pca_df,
x=f"PC{pc1}",
y=f"PC{pc2}",
hue=label_col,
alpha=0.7
)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.title(title if title else f"Projection ACP - PC{pc1} vs PC{pc2}")
plt.xlabel(f"PC{pc1}")
plt.ylabel(f"PC{pc2}")
plt.grid(True)
plt.tight_layout()
plt.show()
except Exception as e:
print(f"Erreur lors de la projection ACP : {e}")
def plot_scree(explained_var, cumulative_var):
"""
Affiche l'éboulis des valeurs propres (scree plot) pour visualiser la variance expliquée par chaque composante principale.
arguments:
- explained_var : array-like, pourcentage de variance expliquée par chaque composante principale
- cumulative_var : array-like, pourcentage de variance cumulée expliquée par les composantes principales
"""
# Graphique
plt.figure(figsize=(8,5))
# Barres (variance individuelle)
plt.bar(range(1, len(explained_var)+1), explained_var, alpha=0.7)
# Ligne (variance cumulée)
plt.plot(range(1, len(cumulative_var)+1), cumulative_var, marker='o', color='red')
# Labels
plt.xlabel("Rang de l'axe d'inertie")
plt.ylabel("Pourcentage d'inertie")
plt.title("Éboulis des valeurs propres")
plt.xticks(range(1, len(explained_var)+1))
plt.ylim(0, 100)
plt.grid(True)
plt.show()
def plot_correlation_circle(pca, features):
"""
Affiche le cercle des corrélations pour les deux premières composantes principales.
arguments:
- pca : objet PCA après ajustement
- features : liste des noms des variables utilisées dans la PCA
"""
x, y = 0,1
fig, ax = plt.subplots(figsize=(10, 9)) # On peut ajuster la taille du graphique selon les besoins
# Affichage des flèches pour chaque variable
for i in range(0, pca.components_.shape[1]):
ax.arrow(0,
0, # Start the arrow at the origin
pca.components_[0, i], #0 for PC1
pca.components_[1, i], #1 for PC2
head_width=0.07,
head_length=0.07,
width=0.02, )
# Affichage des noms des variables à la fin de chaque flèche
plt.text(pca.components_[0, i] + 0.05,
pca.components_[1, i] + 0.05,
features[i])
# affichage des lignes horizontales et verticales
plt.plot([-1, 1], [0, 0], color='grey', ls='--')
plt.plot([0, 0], [-1, 1], color='grey', ls='--')
# nom des axes, avec le pourcentage d'inertie expliqué
plt.xlabel('F{} ({}%)'.format(x+1, round(100*pca.explained_variance_ratio_[x],1)))
plt.ylabel('F{} ({}%)'.format(y+1, round(100*pca.explained_variance_ratio_[y],1)))
plt.title("Cercle des corrélations (F{} et F{})".format(x+1, y+1))
an = np.linspace(0, 2 * np.pi, 100)
plt.plot(np.cos(an), np.sin(an)) # Add a unit circle for scale
plt.axis('equal')
plt.show(block=False)