"""plot_results.py - графики для эксперимента с лабиринтами.""" import csv import os import matplotlib.pyplot as plt import numpy as np CSV = "docs/data/results.csv" PLOTS = "docs/data/plots" os.makedirs(PLOTS, exist_ok=True) def load_means(): """Возвращает dict[(maze, strategy)] = (time_ms, visited, path_len, cost).""" out = {} with open(CSV, encoding="utf-8") as f: rows = list(csv.reader(f)) start = next(i for i, r in enumerate(rows) if r and r[0] == "--- СРЕДНИЕ ---") + 2 for r in rows[start:]: if not r: continue maze, strat, t, vis, plen, cost = r out[(maze, strat)] = (float(t), int(vis), int(plen), int(cost)) return out MAZES = ["small_10x10", "medium_51x51", "large_101x101", "empty_30x30", "nopath_15x15", "weighted_31x31", "weighted_choice"] STRATEGIES = ["BFS", "DFS", "A*", "Dijkstra"] COLORS = {"BFS": "#3498db", "DFS": "#e67e22", "A*": "#2ecc71", "Dijkstra": "#9b59b6"} def grouped_bar(means, idx, ylabel, title, fname, log=True): x = np.arange(len(MAZES)) w = 0.2 fig, ax = plt.subplots(figsize=(11, 5)) for i, s in enumerate(STRATEGIES): vals = [means[(m, s)][idx] for m in MAZES] bars = ax.bar(x + (i - 1.5) * w, vals, w, label=s, color=COLORS[s], alpha=0.9) for b, v in zip(bars, vals): ax.text(b.get_x() + b.get_width() / 2, b.get_height(), f"{v:g}", ha="center", va="bottom", fontsize=7, rotation=0) ax.set_xticks(x) ax.set_xticklabels(MAZES, rotation=20, ha="right") ax.set_ylabel(ylabel) ax.set_title(title) if log: ax.set_yscale("log") ax.legend() ax.grid(axis="y", linestyle="--", alpha=0.4) plt.tight_layout() p = os.path.join(PLOTS, fname) plt.savefig(p, dpi=130) plt.close() print("saved:", p) def weighted_choice_chart(means): """Отдельный график для weighted_choice: путь vs стоимость.""" strategies = STRATEGIES lengths = [means[("weighted_choice", s)][2] for s in strategies] costs = [means[("weighted_choice", s)][3] for s in strategies] x = np.arange(len(strategies)) w = 0.35 fig, ax = plt.subplots(figsize=(7.5, 4.5)) b1 = ax.bar(x - w/2, lengths, w, label="длина пути (клеток)", color="#3498db", alpha=0.9) b2 = ax.bar(x + w/2, costs, w, label="стоимость пути (сумма весов)", color="#e74c3c", alpha=0.9) for bars in (b1, b2): for bar in bars: ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height(), f"{bar.get_height():.0f}", ha="center", va="bottom", fontsize=9) ax.set_xticks(x); ax.set_xticklabels(strategies) ax.set_title("weighted_choice: BFS/DFS режут через болото,\n" "Dijkstra/A* находят более дешёвый обход") ax.set_ylabel("значение") ax.legend() ax.grid(axis="y", linestyle="--", alpha=0.4) plt.tight_layout() p = os.path.join(PLOTS, "weighted_choice_compare.png") plt.savefig(p, dpi=130) plt.close() print("saved:", p) def main(): means = load_means() grouped_bar(means, 0, "Время, мс (среднее по 7 запускам, лог. шкала)", "Время поиска пути", "time_compare.png", log=True) grouped_bar(means, 1, "Число посещённых клеток (лог. шкала)", "Сколько клеток посетил алгоритм", "visited_compare.png", log=True) grouped_bar(means, 2, "Длина пути (клеток)", "Длина найденного пути", "path_compare.png", log=False) weighted_choice_chart(means) if __name__ == "__main__": main()