.
This commit is contained in:
@@ -762,3 +762,6 @@ class CidReportAnswer(models.Model):
|
||||
def clean(self):
|
||||
if self.answer:
|
||||
self.answer = self.answer.strip()
|
||||
|
||||
def get_answer_score(self):
|
||||
return self.score
|
||||
@@ -0,0 +1,80 @@
|
||||
{% extends 'atlas/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div id="stats-plot">{{plot|safe}}</div>
|
||||
<div class="atlas">
|
||||
<h2>{{ exam.name }}</h2>
|
||||
|
||||
{% if unmarked %}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
The following questions need marking
|
||||
{% for exam_index in unmarked %}
|
||||
<a href="{% url 'atlas:mark' exam.pk exam_index %}">{{ exam_index|add:1 }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div id="stats-block">
|
||||
<h3>Stats</h3>
|
||||
Candidates: {{cids|length}}<br />
|
||||
Max score: {{max_score}}<br />
|
||||
Mean: {{mean}}, Median {{median}}, Mode {{mode}}
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<table class="table table-dark table-striped table-hover table-sm cid-score-table">
|
||||
<tr>
|
||||
<th>Candidate ID</th>
|
||||
<th>Score</th>
|
||||
{% comment %} <th>Normalised Score</th> {% endcomment %}
|
||||
</tr>
|
||||
{% comment %} {% for user, value in user_answers_marks.items %} {% endcomment %}
|
||||
{% for cid in cids %}
|
||||
<tr>
|
||||
<td><a href="{% url 'cid_scores_admin' cid %}">{{cid}}</a></td>
|
||||
<td>{{user_scores|get_item:cid}}</td>
|
||||
{% comment %} <td>{{user_scores_normalised|get_item:user}}</td> {% endcomment %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Answers as a table</h3>
|
||||
<table class="table table-dark table-striped table-hover table-sm col-sm">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Candidate</th>
|
||||
{% for cid in cids %}
|
||||
<th><a href="{% url 'atlas:exam_scores_cid_user' exam.pk cid 'None' %}">{{cid}}</a></th>
|
||||
{% comment %} <th><a href="">{{cid}}</a></th> {% endcomment %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
{% for question in questions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'atlas:mark' exam_pk=exam.pk sk=forloop.counter0 %}">Question {{forloop.counter}}</a>
|
||||
</td>
|
||||
{% comment %} {% for cid in cids %}
|
||||
<td class="atlas-ans user-answer-score-{{score_by_question|get_item:question|get_item:cid}}" title="answer score: {{score_by_question|get_item:question|get_item:cid}}">{{ans_by_question|get_item:question|get_item:cid}}</td>
|
||||
{% endfor %} {% endcomment %}
|
||||
{% for cid in cids %}
|
||||
{% with by_question|get_item:question|get_item:cid as ans_score %}
|
||||
<td class="atlas-ans user-answer-score-{{ans_score.1}}" title="answer score: {{ans_score.1}}">{{ans_score.0}}</td>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>Score:</td>
|
||||
{% for cid in cids %}
|
||||
<td>{{user_scores|get_item:cid}}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
+145
-9
@@ -1169,7 +1169,7 @@ def collection_mark_question(request, pk, case_number):
|
||||
return redirect(
|
||||
"atlas:collection_mark_question",
|
||||
case_number=int(request.POST.get("goto")),
|
||||
**kwargs
|
||||
**kwargs,
|
||||
)
|
||||
else:
|
||||
for answer in answers:
|
||||
@@ -1195,13 +1195,6 @@ def collection_mark_question(request, pk, case_number):
|
||||
)
|
||||
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_scores_cid(request, pk):
|
||||
collection = get_object_or_404(CaseCollection, pk=pk)
|
||||
|
||||
return render(request, "atlas/collection_take.html", {"collection": collection})
|
||||
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_candidates(request, pk):
|
||||
collection = get_object_or_404(CaseCollection, pk=pk)
|
||||
@@ -1324,7 +1317,7 @@ def collection_case_view_take(request, pk, case_number, cid, passcode):
|
||||
return redirect(
|
||||
"atlas:collection_case_view_take",
|
||||
case_number=int(request.POST.get("goto")),
|
||||
**kwargs
|
||||
**kwargs,
|
||||
)
|
||||
else:
|
||||
form = CidReportAnswerForm(instance=answer)
|
||||
@@ -1404,3 +1397,146 @@ def collection_case_view(request, pk, case_number):
|
||||
"answer": answer,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_scores_cid(request, pk):
|
||||
collection = get_object_or_404(CaseCollection, pk=pk)
|
||||
|
||||
if not collection.exam_mode:
|
||||
raise Http404("Collection not in exam mode")
|
||||
|
||||
user_answers_and_marks = defaultdict(list)
|
||||
user_answers_marks = defaultdict(list)
|
||||
user_answers = defaultdict(list)
|
||||
user_names = {}
|
||||
# cid_passcodes = {}
|
||||
|
||||
by_question = defaultdict(dict)
|
||||
unmarked = set()
|
||||
|
||||
cases = collection.cases.all().order_by("casedetail__sort_order").prefetch_related()
|
||||
|
||||
case_details = CaseDetail.objects.filter(
|
||||
case__in=cases, collection=collection
|
||||
).prefetch_related("case")
|
||||
|
||||
cid_user_answers = CidReportAnswer.objects.filter(question__in=case_details)
|
||||
|
||||
# questions = exam.exam_questions.all().prefetch_related("answers")
|
||||
|
||||
# cid_user_answers = CidReportAnswer.objects.select_related("question").filter(
|
||||
# question__in=questions, exam__id=pk
|
||||
# )
|
||||
|
||||
cids = set()
|
||||
|
||||
# Loop through all candidates
|
||||
for cid_user_answer in cid_user_answers:
|
||||
# Convoluted (probably...)
|
||||
cid = cid_user_answer.cid
|
||||
# cid_passcodes[cid] = cid_user_answer.passcode
|
||||
cids.add(cid)
|
||||
s = cid_user_answer
|
||||
user_names[cid] = cid
|
||||
|
||||
q = cid_user_answer.question
|
||||
|
||||
# if not s:
|
||||
# # skip if no answer
|
||||
# user_answers_marks[cid].append(0)
|
||||
# user_answers[cid].append("")
|
||||
# by_question[q].append(("", 0))
|
||||
# continue
|
||||
|
||||
ans = s.answer
|
||||
|
||||
answer_score = s.get_answer_score()
|
||||
if answer_score == "unmarked":
|
||||
index = cases.index(q)
|
||||
unmarked.add(index)
|
||||
user_answers[cid].append(ans)
|
||||
user_answers_marks[cid].append(answer_score)
|
||||
user_answers_and_marks[cid].append((ans, answer_score))
|
||||
|
||||
by_question[q][cid] = (ans, answer_score)
|
||||
|
||||
user_scores = {}
|
||||
user_scores_normalised = {}
|
||||
for user in user_answers_marks:
|
||||
|
||||
user_scores[user] = sum(
|
||||
[i for i in user_answers_marks[user] if i != "unmarked"]
|
||||
)
|
||||
|
||||
user_scores_normalised[user] = user_scores[user]
|
||||
|
||||
# ignore scores of 0 for stats
|
||||
user_scores_list = [i for i in user_scores.values() if i > 0]
|
||||
|
||||
max_score = len(cases)
|
||||
|
||||
if len(user_scores_list) < 1:
|
||||
mean = 0
|
||||
median = 0
|
||||
mode = 0
|
||||
fig_html = ""
|
||||
else:
|
||||
mean = statistics.mean(user_scores_list)
|
||||
median = statistics.median(user_scores_list)
|
||||
try:
|
||||
mode = statistics.mode(user_scores_list)
|
||||
except statistics.StatisticsError:
|
||||
mode = "No unique mode"
|
||||
|
||||
df = user_scores_list
|
||||
fig = px.histogram(
|
||||
df,
|
||||
x=0,
|
||||
title="{}: distribution of scores".format(collection),
|
||||
labels={"0": "Score"},
|
||||
height=400,
|
||||
width=600,
|
||||
)
|
||||
fig_html = fig.to_html()
|
||||
|
||||
collection.stats_mean = mean
|
||||
collection.stats_median = median
|
||||
collection.stats_mode = mode
|
||||
|
||||
collection.stats_candidates = len(user_scores_list)
|
||||
collection.stats_max_possible = max_score
|
||||
|
||||
collection.stats_min = min(user_scores_list)
|
||||
collection.stats_max = max(user_scores_list)
|
||||
|
||||
collection.stats_graph = fig_html
|
||||
|
||||
collection.user_scores = user_scores
|
||||
|
||||
collection.save()
|
||||
|
||||
return render(
|
||||
request,
|
||||
f"atlas/collection_scores.html",
|
||||
{
|
||||
"cids": sorted(cids),
|
||||
# "cid_passcodes": cid_passcodes,
|
||||
"exam": collection,
|
||||
"unmarked": unmarked,
|
||||
"questions": cases,
|
||||
"by_question": by_question,
|
||||
"user_answers": dict(user_answers),
|
||||
"user_answers_marks": dict(user_answers_marks),
|
||||
"user_scores": user_scores,
|
||||
"user_scores_normalised": user_scores_normalised,
|
||||
"user_scores_list": user_scores_list,
|
||||
"user_names": user_names,
|
||||
"user_answers_and_marks": user_answers_and_marks,
|
||||
"max_score": max_score,
|
||||
"mean": mean,
|
||||
"median": median,
|
||||
"mode": mode,
|
||||
"plot": fig_html,
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user