""" Analyseur et générateur de graphiques pour les résultats de simulation """ import json import matplotlib.pyplot as plt import matplotlib matplotlib.use('Agg') # Backend sans affichage class ResultsAnalyzer: """Analyse et visualise les résultats des simulations.""" def __init__(self, results_file): """ Charge les résultats depuis un fichier JSON. Args: results_file (str): Chemin vers le fichier JSON """ with open(results_file, 'r') as f: self.results = json.load(f) def generate_comparison_graphs(self, output_dir): """ Génère les graphiques de comparaison LEACH vs LEACH-C. Args: output_dir (str): Répertoire de sortie """ # 1. FDN Comparison self._plot_fdn_comparison(output_dir) # 2. FMR Comparison self._plot_fmr_comparison(output_dir) # 3. DLBI Comparison self._plot_dlbi_comparison(output_dir) # 4. RSPI Comparison self._plot_rspi_comparison(output_dir) # 5. Alive Nodes Over Rounds self._plot_alive_nodes(output_dir) def _plot_fdn_comparison(self, output_dir): """Graphique : FDN pour tous les scénarios.""" scenarios = list(self.results.keys()) leach_fdn = [] leachc_fdn = [] for scenario in scenarios: leach_metrics = self.results[scenario]["LEACH"]["metrics"] leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"] leach_fdn.append(leach_metrics.get("first_dead_node_round") or 0) leachc_fdn.append(leachc_metrics.get("first_dead_node_round") or 0) fig, ax = plt.subplots(figsize=(12, 6)) x_pos = range(len(scenarios)) width = 0.35 ax.bar([i - width/2 for i in x_pos], leach_fdn, width, label='LEACH', color='#FF6B6B') ax.bar([i + width/2 for i in x_pos], leachc_fdn, width, label='LEACH-C', color='#4ECDC4') ax.set_xlabel('Scénario', fontsize=12) ax.set_ylabel('Premier Nœud Mort (Round)', fontsize=12) ax.set_title('Comparaison FDN (First Dead Node)', fontsize=14, fontweight='bold') ax.set_xticks(x_pos) ax.set_xticklabels(scenarios, rotation=45, ha='right') ax.legend() ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(f"{output_dir}/01_FDN_Comparison.png", dpi=300) plt.close() def _plot_fmr_comparison(self, output_dir): """Graphique : FMR pour tous les scénarios.""" scenarios = list(self.results.keys()) leach_fmr = [] leachc_fmr = [] for scenario in scenarios: leach_metrics = self.results[scenario]["LEACH"]["metrics"] leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"] leach_fmr.append(leach_metrics.get("first_muted_round") or 9999) leachc_fmr.append(leachc_metrics.get("first_muted_round") or 9999) fig, ax = plt.subplots(figsize=(12, 6)) x_pos = range(len(scenarios)) width = 0.35 ax.bar([i - width/2 for i in x_pos], leach_fmr, width, label='LEACH', color='#FF6B6B') ax.bar([i + width/2 for i in x_pos], leachc_fmr, width, label='LEACH-C', color='#4ECDC4') ax.set_xlabel('Scénario', fontsize=12) ax.set_ylabel('Premier Round Muet', fontsize=12) ax.set_title('Comparaison FMR (First Muted Round)', fontsize=14, fontweight='bold') ax.set_xticks(x_pos) ax.set_xticklabels(scenarios, rotation=45, ha='right') ax.legend() ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(f"{output_dir}/02_FMR_Comparison.png", dpi=300) plt.close() def _plot_dlbi_comparison(self, output_dir): """Graphique : DLBI pour tous les scénarios.""" scenarios = list(self.results.keys()) leach_dlbi = [] leachc_dlbi = [] for scenario in scenarios: leach_metrics = self.results[scenario]["LEACH"]["metrics"] leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"] leach_dlbi.append(leach_metrics.get("dlbi", 0)) leachc_dlbi.append(leachc_metrics.get("dlbi", 0)) fig, ax = plt.subplots(figsize=(12, 6)) x_pos = range(len(scenarios)) width = 0.35 ax.bar([i - width/2 for i in x_pos], leach_dlbi, width, label='LEACH', color='#FF6B6B') ax.bar([i + width/2 for i in x_pos], leachc_dlbi, width, label='LEACH-C', color='#4ECDC4') ax.set_xlabel('Scénario', fontsize=12) ax.set_ylabel('DLBI (0 à 1)', fontsize=12) ax.set_title('Comparaison DLBI (Dynamic Load Balancing Index)', fontsize=14, fontweight='bold') ax.set_xticks(x_pos) ax.set_xticklabels(scenarios, rotation=45, ha='right') ax.set_ylim([0, 1.1]) ax.legend() ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(f"{output_dir}/03_DLBI_Comparison.png", dpi=300) plt.close() def _plot_rspi_comparison(self, output_dir): """Graphique : RSPI pour tous les scénarios.""" scenarios = list(self.results.keys()) leach_rspi = [] leachc_rspi = [] for scenario in scenarios: leach_metrics = self.results[scenario]["LEACH"]["metrics"] leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"] leach_rspi.append(leach_metrics.get("rspi", 0)) leachc_rspi.append(leachc_metrics.get("rspi", 0)) fig, ax = plt.subplots(figsize=(12, 6)) x_pos = range(len(scenarios)) width = 0.35 ax.bar([i - width/2 for i in x_pos], leach_rspi, width, label='LEACH', color='#FF6B6B') ax.bar([i + width/2 for i in x_pos], leachc_rspi, width, label='LEACH-C', color='#4ECDC4') ax.set_xlabel('Scénario', fontsize=12) ax.set_ylabel('RSPI (0 à 1)', fontsize=12) ax.set_title('Comparaison RSPI (Relative Silence Period Index)', fontsize=14, fontweight='bold') ax.set_xticks(x_pos) ax.set_xticklabels(scenarios, rotation=45, ha='right') ax.set_ylim([0, 1.1]) ax.legend() ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(f"{output_dir}/04_RSPI_Comparison.png", dpi=300) plt.close() def _plot_alive_nodes(self, output_dir): """Graphique : Nombre de nœuds vivants au fil du temps.""" scenarios = list(self.results.keys())[:3] # Premiers 3 scénarios fig, axes = plt.subplots(len(scenarios), 2, figsize=(14, 4*len(scenarios))) for idx, scenario in enumerate(scenarios): # LEACH leach_detailed = self.results[scenario]["LEACH"]["detailed_rounds"] rounds = [r["round"] for r in leach_detailed] alive = [r["alive_nodes"] for r in leach_detailed] axes[idx, 0].plot(rounds, alive, marker='o', label='LEACH', color='#FF6B6B') axes[idx, 0].set_xlabel('Round') axes[idx, 0].set_ylabel('Nœuds Vivants') axes[idx, 0].set_title(f'LEACH - {scenario}') axes[idx, 0].grid(alpha=0.3) # LEACH-C leachc_detailed = self.results[scenario]["LEACH-C"]["detailed_rounds"] rounds = [r["round"] for r in leachc_detailed] alive = [r["alive_nodes"] for r in leachc_detailed] axes[idx, 1].plot(rounds, alive, marker='s', label='LEACH-C', color='#4ECDC4') axes[idx, 1].set_xlabel('Round') axes[idx, 1].set_ylabel('Nœuds Vivants') axes[idx, 1].set_title(f'LEACH-C - {scenario}') axes[idx, 1].grid(alpha=0.3) plt.tight_layout() plt.savefig(f"{output_dir}/05_Alive_Nodes_Over_Time.png", dpi=300) plt.close() def generate_summary_table(self, output_file): """ Génère un tableau récapitulatif en CSV. Args: output_file (str): Chemin du fichier CSV """ with open(output_file, 'w') as f: # En-tête f.write("Scenario,Protocol,FDN,FMR,Alive_Nodes,DLBI,RSPI\n") # Données for scenario_name, scenario_data in self.results.items(): for protocol in ["LEACH", "LEACH-C"]: metrics = scenario_data[protocol]["metrics"] f.write(f"{scenario_name},{protocol},") f.write(f"{metrics.get('first_dead_node_round', 'N/A')},") f.write(f"{metrics.get('first_muted_round', 'N/A')},") f.write(f"{metrics.get('final_alive_nodes', 'N/A')},") f.write(f"{metrics.get('dlbi', 'N/A'):.4f},") f.write(f"{metrics.get('rspi', 'N/A'):.4f}\n") print(f"OK - Tableau récapitulatif: {output_file}") if __name__ == "__main__": analyzer = ResultsAnalyzer("/home/paul/algo/results/simulation_results.json") analyzer.generate_comparison_graphs("/home/paul/algo/results") analyzer.generate_summary_table("/home/paul/algo/results/summary.csv")