import pandas as pd import matplotlib.pyplot as plt import numpy as np # Настройка русских шрифтов plt.rcParams['font.family'] = 'DejaVu Sans' plt.rcParams['axes.unicode_minus'] = False def load_and_prepare_data(filename='experiment_results.csv'): """Загрузка данных из CSV и подготовка.""" df = pd.read_csv(filename, delimiter=',') # Используем запятую как разделитель # Переименовываем столбцы для удобства df.columns = ['maze_type', 'algorithm', 'avg_time_ms', 'avg_visited_cells', 'avg_path_length'] # Преобразование типов numeric_cols = ['avg_time_ms', 'avg_visited_cells', 'avg_path_length'] for col in numeric_cols: df[col] = pd.to_numeric(df[col], errors='coerce') # Добавляем столбец с размером лабиринта для анализа def extract_maze_size(maze_name): if 'Small' in maze_name: return 'Small (10x10)' elif 'Medium' in maze_name: return 'Medium (50x50)' elif 'Large' in maze_name: return 'Large (100x100)' elif 'Empty' in maze_name: return 'Empty (30x30)' elif 'No Exit' in maze_name: return 'No Exit (20x20)' return maze_name df['maze_category'] = df['maze_type'].apply(extract_maze_size) return df def plot_time_comparison(df): """График 1: Сравнение времени выполнения по лабиринтам.""" fig, ax = plt.subplots(figsize=(12, 6)) maze_types = df['maze_category'].unique() algorithms = df['algorithm'].unique() x = np.arange(len(maze_types)) width = 0.2 colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for i, algorithm in enumerate(algorithms): algo_data = df[df['algorithm'] == algorithm] times = [] for maze in maze_types: row = algo_data[algo_data['maze_category'] == maze] if not row.empty: times.append(row['avg_time_ms'].values[0]) else: times.append(0) bars = ax.bar(x + i*width, times, width, label=algorithm, color=colors[i]) ax.set_xlabel('Тип лабиринта', fontsize=12) ax.set_ylabel('Время выполнения (мс)', fontsize=12) ax.set_title('Сравнение времени выполнения алгоритмов поиска пути', fontsize=14) ax.set_xticks(x + width * 1.5) ax.set_xticklabels(maze_types, rotation=45, ha='right') ax.legend() ax.grid(True, alpha=0.3, axis='y') # Добавление значений на столбцы for i, algorithm in enumerate(algorithms): algo_data = df[df['algorithm'] == algorithm] for j, maze in enumerate(maze_types): row = algo_data[algo_data['maze_category'] == maze] if not row.empty and row['avg_time_ms'].values[0] > 0: time_val = row['avg_time_ms'].values[0] ax.text(x[j] + i*width, time_val + 0.02, f'{time_val:.3f}', ha='center', va='bottom', fontsize=8) plt.tight_layout() plt.savefig('time_comparison.png', dpi=150) plt.show() def plot_visited_cells(df): """График 2: Количество посещённых клеток.""" fig, ax = plt.subplots(figsize=(12, 6)) maze_types = df['maze_category'].unique() algorithms = df['algorithm'].unique() x = np.arange(len(maze_types)) width = 0.2 colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for i, algorithm in enumerate(algorithms): algo_data = df[df['algorithm'] == algorithm] visited = [] for maze in maze_types: row = algo_data[algo_data['maze_category'] == maze] if not row.empty: visited.append(row['avg_visited_cells'].values[0]) else: visited.append(0) ax.bar(x + i*width, visited, width, label=algorithm, color=colors[i]) ax.set_xlabel('Тип лабиринта', fontsize=12) ax.set_ylabel('Количество посещённых клеток', fontsize=12) ax.set_title('Сравнение количества посещённых клеток', fontsize=14) ax.set_xticks(x + width * 1.5) ax.set_xticklabels(maze_types, rotation=45, ha='right') ax.legend() ax.grid(True, alpha=0.3, axis='y') plt.tight_layout() plt.savefig('visited_cells.png', dpi=150) plt.show() def plot_path_length(df): """График 3: Длина найденного пути.""" fig, ax = plt.subplots(figsize=(12, 6)) # Исключаем лабиринты без выхода (где путь = 0) df_filtered = df[df['avg_path_length'] > 0] maze_types = df_filtered['maze_category'].unique() algorithms = df_filtered['algorithm'].unique() x = np.arange(len(maze_types)) width = 0.2 colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for i, algorithm in enumerate(algorithms): algo_data = df_filtered[df_filtered['algorithm'] == algorithm] path_lengths = [] for maze in maze_types: row = algo_data[algo_data['maze_category'] == maze] if not row.empty: path_lengths.append(row['avg_path_length'].values[0]) else: path_lengths.append(0) ax.bar(x + i*width, path_lengths, width, label=algorithm, color=colors[i]) ax.set_xlabel('Тип лабиринта', fontsize=12) ax.set_ylabel('Длина пути (количество клеток)', fontsize=12) ax.set_title('Сравнение длины найденного пути', fontsize=14) ax.set_xticks(x + width * 1.5) ax.set_xticklabels(maze_types, rotation=45, ha='right') ax.legend() ax.grid(True, alpha=0.3, axis='y') plt.tight_layout() plt.savefig('path_length.png', dpi=150) plt.show() def plot_time_per_maze(df): """График 4: Для каждого лабиринта - сравнение алгоритмов по времени.""" maze_types = df['maze_category'].unique() algorithms = df['algorithm'].unique() for maze in maze_types: fig, ax = plt.subplots(figsize=(10, 6)) maze_data = df[df['maze_category'] == maze] times = [] algo_names = [] for algo in algorithms: row = maze_data[maze_data['algorithm'] == algo] if not row.empty: times.append(row['avg_time_ms'].values[0]) algo_names.append(algo) bars = ax.bar(algo_names, times, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'][:len(algo_names)]) ax.set_xlabel('Алгоритм', fontsize=12) ax.set_ylabel('Время выполнения (мс)', fontsize=12) ax.set_title(f'Сравнение алгоритмов на лабиринте: {maze}', fontsize=14) ax.grid(True, alpha=0.3, axis='y') # Добавление значений на столбцы for bar, time_val in zip(bars, times): height = bar.get_height() ax.text(bar.get_x() + bar.get_width()/2., height + 0.02, f'{time_val:.3f}', ha='center', va='bottom', fontsize=10) plt.tight_layout() # Очищаем имя файла от скобок safe_maze_name = maze.replace('(', '').replace(')', '').replace(' ', '_') plt.savefig(f'time_{safe_maze_name}.png', dpi=150) plt.show() def plot_visited_per_maze(df): """График 5: Для каждого лабиринта - посещённые клетки.""" maze_types = df['maze_category'].unique() for maze in maze_types: fig, ax = plt.subplots(figsize=(10, 6)) maze_data = df[df['maze_category'] == maze] visited = maze_data['avg_visited_cells'].values algo_names = maze_data['algorithm'].values bars = ax.bar(algo_names, visited, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'][:len(algo_names)]) ax.set_xlabel('Алгоритм', fontsize=12) ax.set_ylabel('Количество посещённых клеток', fontsize=12) ax.set_title(f'Посещённые клетки на лабиринте: {maze}', fontsize=14) ax.grid(True, alpha=0.3, axis='y') # Добавление значений на столбцы for bar, val in zip(bars, visited): height = bar.get_height() ax.text(bar.get_x() + bar.get_width()/2., height + 10, f'{int(val)}', ha='center', va='bottom', fontsize=10) plt.tight_layout() safe_maze_name = maze.replace('(', '').replace(')', '').replace(' ', '_') plt.savefig(f'visited_{safe_maze_name}.png', dpi=150) plt.show() def plot_efficiency_ratio(df): """График 6: Эффективность (время на клетку пути).""" fig, ax = plt.subplots(figsize=(12, 6)) # Исключаем лабиринты без пути df_filtered = df[(df['avg_path_length'] > 0) & (df['avg_time_ms'] > 0)].copy() df_filtered['efficiency'] = df_filtered['avg_time_ms'] / df_filtered['avg_path_length'] maze_types = df_filtered['maze_category'].unique() algorithms = df_filtered['algorithm'].unique() x = np.arange(len(maze_types)) width = 0.2 colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for i, algorithm in enumerate(algorithms): algo_data = df_filtered[df_filtered['algorithm'] == algorithm] efficiency = [] for maze in maze_types: row = algo_data[algo_data['maze_category'] == maze] if not row.empty: efficiency.append(row['efficiency'].values[0]) else: efficiency.append(0) ax.bar(x + i*width, efficiency, width, label=algorithm, color=colors[i]) ax.set_xlabel('Тип лабиринта', fontsize=12) ax.set_ylabel('Время на клетку пути (мс/клетку)', fontsize=12) ax.set_title('Эффективность алгоритмов (время на единицу длины пути)', fontsize=14) ax.set_xticks(x + width * 1.5) ax.set_xticklabels(maze_types, rotation=45, ha='right') ax.legend() ax.grid(True, alpha=0.3, axis='y') plt.tight_layout() plt.savefig('efficiency_ratio.png', dpi=150) plt.show() def plot_path_vs_visited(df): """График 7: Соотношение длины пути и посещённых клеток.""" fig, ax = plt.subplots(figsize=(10, 6)) algorithms = df['algorithm'].unique() markers = ['o', 's', '^', 'D'] colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for algo, marker, color in zip(algorithms, markers, colors): algo_data = df[df['algorithm'] == algo] # Только лабиринты с путём algo_data = algo_data[algo_data['avg_path_length'] > 0] if not algo_data.empty: plt.scatter(algo_data['avg_visited_cells'], algo_data['avg_path_length'], marker=marker, s=100, label=algo, color=color, alpha=0.7) # Добавляем подписи для каждой точки for _, row in algo_data.iterrows(): plt.annotate(row['maze_category'].split()[0], (row['avg_visited_cells'], row['avg_path_length']), xytext=(5, 5), textcoords='offset points', fontsize=8) plt.xlabel('Количество посещённых клеток', fontsize=12) plt.ylabel('Длина пути (клеток)', fontsize=12) plt.title('Соотношение: посещённые клетки vs длина пути', fontsize=14) plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.savefig('path_vs_visited.png', dpi=150) plt.show() def main(): """Основная функция: загрузка данных и построение всех графиков.""" try: df = load_and_prepare_data('experiment_results.csv') print("Данные успешно загружены") print(f"Найдено {len(df)} записей") print("\nСтруктура данных:") print(df.head()) print("\nУникальные типы лабиринтов:") print(df['maze_category'].unique()) print("\nУникальные алгоритмы:") print(df['algorithm'].unique()) print("\nПостроение графиков...") # Базовые графики plot_time_comparison(df) plot_visited_cells(df) plot_path_length(df) # Детальные графики по каждому лабиринту plot_time_per_maze(df) plot_visited_per_maze(df) # Аналитические графики plot_efficiency_ratio(df) plot_path_vs_visited(df) print("\nВсе графики сохранены в текущей директории:") print(" - time_comparison.png") print(" - visited_cells.png") print(" - path_length.png") print(" - time_{maze}.png (для каждого лабиринта)") print(" - visited_{maze}.png (для каждого лабиринта)") print(" - efficiency_ratio.png") print(" - path_vs_visited.png") # Вывод статистики print("\n=== Краткая статистика ===") for maze in df['maze_category'].unique(): print(f"\n{maze}:") maze_data = df[df['maze_category'] == maze] for algo in df['algorithm'].unique(): algo_data = maze_data[maze_data['algorithm'] == algo] if not algo_data.empty: time_val = algo_data['avg_time_ms'].values[0] visited_val = int(algo_data['avg_visited_cells'].values[0]) path_val = int(algo_data['avg_path_length'].values[0]) print(f" {algo}: время={time_val:.6f}мс, посещено={visited_val}, путь={path_val}") except FileNotFoundError: print("Ошибка: файл experiment_results.csv не найден") print("Убедитесь, что файл находится в текущей директории") except Exception as e: print(f"Ошибка: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()