Add problem point distribution
This commit is contained in:
parent
8ac611f9f4
commit
04a20626b8
4 changed files with 87 additions and 2 deletions
|
@ -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)),
|
||||
},
|
||||
],
|
||||
}
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue