|
from pathlib import Path |
|
from typing import Any |
|
|
|
import matplotlib.patches as mpatches |
|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
import pandas as pd |
|
from matplotlib.colors import Normalize |
|
|
|
|
|
def save_combined_radar_chart( |
|
categories: dict[str, Any], save_path: str | Path |
|
) -> None: |
|
categories = {k: v for k, v in categories.items() if v} |
|
if not all(categories.values()): |
|
raise Exception("No data to plot") |
|
labels = np.array( |
|
list(next(iter(categories.values())).keys()) |
|
) |
|
num_vars = len(labels) |
|
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist() |
|
angles += angles[ |
|
:1 |
|
] |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True)) |
|
ax.set_theta_offset(np.pi / 2) |
|
ax.set_theta_direction(-1) |
|
ax.spines["polar"].set_visible(False) |
|
|
|
|
|
norm = Normalize( |
|
vmin=0, vmax=max([max(val.values()) for val in categories.values()]) |
|
) |
|
|
|
cmap = plt.cm.get_cmap("nipy_spectral", len(categories)) |
|
|
|
colors = [cmap(i) for i in range(len(categories))] |
|
|
|
for i, (cat_name, cat_values) in enumerate( |
|
categories.items() |
|
): |
|
values = np.array(list(cat_values.values())) |
|
values = np.concatenate((values, values[:1])) |
|
|
|
ax.fill(angles, values, color=colors[i], alpha=0.25) |
|
ax.plot(angles, values, color=colors[i], linewidth=2) |
|
ax.plot( |
|
angles, |
|
values, |
|
"o", |
|
color="white", |
|
markersize=7, |
|
markeredgecolor=colors[i], |
|
markeredgewidth=2, |
|
) |
|
|
|
|
|
legend = ax.legend( |
|
handles=[ |
|
mpatches.Patch(color=color, label=cat_name, alpha=0.25) |
|
for cat_name, color in zip(categories.keys(), colors) |
|
], |
|
loc="upper left", |
|
bbox_to_anchor=(0.7, 1.3), |
|
) |
|
|
|
|
|
plt.tight_layout() |
|
|
|
lines, labels = plt.thetagrids( |
|
np.degrees(angles[:-1]), (list(next(iter(categories.values())).keys())) |
|
) |
|
|
|
highest_score = 7 |
|
|
|
|
|
ax.set_ylim(top=highest_score) |
|
|
|
|
|
for label in labels: |
|
label.set_position( |
|
(label.get_position()[0], label.get_position()[1] + -0.05) |
|
) |
|
|
|
|
|
ax.set_rlabel_position(180) |
|
|
|
ax.set_yticks([]) |
|
|
|
|
|
for y in np.arange(0, highest_score + 1, 1): |
|
if y != highest_score: |
|
ax.plot( |
|
angles, [y] * len(angles), color="gray", linewidth=0.5, linestyle=":" |
|
) |
|
|
|
ax.text( |
|
angles[0], |
|
y + 0.2, |
|
str(int(y)), |
|
color="black", |
|
size=9, |
|
horizontalalignment="center", |
|
verticalalignment="center", |
|
) |
|
|
|
plt.savefig(save_path, dpi=300) |
|
plt.close() |
|
|
|
|
|
def save_single_radar_chart( |
|
category_dict: dict[str, int], save_path: str | Path |
|
) -> None: |
|
labels = np.array(list(category_dict.keys())) |
|
values = np.array(list(category_dict.values())) |
|
|
|
num_vars = len(labels) |
|
|
|
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist() |
|
|
|
angles += angles[:1] |
|
values = np.concatenate((values, values[:1])) |
|
|
|
colors = ["#1f77b4"] |
|
|
|
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True)) |
|
ax.set_theta_offset(np.pi / 2) |
|
ax.set_theta_direction(-1) |
|
|
|
ax.spines["polar"].set_visible(False) |
|
|
|
lines, labels = plt.thetagrids( |
|
np.degrees(angles[:-1]), (list(category_dict.keys())) |
|
) |
|
|
|
highest_score = 7 |
|
|
|
|
|
ax.set_ylim(top=highest_score) |
|
|
|
for label in labels: |
|
label.set_position((label.get_position()[0], label.get_position()[1] + -0.05)) |
|
|
|
ax.fill(angles, values, color=colors[0], alpha=0.25) |
|
ax.plot(angles, values, color=colors[0], linewidth=2) |
|
|
|
for i, (angle, value) in enumerate(zip(angles, values)): |
|
ha = "left" |
|
if angle in {0, np.pi}: |
|
ha = "center" |
|
elif np.pi < angle < 2 * np.pi: |
|
ha = "right" |
|
ax.text( |
|
angle, |
|
value - 0.5, |
|
f"{value}", |
|
size=10, |
|
horizontalalignment=ha, |
|
verticalalignment="center", |
|
color="black", |
|
) |
|
|
|
ax.set_yticklabels([]) |
|
|
|
ax.set_yticks([]) |
|
|
|
if values.size == 0: |
|
return |
|
|
|
for y in np.arange(0, highest_score, 1): |
|
ax.plot(angles, [y] * len(angles), color="gray", linewidth=0.5, linestyle=":") |
|
|
|
for angle, value in zip(angles, values): |
|
ax.plot( |
|
angle, |
|
value, |
|
"o", |
|
color="white", |
|
markersize=7, |
|
markeredgecolor=colors[0], |
|
markeredgewidth=2, |
|
) |
|
|
|
plt.savefig(save_path, dpi=300) |
|
plt.close() |
|
|
|
|
|
def save_combined_bar_chart(categories: dict[str, Any], save_path: str | Path) -> None: |
|
if not all(categories.values()): |
|
raise Exception("No data to plot") |
|
|
|
|
|
df = pd.DataFrame(categories) |
|
|
|
|
|
df.plot(kind="bar", figsize=(10, 7)) |
|
|
|
plt.title("Performance by Category for Each Agent") |
|
plt.xlabel("Category") |
|
plt.ylabel("Performance") |
|
|
|
plt.savefig(save_path, dpi=300) |
|
plt.close() |
|
|