Add problem point distribution

This commit is contained in:
cuom1999 2021-06-01 19:20:39 -05:00
parent 8ac611f9f4
commit 04a20626b8
4 changed files with 87 additions and 2 deletions

View file

@ -51,3 +51,18 @@ def get_bar_chart(data, **kwargs):
},
],
}
def get_histogram(data, **kwargs):
return {
'labels': [round(i, 1) for i in list(map(itemgetter(0), data))],
'datasets': [
{
'backgroundColor': kwargs.get('fillColor', 'rgba(151,187,205,0.5)'),
'borderColor': kwargs.get('strokeColor', 'rgba(151,187,205,0.8)'),
'borderWidth': 1,
'hoverBackgroundColor': kwargs.get('highlightFill', 'rgba(151,187,205,0.75)'),
'hoverBorderColor': kwargs.get('highlightStroke', 'rgba(151,187,205,1)'),
'data': list(map(itemgetter(1), data)),
},
],
}

View file

@ -1,4 +1,5 @@
import json
import math
from calendar import Calendar, SUNDAY
from collections import defaultdict, namedtuple
from datetime import date, datetime, time, timedelta
@ -37,7 +38,7 @@ from judge.utils.celery import redirect_to_task_status
from judge.utils.opengraph import generate_opengraph
from judge.utils.problems import _get_result_data
from judge.utils.ranker import ranker
from judge.utils.stats import get_bar_chart, get_pie_chart
from judge.utils.stats import get_bar_chart, get_pie_chart, get_histogram
from judge.utils.views import DiggPaginatorMixin, SingleObjectFormView, TitleMixin, generic_message
__all__ = ['ContestList', 'ContestDetail', 'ContestRanking', 'ContestJoin', 'ContestLeave', 'ContestCalendar',
@ -524,6 +525,7 @@ class CachedContestCalendar(ContestCalendar):
class ContestStats(TitleMixin, ContestMixin, DetailView):
template_name = 'contest/stats.html'
POINT_BIN = 10 # in point distribution
def get_title(self):
return _('%s Statistics') % self.object.name
@ -558,6 +560,21 @@ class ContestStats(TitleMixin, ContestMixin, DetailView):
for category in _get_result_data(defaultdict(int, status_counts[i]))['categories']:
result_data[category['code']][i] = category['count']
problem_points = [[] for _ in range(num_problems)]
point_count = queryset.values('contest__problem__order', 'contest__points')\
.annotate(count=Count('contest__points')) \
.filter(points__isnull=False) \
.order_by('contest__problem__order', 'contest__points')
counter = [[0 for _ in range(self.POINT_BIN + 1)] for _ in range(num_problems)]
for sub in point_count.iterator():
problem_idx = sub['contest__problem__order'] - 1
bin_idx = math.floor(sub['contest__points'] * self.POINT_BIN / 100)
counter[problem_idx][bin_idx] += sub['count']
for i in range(num_problems):
problem_points[i] = [(j * 100 / self.POINT_BIN, counter[i][j])
for j in range(len(counter[i]))]
stats = {
'problem_status_count': {
'labels': labels,
@ -574,6 +591,9 @@ class ContestStats(TitleMixin, ContestMixin, DetailView):
queryset.values('contest__problem__order', 'problem__name').annotate(ac_rate=ac_rate)
.order_by('contest__problem__order').values_list('problem__name', 'ac_rate'),
),
'problem_point': [get_histogram(problem_points[i])
for i in range(num_problems)
],
'language_count': get_pie_chart(
queryset.values('language__name').annotate(count=Count('language__name'))
.filter(count__gt=0).order_by('-count').values_list('language__name', 'count'),
@ -585,7 +605,7 @@ class ContestStats(TitleMixin, ContestMixin, DetailView):
}
context['stats'] = mark_safe(json.dumps(stats))
context['problems'] = labels
return context

View file

@ -18,9 +18,22 @@
$(function () {
draw_stacked_bar_chart(window.stats.problem_status_count, $('#problem-status-count'));
draw_bar_chart(window.stats.problem_ac_rate, $('#problem-ac-rate'));
pts_hist = draw_histogram(window.stats.problem_point[0], $('#problem-point'));
draw_pie_chart(window.stats.language_count, $('#language-count'));
draw_bar_chart(window.stats.language_ac_rate, $('#language-ac-rate'));
$('#problem-point-select').change(function() {
pts_hist.destroy();
problem = $(this).val();
pts_hist = draw_histogram(window.stats.problem_point[problem],
$('#problem-point'));
})
$('#problem-point-select').select2({
width: '10em',
});
});
</script>
{% endcompress %}
{% include "contest/media-js.html" %}
@ -44,6 +57,21 @@
<div id="problem-ac-rate" class="chart">
<canvas></canvas>
</div>
<h3>
{{ _('Problem Point Distribution') }}:
<select id="problem-point-select">
{% for name in problems %}
<option value="{{ loop.index0 }}" class="point-dropdown">
{{ name }}
</option>
{% endfor %}
</select>
</h3>
<div id="problem-point" class="chart">
<canvas></canvas>
</div>
<h3>{{ _('Submissions by Language') }}</h3>
<div id="language-count" class="chart">

View file

@ -65,4 +65,26 @@
},
});
}
function draw_histogram(data, $chart) {
var ctx = $chart.find('canvas')[0].getContext('2d');
ctx.canvas.height = 20 * data.labels.length + 100;
var chart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return tooltipItem.value;
},
},
},
},
});
return chart;
}
</script>