2022-09-24 17:29:56 +00:00
|
|
|
from base64 import b64encode
|
|
|
|
from io import BytesIO
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
from flask_login import current_user
|
|
|
|
from matplotlib.figure import Figure
|
|
|
|
from matplotlib.ticker import MaxNLocator
|
|
|
|
from sqlalchemy import select
|
|
|
|
|
|
|
|
from .models import MAX_MARK, MIN_MARK, Assistant, Semester, User, db
|
|
|
|
|
|
|
|
|
|
|
|
def html_fig(fig):
|
|
|
|
buf = BytesIO()
|
|
|
|
fig.savefig(buf, format="png")
|
|
|
|
|
|
|
|
return b64encode(buf.getbuffer()).decode("ascii")
|
|
|
|
|
|
|
|
|
|
|
|
def mark_hist(data, title):
|
|
|
|
fig = Figure()
|
|
|
|
ax = fig.subplots()
|
|
|
|
ax.set_xlim(MIN_MARK - 0.5, MAX_MARK + 0.5)
|
|
|
|
ax.set_xticks(np.arange(MAX_MARK + 1))
|
|
|
|
# Only integer ticks
|
|
|
|
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
|
|
|
|
ax.set_xlabel("Mark")
|
|
|
|
|
|
|
|
N = data.size
|
|
|
|
title += f"\nN = {N}"
|
|
|
|
|
|
|
|
if N > 0:
|
|
|
|
ax.hist(
|
|
|
|
data,
|
|
|
|
bins=np.arange(MAX_MARK + 2) - 0.5,
|
|
|
|
)
|
|
|
|
title += f" | mean = {round(np.mean(data), 1)}"
|
|
|
|
|
|
|
|
ax.set_title(title)
|
|
|
|
|
|
|
|
return html_fig(fig)
|
|
|
|
|
|
|
|
|
|
|
|
def get_experiment_marks(assistant, attr):
|
|
|
|
data = []
|
|
|
|
|
|
|
|
for experiment_mark in assistant.experiment_marks:
|
|
|
|
mark = getattr(experiment_mark, attr)
|
|
|
|
if mark is not None:
|
|
|
|
data.append(mark)
|
|
|
|
|
|
|
|
return np.array(data)
|
|
|
|
|
|
|
|
|
|
|
|
def mark_hists(markType, active_assistants):
|
|
|
|
attr = markType.lower() + "_mark"
|
|
|
|
mark_type_title_addition = f" | {markType} marks"
|
|
|
|
marks = [get_experiment_marks(assistant, attr) for assistant in active_assistants]
|
|
|
|
|
|
|
|
hists = [
|
|
|
|
mark_hist(
|
|
|
|
data=marks[i],
|
|
|
|
title=str(active_assistants[i]) + mark_type_title_addition,
|
|
|
|
)
|
|
|
|
for i in range(len(marks))
|
|
|
|
]
|
|
|
|
|
|
|
|
hists.append(
|
|
|
|
mark_hist(
|
|
|
|
data=np.hstack(marks),
|
|
|
|
title="All" + mark_type_title_addition,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
return hists
|
|
|
|
|
|
|
|
|
|
|
|
def assistant_marks_analysis(cls):
|
2023-11-02 17:09:10 +00:00
|
|
|
active_assistants = db.session.scalars(select(Assistant).join(User).where(User.active is True)).all()
|
2022-09-24 17:29:56 +00:00
|
|
|
|
|
|
|
oral_mark_hists = mark_hists("Oral", active_assistants)
|
|
|
|
protocol_mark_hists = mark_hists("Protocol", active_assistants)
|
|
|
|
|
|
|
|
return cls.render(
|
|
|
|
"analysis/assistant_marks.jinja.html",
|
|
|
|
hist_indices=range(len(oral_mark_hists)),
|
|
|
|
oral_mark_hists=oral_mark_hists,
|
|
|
|
protocol_mark_hists=protocol_mark_hists,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def get_final_part_marks(part):
|
|
|
|
data = []
|
|
|
|
|
|
|
|
for part_student in part.part_students:
|
|
|
|
mark = part_student.final_part_mark
|
|
|
|
if mark is not None:
|
|
|
|
data.append(mark)
|
|
|
|
|
|
|
|
return np.array(data)
|
|
|
|
|
|
|
|
|
|
|
|
def final_part_marks_analysis(cls):
|
|
|
|
parts = current_user.active_semester.parts
|
|
|
|
|
|
|
|
active_semester_final_part_marks_hists = [
|
|
|
|
mark_hist(
|
|
|
|
data=get_final_part_marks(part),
|
|
|
|
title=part.str(),
|
|
|
|
)
|
|
|
|
for part in parts
|
|
|
|
]
|
|
|
|
|
|
|
|
semesters = db.session.scalars(select(Semester)).all()
|
|
|
|
mean_final_part_marks = np.array(
|
|
|
|
[np.mean(np.hstack([get_final_part_marks(part) for part in semester.parts])) for semester in semesters]
|
|
|
|
)
|
|
|
|
|
|
|
|
fig = Figure()
|
|
|
|
len_mean_final_part_marks = mean_final_part_marks.size
|
|
|
|
|
|
|
|
ax = fig.subplots()
|
|
|
|
x = range(len_mean_final_part_marks)
|
|
|
|
ax.plot(
|
|
|
|
x,
|
|
|
|
mean_final_part_marks,
|
|
|
|
marker="d",
|
|
|
|
)
|
|
|
|
ax.set_xticks(x, [semester.str() for semester in semesters])
|
|
|
|
|
|
|
|
ax.set_xlabel("Semester")
|
|
|
|
ax.set_ylabel("Mean final experiment mark")
|
|
|
|
|
|
|
|
ax.set_title("Mean final experiment mark over all semesters")
|
|
|
|
|
|
|
|
mean_final_part_mark_plot = html_fig(fig)
|
|
|
|
|
|
|
|
return cls.render(
|
|
|
|
"analysis/final_part_marks.jinja.html",
|
|
|
|
active_semester_final_part_marks_hists=active_semester_final_part_marks_hists,
|
|
|
|
mean_final_part_mark_plot=mean_final_part_mark_plot,
|
|
|
|
)
|