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 json
import math
from calendar import Calendar, SUNDAY from calendar import Calendar, SUNDAY
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from datetime import date, datetime, time, timedelta 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.opengraph import generate_opengraph
from judge.utils.problems import _get_result_data from judge.utils.problems import _get_result_data
from judge.utils.ranker import ranker 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 from judge.utils.views import DiggPaginatorMixin, SingleObjectFormView, TitleMixin, generic_message
__all__ = ['ContestList', 'ContestDetail', 'ContestRanking', 'ContestJoin', 'ContestLeave', 'ContestCalendar', __all__ = ['ContestList', 'ContestDetail', 'ContestRanking', 'ContestJoin', 'ContestLeave', 'ContestCalendar',
@ -524,6 +525,7 @@ class CachedContestCalendar(ContestCalendar):
class ContestStats(TitleMixin, ContestMixin, DetailView): class ContestStats(TitleMixin, ContestMixin, DetailView):
template_name = 'contest/stats.html' template_name = 'contest/stats.html'
POINT_BIN = 10 # in point distribution
def get_title(self): def get_title(self):
return _('%s Statistics') % self.object.name 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']: for category in _get_result_data(defaultdict(int, status_counts[i]))['categories']:
result_data[category['code']][i] = category['count'] 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 = { stats = {
'problem_status_count': { 'problem_status_count': {
'labels': labels, 'labels': labels,
@ -574,6 +591,9 @@ class ContestStats(TitleMixin, ContestMixin, DetailView):
queryset.values('contest__problem__order', 'problem__name').annotate(ac_rate=ac_rate) queryset.values('contest__problem__order', 'problem__name').annotate(ac_rate=ac_rate)
.order_by('contest__problem__order').values_list('problem__name', '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( 'language_count': get_pie_chart(
queryset.values('language__name').annotate(count=Count('language__name')) queryset.values('language__name').annotate(count=Count('language__name'))
.filter(count__gt=0).order_by('-count').values_list('language__name', 'count'), .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['stats'] = mark_safe(json.dumps(stats))
context['problems'] = labels
return context return context

View file

@ -18,9 +18,22 @@
$(function () { $(function () {
draw_stacked_bar_chart(window.stats.problem_status_count, $('#problem-status-count')); draw_stacked_bar_chart(window.stats.problem_status_count, $('#problem-status-count'));
draw_bar_chart(window.stats.problem_ac_rate, $('#problem-ac-rate')); 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_pie_chart(window.stats.language_count, $('#language-count'));
draw_bar_chart(window.stats.language_ac_rate, $('#language-ac-rate')); 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> </script>
{% endcompress %} {% endcompress %}
{% include "contest/media-js.html" %} {% include "contest/media-js.html" %}
@ -45,6 +58,21 @@
<canvas></canvas> <canvas></canvas>
</div> </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> <h3>{{ _('Submissions by Language') }}</h3>
<div id="language-count" class="chart"> <div id="language-count" class="chart">
<canvas width="400" height="300"></canvas> <canvas width="400" height="300"></canvas>

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> </script>