| import numpy as np |
| import matplotlib.pyplot as plt |
| from matplotlib.collections import LineCollection |
| from matplotlib.colors import LinearSegmentedColormap |
| from plot_lines import TECH_STYLE |
|
|
| def plot_radar_chart(data: dict, attributes: list, assigned_colors: dict = None, save_path: str = None, is_dark_mode: bool = True, font_size_axis: int = 12, font_size_legend: int = 12): |
| """ |
| Plot radar chart for AUP results with tech style. |
| Normalizes each attribute to [0, 1] based on the maximum value across methods. |
| Axes show the real values for each task. |
| data: {method_name: [val1, val2, ...]} |
| attributes: list of attribute names (e.g., datasets) |
| is_dark_mode: whether to use dark mode (True) or light mode (False) |
| font_size_axis: font size for axis labels |
| font_size_legend: font size for legend |
| """ |
| |
| N = len(attributes) |
| angles = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist() |
| angles += [angles[0]] |
| |
| |
| method_names = list(data.keys()) |
| raw_matrix = np.array([data[m] for m in method_names]) |
| |
| |
| attr_maxs = np.max(raw_matrix, axis=0) |
| attr_maxs = np.array([np.ceil(m / 5.0) * 5.0 if m > 0 else 5.0 for m in attr_maxs]) |
| |
| |
| normalized_matrix = raw_matrix / attr_maxs[np.newaxis, :] |
| norm_data = {m: normalized_matrix[i] for i, m in enumerate(method_names)} |
|
|
| |
| if is_dark_mode: |
| style_context = 'dark_background' |
| bg_color = 'black' |
| fg_color = 'white' |
| grid_color = 'white' |
| grid_alpha = 0.3 |
| spine_color = 'white' |
| else: |
| style_context = 'default' |
| bg_color = '#F5F5F7' |
| fg_color = 'black' |
| grid_color = '#86868b' |
| grid_alpha = 0.3 |
| spine_color = '#86868b' |
|
|
| with plt.style.context(style_context): |
| fig, ax = plt.subplots(figsize=(12, 12), subplot_kw=dict(polar=True)) |
| |
| if not is_dark_mode: |
| fig.patch.set_facecolor(bg_color) |
| ax.set_facecolor(bg_color) |
| |
| for i, (method_name, v) in enumerate(norm_data.items()): |
| |
| if assigned_colors: |
| c_name = assigned_colors[i] if isinstance(assigned_colors, list) else assigned_colors.get(method_name, 'grey') |
| else: |
| c_name = 'grey' |
| grad_colors = TECH_STYLE.get(c_name, TECH_STYLE['grey']) |
| main_color = grad_colors[1] |
| cmap = LinearSegmentedColormap.from_list(f"tech_{c_name}", grad_colors) |
| |
| |
| v_loop = np.concatenate([v, [v[0]]]) |
| |
| |
| points = np.array([angles, v_loop]).T.reshape(-1, 1, 2) |
| segments = np.concatenate([points[:-1], points[1:]], axis=1) |
| |
| norm = plt.Normalize(0, 2 * np.pi) |
| lc = LineCollection(segments, cmap=cmap, norm=norm) |
| lc.set_array(np.array(angles)) |
| lc.set_linewidth(4) |
| lc.set_alpha(0.9) |
| ax.add_collection(lc) |
| |
| |
| ax.fill(angles, v_loop, color=main_color, alpha=0.1) |
| |
| |
| edge_c = main_color if is_dark_mode else 'white' |
| |
| |
| |
| ax.scatter(angles, v_loop, color='white', edgecolors=main_color, s=100, zorder=10, lw=2) |
| |
| |
| ax.plot([], [], color=main_color, label=method_name, linewidth=4) |
|
|
| |
| ax.set_theta_offset(np.pi / 2) |
| ax.set_theta_direction(-1) |
| |
| |
| ax.grid(True, linestyle='--', alpha=grid_alpha, color=grid_color, linewidth=1) |
| ax.spines['polar'].set_visible(False) |
| |
| |
| ax.set_xticks(angles[:-1]) |
| labels = ax.set_xticklabels(attributes, fontsize=font_size_axis, color=fg_color, fontweight='bold') |
| ax.tick_params(axis='x', pad=30) |
| |
| |
| if len(attributes) == 4: |
| import matplotlib.transforms as mtransforms |
| for label in labels: |
| if label.get_text() == 'humaneval+': |
| |
| offset = mtransforms.ScaledTranslation(40/72, 0, fig.dpi_scale_trans) |
| label.set_transform(label.get_transform() + offset) |
| |
| |
| ax.set_yticklabels([]) |
| ax.set_ylim(0, 1.05) |
| |
| |
| grid_ticks = [0.2, 0.4, 0.6, 0.8, 1.0] |
| for i, angle in enumerate(angles[:-1]): |
| max_val = attr_maxs[i] |
| for t in grid_ticks: |
| val = t * max_val |
| if val.is_integer(): |
| label = f"{int(val)}" |
| else: |
| label = f"{val:.1f}" |
| |
| |
| box_color = '#202020' if is_dark_mode else '#e0e0e0' |
| text_color_tick = 'white' if is_dark_mode else 'black' |
| |
| ax.text(angle, t, label, |
| color=text_color_tick, fontsize=font_size_axis, fontweight='bold', |
| ha='center', va='center', |
| bbox=dict(facecolor=box_color, edgecolor='none', alpha=0.8, boxstyle='round,pad=0.2')) |
| |
| |
| plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1), frameon=False, fontsize=font_size_legend, labelcolor=fg_color) |
| |
| |
| if save_path: |
| fc = bg_color if not is_dark_mode else 'black' |
| plt.savefig(save_path, dpi=300, bbox_inches='tight', facecolor=fc) |
| print(f"Radar chart saved to {save_path}") |
| |
| |
|
|