Skip to content

Commit

Permalink
pass figures
Browse files Browse the repository at this point in the history
  • Loading branch information
ab-smith committed Dec 7, 2024
1 parent 255958e commit d5f52dd
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 18 deletions.
103 changes: 86 additions & 17 deletions backend/core/generators.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,113 @@
import os
import io
import matplotlib
from icecream import ic
from numpy import char
from .models import *
from math import ceil
from docxtpl import InlineImage
from docx.shared import Cm
import matplotlib.pyplot as plt

matplotlib.use("Agg")

def gen_audit_context(id):

def plot_bar(data):
plt.figure(figsize=(10, 6))
plt.bar(
[item["category"] for item in data],
[item["value"] for item in data],
)
plt.tight_layout()
chart_buffer = io.BytesIO()
plt.savefig(chart_buffer, format="png")
chart_buffer.seek(0)
plt.close()
return chart_buffer


def plot_donut(data, colors=None):
"""
Create a donut chart from the input data
Args:
data (list): List of dictionaries with 'category' and 'value' keys
Returns:
io.BytesIO: Buffer containing the donut chart image
"""
plt.figure(figsize=(10, 6))

values = [item["value"] for item in data]
labels = [item["category"] for item in data]

default_colors = [
"#4CAF50", # Green for Compliant
"#FFC107", # Amber for Partially Compliant
"#F44336", # Red for Non-Compliant
"#9C27B0", # Purple for Not Applicable
"#2196F3", # Blue for Not Assessed
]

# Use provided colors or fall back to default
plot_colors = colors if colors is not None else default_colors[: len(values)]
plt.pie(
values,
labels=labels,
colors=plot_colors,
autopct="%1.f%%", # Show percentage
startangle=90,
pctdistance=0.85, # Distance of percentage from the center
wedgeprops={"edgecolor": "white", "linewidth": 1},
)

center_circle = plt.Circle((0, 0), 0.60, fc="white", ec="white")
fig = plt.gcf()
fig.gca().add_artist(center_circle)

plt.axis("equal") # Equal aspect ratio ensures that pie is drawn as a circle
plt.tight_layout()

chart_buffer = io.BytesIO()
plt.savefig(chart_buffer, format="png", dpi=300)
chart_buffer.seek(0)
plt.close()

return chart_buffer


def gen_audit_context(id, doc):
context = dict()
audit = ComplianceAssessment.objects.get(id=id)

authors = ", ".join([a.email for a in audit.authors.all()])
reviewers = ", ".join([a.email for a in audit.reviewers.all()])

cnt_per_result = audit.get_requirements_result_count()
ic(cnt_per_result)
total = sum([res[0] for res in cnt_per_result])
perc_res = [
ceil((res[0] / total) * 100) if total > 0 else 0 for res in cnt_per_result

donut_data = [
{"category": "Conforme", "value": cnt_per_result[3][0]},
{"category": "Partiellement conforme", "value": cnt_per_result[1][0]},
{"category": "Non conforme", "value": cnt_per_result[2][0]},
{"category": "Non applicable", "value": cnt_per_result[4][0]},
{"category": "Non évalué", "value": cnt_per_result[0][0]},
]
ic(perc_res)

res_donut = InlineImage(doc, plot_donut(donut_data), width=Cm(15))

context = {
"name": audit.name,
"framework": audit.framework.name,
"date": now().strftime("%Y-%m-%d %H:%M"),
"audit": audit,
"date": now().strftime("%d/%m/%Y"),
"contributors": f"{authors}\n{reviewers}",
"description": audit.description,
"domain": audit.project,
"observation": audit.observation,
"req": {
"total": total,
"compliant": cnt_per_result[3][0],
"part_compliant": cnt_per_result[1][0],
"non_compliant": cnt_per_result[2][0],
"not_applicable": cnt_per_result[4][0],
"not_assessed": cnt_per_result[0][0],
"compliant_p": perc_res[3],
"part_compliant_p": perc_res[1],
"non_compliant_p": perc_res[2],
"not_applicable_p": perc_res[4],
"not_assessed_p": perc_res[0],
},
"chart_progress_donut": res_donut,
}

return context
Binary file modified backend/core/templates/core/audit_report_template.docx
Binary file not shown.
2 changes: 1 addition & 1 deletion backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2166,7 +2166,7 @@ def word_report(self, request, pk):
/ "audit_report_template.docx"
)
doc = DocxTemplate(template_path)
context = gen_audit_context(pk)
context = gen_audit_context(pk, doc)
doc.render(context)
buffer_doc = io.BytesIO()
doc.save(buffer_doc)
Expand Down

0 comments on commit d5f52dd

Please sign in to comment.