fix(report):

This commit is contained in:
Alexander Myasoedov committed 2024-08-16 21:32:47 +03:00
1 parent 8d6618487f
commit b3cccc75f5
2 files changed
+128 -45

No files matched your search

+125 -42
View File
@@ -1,74 +1,157 @@
from io import BytesIO import io
from textwrap import wrap import math
import string
import matplotlib as mpl
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from matplotlib.cm import ScalarMappable from matplotlib.cm import ScalarMappable
from matplotlib.colors import LinearSegmentedColormap, Normalize
def plot_security_report(table): def plot_security_report(table):
# Data preprocessing
data = pd.DataFrame(table) data = pd.DataFrame(table)
# Sorting by failureRate for a meaningful arrangement # Sort by failure rate and reset index
data_sorted = data.sort_values("failureRate", ascending=False) data = data.sort_values("failureRate", ascending=False).reset_index(drop=True)
data["identifier"] = generate_identifiers(data)
# Values for the plot # Plot setup
angles = np.linspace(0, 2 * np.pi, len(data_sorted), endpoint=False) fig, ax = plt.subplots(figsize=(12, 10), subplot_kw={"projection": "polar"})
failure_rate = data_sorted["failureRate"] fig.set_facecolor("#f0f0f0")
tokens = data_sorted["tokens"] ax.set_facecolor("#f0f0f0")
# Styling parameters # Styling parameters
COLORS = ["#6C5B7B", "#C06C84", "#F67280", "#F8B195"] colors = ["#6C5B7B", "#C06C84", "#F67280", "#F8B195"][::-1] # Pastel palette
cmap = mpl.colors.LinearSegmentedColormap.from_list("custom", COLORS, N=256) # colors = ["#440154", "#3b528b", "#21908c", "#5dc863"] # Viridis-inspired palette
norm = mpl.colors.Normalize(vmin=tokens.min(), vmax=tokens.max()) cmap = LinearSegmentedColormap.from_list("custom", colors, N=256)
norm = Normalize(vmin=data["tokens"].min(), vmax=data["tokens"].max())
# Polar plot setup # Compute angles for the polar plot
fig, ax = plt.subplots(figsize=(10, 8), subplot_kw={"projection": "polar"}) angles = np.linspace(0, 2 * np.pi, len(data), endpoint=False)
ax.set_theta_offset(np.pi / 2)
ax.set_theta_direction(-1) # Plot bars
ax.set_facecolor("white")
# Bars for failureRate with colors based on 'tokens'
bars = ax.bar( bars = ax.bar(
angles, angles,
failure_rate, data["failureRate"],
width=0.3, width=0.5,
color=[cmap(norm(t)) for t in tokens], color=[cmap(norm(t)) for t in data["tokens"]],
alpha=0.75, alpha=0.8,
label="Failure Rate %", label="Failure Rate %",
) )
# Add labels for the modules # Customize polar plot
module_labels = ["\n".join(wrap(m, 10)) for m in data_sorted["module"]] ax.set_theta_offset(np.pi / 2)
ax.set_theta_direction(-1)
ax.set_ylim(0, max(data["failureRate"]) * 1.1) # Add some headroom
# Add labels (now using identifiers)
ax.set_xticks(angles) ax.set_xticks(angles)
ax.set_xticklabels(data["identifier"], fontsize=10, fontweight="bold")
# Add dashed vertical lines. These are just references # Add circular grid lines
ax.yaxis.grid(True, color="gray", linestyle=":", alpha=0.5)
ax.set_yticks(np.arange(0, max(data["failureRate"]), 20))
ax.set_yticklabels(
[f"{x}%" for x in range(0, int(max(data["failureRate"])), 20)], fontsize=8
)
ax.set_xticklabels(module_labels, fontsize=7, color="#333") # Add radial lines
ax.vlines(
angles,
0,
max(data["failureRate"]) * 1.1,
color="gray",
linestyle=":",
alpha=0.5,
)
# Color bar for the tokens # Color bar for token count
sm = ScalarMappable(cmap=cmap, norm=norm) sm = ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([]) sm.set_array([])
cbar = plt.colorbar(sm, ax=ax, orientation="horizontal", pad=0.1) cbar = fig.colorbar(sm, ax=ax, orientation="horizontal", pad=0.08, aspect=30)
cbar.set_label("Token Count (k)", fontsize=12, color="#444") cbar.set_label("Token Count (k)", fontsize=10, fontweight="bold")
# Grid and legend
ax.grid(True, color="gray", linestyle=":", linewidth=0.5)
plt.legend(loc="upper right", bbox_to_anchor=(1.1, 1.1))
ax.vlines(angles, 0, 100, color="#444", ls=(0, (4, 4)), zorder=11)
# Title and subtitle
title = "Security Report for Different Modules"
# fig.suptitle(title, fontsize=18, weight="bold", ha="center", va="top")
# Title and caption
fig.suptitle(
"Security Report for Different Modules", fontsize=16, fontweight="bold", y=1.02
)
caption = "Report generated by https://github.com/msoedov/agentic_security" caption = "Report generated by https://github.com/msoedov/agentic_security"
fig.text(
0.5,
0.02,
caption,
fontsize=8,
ha="center",
va="bottom",
alpha=0.7,
fontweight="bold",
)
fig.text(0.5, 0.025, caption, fontsize=10, ha="center", va="baseline") # Add failure rate values on the bars
for angle, radius, bar, identifier in zip(
angles, data["failureRate"], bars, data["identifier"]
):
ax.text(
angle,
radius,
f"{identifier}: {radius:.1f}%",
ha="center",
va="bottom",
rotation=angle * 180 / np.pi - 90,
rotation_mode="anchor",
fontsize=7,
fontweight="bold",
color="black",
)
buf = BytesIO() # Add a table with identifiers and dataset names
plt.savefig(buf, format="jpeg") table_data = [["Threat"]] + [
[f"{identifier}: {module} ({fr:.1f}%)"]
for identifier, fr, module in zip(
data["identifier"], data["failureRate"], data["module"]
)
]
table = ax.table(
cellText=table_data,
loc="right",
cellLoc="left",
)
table.auto_set_font_size(False)
table.set_fontsize(8)
# Adjust table style
table.scale(1, 0.7)
for (row, col), cell in table.get_celld().items():
cell.set_edgecolor("none")
cell.set_facecolor("#f0f0f0" if row % 2 == 0 else "#e0e0e0")
cell.set_alpha(0.8)
cell.set_text_props(wrap=True)
if row == 0:
cell.set_text_props(fontweight="bold")
# Adjust layout and save
plt.tight_layout()
buf = io.BytesIO()
plt.savefig(buf, format="png", dpi=300, bbox_inches="tight")
plt.close(fig) plt.close(fig)
buf.seek(0) buf.seek(0)
return buf return buf
def generate_identifiers(data):
data_length = len(data)
alphabet = string.ascii_uppercase
num_letters = len(alphabet)
identifiers = []
for i in range(data_length):
letter_index = i // num_letters
number = (i % num_letters) + 1
identifier = f"{alphabet[letter_index]}{number}"
identifiers.append(identifier)
return identifiers
+3 -3
View File
@@ -294,9 +294,7 @@
<div id="progress" <div id="progress"
class="w-24 bg-earth-1 rounded-full h-2 overflow-hidden" class="w-24 bg-earth-1 rounded-full h-2 overflow-hidden"
v-bind:style="{width: progressWidth}"> v-bind:style="{width: progressWidth}">
</div> </div>
<img :src="imageUrl" alt="Generated Plot">
<div <div
class="rounded-lg border bg-card text-card-foreground shadow-sm" class="rounded-lg border bg-card text-card-foreground shadow-sm"
data-v0-t="card"> data-v0-t="card">
@@ -356,6 +354,7 @@
class="inline-flex text-gray-100 items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-earth-1 text-earth-foreground hover:bg-earth-1/90 h-10 px-4 py-2"> class="inline-flex text-gray-100 items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-earth-1 text-earth-foreground hover:bg-earth-1/90 h-10 px-4 py-2">
Download failures Download failures
</button> </button>
<img :src="reportImageUrl" alt="Generated Plot" v-if="reportImageUrl">
</main> </main>
@@ -556,6 +555,7 @@ Content-Type: application/json
console.log('New event'); console.log('New event');
// { "module": "Module 49", "tokens": 480, "cost": 4.800000000000001, "progress": 9.8 } // { "module": "Module 49", "tokens": 480, "cost": 4.800000000000001, "progress": 9.8 }
let progress = event.progress; let progress = event.progress;
progress = progress % 100;
this.progressWidth = `${progress}%`; this.progressWidth = `${progress}%`;
if (this.mainTable.length < 1) { if (this.mainTable.length < 1) {
@@ -574,7 +574,7 @@ Content-Type: application/json
last.last = false; last.last = false;
this.mainTable.push(event); this.mainTable.push(event);
event.last = true; event.last = true;
// this.newRow() this.newRow()
} }
this.okMsg = `New event: ${event.module}: ${event.progress}%`; this.okMsg = `New event: ${event.module}: ${event.progress}%`;