File size: 4,255 Bytes
c162d1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from __future__ import annotations

from typing import List

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.lines import Line2D


class RadarPlotter:
    def __init__(self, data_loader):
        self.data_loader = data_loader
        self.dimension_metrics = list(data_loader.dimension_metrics)
        self.dimension_labels = list(data_loader.dimension_display_labels)
        self.color_list = [
            "#1f77b4",
            "#ff7f0e",
            "#2ca02c",
            "#d62728",
            "#9467bd",
            "#8c564b",
            "#e377c2",
            "#7f7f7f",
            "#bcbd22",
            "#17becf",
        ]

    def create_radar_chart(self, models_df: pd.DataFrame) -> plt.Figure:
        if models_df.empty or not self.dimension_metrics:
            fig, ax = plt.subplots(figsize=(8, 6))
            ax.text(0.5, 0.5, "No dimension metrics available for radar chart", ha="center", va="center", fontsize=14)
            ax.axis("off")
            return fig

        plt.rcParams["font.family"] = "sans-serif"
        plt.rcParams["font.sans-serif"] = ["Arial", "Microsoft YaHei", "SimHei", "DejaVu Sans"]
        plt.rcParams["axes.unicode_minus"] = False

        labels = self.dimension_labels
        angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False).tolist()
        angles += angles[:1]

        fig = plt.figure(figsize=(13.5, 8.5))
        grid = fig.add_gridspec(1, 2, width_ratios=[3.2, 1.35], wspace=0.02)
        ax = fig.add_subplot(grid[0, 0], polar=True)
        ax_legend = fig.add_subplot(grid[0, 1])
        ax_legend.axis("off")
        ax.set_theta_offset(np.pi / 2)
        ax.set_theta_direction(-1)
        ax.set_ylim(0, 105)
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(labels, fontsize=11, fontweight="bold")
        ax.set_yticks([20, 40, 60, 80, 100])
        ax.set_yticklabels(["20", "40", "60", "80", "100"], color="#666666")
        ax.yaxis.grid(True, color="#D0D8E8", linewidth=0.8)
        ax.xaxis.grid(True, color="#D0D8E8", linewidth=0.8)
        ax.fill(np.linspace(0, 2 * np.pi, 400), [105] * 400, color="#EAF1FA", alpha=0.5)

        model_scores = []
        for _, row in models_df.iterrows():
            values = [float(row.get(metric, 0) or 0) for metric in self.dimension_metrics]
            valid_values = [value for value in values if value is not None]
            avg_score = sum(valid_values) / len(valid_values) if valid_values else 0
            model_scores.append((row, avg_score))

        model_scores.sort(key=lambda item: item[1])

        legend_elements = []
        for index, (row, _) in enumerate(model_scores):
            values = [float(row.get(metric, 0) or 0) for metric in self.dimension_metrics]
            values += values[:1]
            color = self.color_list[index % len(self.color_list)]
            ax.plot(angles, values, color=color, linewidth=2.0, label=row["Model"])
            ax.fill(angles, values, color=color, alpha=0.06)
            ax.scatter(angles[:-1], values[:-1], color=color, s=36, edgecolors="white", linewidths=0.5)
            legend_elements.append(
                Line2D(
                    [0],
                    [0],
                    color=color,
                    linestyle="-",
                    marker="o",
                    markersize=6,
                    linewidth=2.0,
                    markerfacecolor=color,
                    markeredgecolor="white",
                    markeredgewidth=0.5,
                    label=row["Model"],
                )
            )

        if legend_elements:
            ax_legend.legend(
                handles=legend_elements,
                loc="center left",
                frameon=True,
                fontsize=9,
                fancybox=True,
                shadow=False,
                edgecolor="#d9d9d9",
                facecolor="white",
                borderpad=0.8,
                labelspacing=0.55,
                handlelength=2.0,
                handletextpad=0.7,
            )

        ax.set_title("Dimension Radar Chart", fontsize=18, fontweight="bold", pad=26)
        fig.subplots_adjust(left=0.05, right=0.97, top=0.92, bottom=0.06)
        return fig