Change lang stat page
This commit is contained in:
parent
fa8c683439
commit
fe5e7198ee
5 changed files with 90 additions and 112 deletions
22
dmoj/urls.py
22
dmoj/urls.py
|
@ -886,27 +886,7 @@ urlpatterns = [
|
||||||
"^language/",
|
"^language/",
|
||||||
include(
|
include(
|
||||||
[
|
[
|
||||||
url("^$", stats.language, name="language_stats"),
|
url("^$", stats.StatLanguage.as_view(), name="language_stats"),
|
||||||
url(
|
|
||||||
"^data/all/$",
|
|
||||||
stats.language_data,
|
|
||||||
name="language_stats_data_all",
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
"^data/ac/$",
|
|
||||||
stats.ac_language_data,
|
|
||||||
name="language_stats_data_ac",
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
"^data/status/$",
|
|
||||||
stats.status_data,
|
|
||||||
name="stats_data_status",
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
"^data/ac_rate/$",
|
|
||||||
stats.ac_rate,
|
|
||||||
name="language_stats_data_ac_rate",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from itertools import chain, repeat
|
from itertools import chain, repeat
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
import json
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Case, Count, FloatField, IntegerField, Value, When
|
from django.db.models import Case, Count, FloatField, IntegerField, Value, When
|
||||||
|
@ -7,6 +8,9 @@ from django.db.models.expressions import CombinedExpression
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
from django.http import Http404
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from judge.models import Language, Submission
|
from judge.models import Language, Submission
|
||||||
from judge.utils.stats import (
|
from judge.utils.stats import (
|
||||||
|
@ -17,86 +21,88 @@ from judge.utils.stats import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
ac_count = Count(
|
class StatViewBase(TemplateView):
|
||||||
Case(When(submission__result="AC", then=Value(1)), output_field=IntegerField())
|
def get(self, request, *args, **kwargs):
|
||||||
)
|
if not request.user.is_superuser:
|
||||||
|
raise Http404
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def repeat_chain(iterable):
|
class StatLanguage(StatViewBase):
|
||||||
return chain.from_iterable(repeat(iterable))
|
template_name = "stats/language.html"
|
||||||
|
ac_count = Count(
|
||||||
|
Case(When(submission__result="AC", then=Value(1)), output_field=IntegerField())
|
||||||
def language_data(
|
|
||||||
request, language_count=Language.objects.annotate(count=Count("submission"))
|
|
||||||
):
|
|
||||||
languages = (
|
|
||||||
language_count.filter(count__gt=0)
|
|
||||||
.values("key", "name", "count")
|
|
||||||
.order_by("-count")
|
|
||||||
)
|
|
||||||
num_languages = min(len(languages), settings.DMOJ_STATS_LANGUAGE_THRESHOLD)
|
|
||||||
other_count = sum(map(itemgetter("count"), languages[num_languages:]))
|
|
||||||
|
|
||||||
return JsonResponse(
|
|
||||||
{
|
|
||||||
"labels": list(map(itemgetter("name"), languages[:num_languages]))
|
|
||||||
+ ["Other"],
|
|
||||||
"datasets": [
|
|
||||||
{
|
|
||||||
"backgroundColor": chart_colors[:num_languages] + ["#FDB45C"],
|
|
||||||
"highlightBackgroundColor": highlight_colors[:num_languages]
|
|
||||||
+ ["#FFC870"],
|
|
||||||
"data": list(map(itemgetter("count"), languages[:num_languages]))
|
|
||||||
+ [other_count],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
safe=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def repeat_chain(iterable):
|
||||||
|
return chain.from_iterable(repeat(iterable))
|
||||||
|
|
||||||
def ac_language_data(request):
|
def language_data(
|
||||||
return language_data(request, Language.objects.annotate(count=ac_count))
|
self, language_count=Language.objects.annotate(count=Count("submission"))
|
||||||
|
):
|
||||||
|
languages = (
|
||||||
def status_data(request, statuses=None):
|
language_count.filter(count__gt=0)
|
||||||
if not statuses:
|
.values("key", "name", "count")
|
||||||
statuses = (
|
|
||||||
Submission.objects.values("result")
|
|
||||||
.annotate(count=Count("result"))
|
|
||||||
.values("result", "count")
|
|
||||||
.order_by("-count")
|
.order_by("-count")
|
||||||
)
|
)
|
||||||
data = []
|
num_languages = min(len(languages), settings.DMOJ_STATS_LANGUAGE_THRESHOLD)
|
||||||
for status in statuses:
|
other_count = sum(map(itemgetter("count"), languages[num_languages:]))
|
||||||
res = status["result"]
|
|
||||||
if not res:
|
|
||||||
continue
|
|
||||||
count = status["count"]
|
|
||||||
data.append((str(Submission.USER_DISPLAY_CODES[res]), count))
|
|
||||||
|
|
||||||
return JsonResponse(get_pie_chart(data), safe=False)
|
return {
|
||||||
|
"labels": list(map(itemgetter("name"), languages[:num_languages]))
|
||||||
|
+ ["Other"],
|
||||||
|
"datasets": [
|
||||||
|
{
|
||||||
|
"backgroundColor": chart_colors[:num_languages] + ["#FDB45C"],
|
||||||
|
"highlightBackgroundColor": highlight_colors[:num_languages]
|
||||||
|
+ ["#FFC870"],
|
||||||
|
"data": list(map(itemgetter("count"), languages[:num_languages]))
|
||||||
|
+ [other_count],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def ac_language_data(self):
|
||||||
|
return self.language_data(Language.objects.annotate(count=self.ac_count))
|
||||||
|
|
||||||
|
def status_data(self, statuses=None):
|
||||||
|
if not statuses:
|
||||||
|
statuses = (
|
||||||
|
Submission.objects.values("result")
|
||||||
|
.annotate(count=Count("result"))
|
||||||
|
.values("result", "count")
|
||||||
|
.order_by("-count")
|
||||||
|
)
|
||||||
|
data = []
|
||||||
|
for status in statuses:
|
||||||
|
res = status["result"]
|
||||||
|
if not res:
|
||||||
|
continue
|
||||||
|
count = status["count"]
|
||||||
|
data.append((str(Submission.USER_DISPLAY_CODES[res]), count))
|
||||||
|
|
||||||
|
return get_pie_chart(data)
|
||||||
|
|
||||||
|
|
||||||
def ac_rate(request):
|
def ac_rate(self):
|
||||||
rate = CombinedExpression(
|
rate = CombinedExpression(
|
||||||
ac_count / Count("submission"), "*", Value(100.0), output_field=FloatField()
|
self.ac_count / Count("submission"), "*", Value(100.0), output_field=FloatField()
|
||||||
)
|
)
|
||||||
data = (
|
data = (
|
||||||
Language.objects.annotate(total=Count("submission"), ac_rate=rate)
|
Language.objects.annotate(total=Count("submission"), ac_rate=rate)
|
||||||
.filter(total__gt=0)
|
.filter(total__gt=0)
|
||||||
.order_by("total")
|
.order_by("total")
|
||||||
.values_list("name", "ac_rate")
|
.values_list("name", "ac_rate")
|
||||||
)
|
)
|
||||||
return JsonResponse(get_bar_chart(list(data)))
|
return get_bar_chart(list(data))
|
||||||
|
|
||||||
|
|
||||||
def language(request):
|
def get_context_data(self, **kwargs):
|
||||||
return render(
|
context = super().get_context_data(**kwargs)
|
||||||
request,
|
context["title"] = _("Language statistics")
|
||||||
"stats/language.html",
|
context["tab"] = "language"
|
||||||
{
|
context["data_all"] = mark_safe(json.dumps(self.language_data()))
|
||||||
"title": _("Language statistics"),
|
context["lang_ac"] = mark_safe(json.dumps(self.ac_language_data()))
|
||||||
"tab": "language",
|
context["status_counts"] = mark_safe(json.dumps(self.status_data()))
|
||||||
},
|
context["ac_rate"] = mark_safe(json.dumps(self.ac_rate()))
|
||||||
)
|
return context
|
|
@ -6,13 +6,10 @@
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_title %}{{ _('Statistics') }}{% endblock %}
|
{% block content_title %}{% endblock %}
|
||||||
|
{% block title_ruler %}{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="tabs">
|
{% include "stats/tab.html" %}
|
||||||
<li{% if tab == 'language' %} class="active"{% endif %}>
|
|
||||||
<a href="{{ url('language_stats') }}">{{ _('Language') }}</a>
|
|
||||||
</li>
|
|
||||||
</div>
|
|
||||||
{% block chart_body %}{% endblock %}
|
{% block chart_body %}{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -36,20 +36,10 @@
|
||||||
Chart.defaults.global.tooltipFontFamily =
|
Chart.defaults.global.tooltipFontFamily =
|
||||||
Chart.defaults.global.tooltipTitleFontFamily =
|
Chart.defaults.global.tooltipTitleFontFamily =
|
||||||
$('body').css('font-family');
|
$('body').css('font-family');
|
||||||
|
draw_pie_chart({{ data_all }}, $('#lang-all'));
|
||||||
function pie_chart(url, $chart) {
|
draw_pie_chart({{ lang_ac }}, $('#lang-ac'));
|
||||||
$.getJSON(url, function (data) {
|
draw_pie_chart({{ status_counts }}, $('#status-counts'));
|
||||||
draw_pie_chart(data, $chart);
|
draw_bar_chart({{ ac_rate }}, $('#ac-rate'));
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pie_chart('{{ url('language_stats_data_all') }}', $('#lang-all'));
|
|
||||||
pie_chart('{{ url('language_stats_data_ac') }}', $('#lang-ac'));
|
|
||||||
pie_chart('{{ url('stats_data_status') }}', $('#status-counts'));
|
|
||||||
|
|
||||||
$.getJSON('{{ url('language_stats_data_ac_rate') }}', function (data) {
|
|
||||||
draw_bar_chart(data, $('#ac-rate'));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
5
templates/stats/tab.html
Normal file
5
templates/stats/tab.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "tabs-base.html" %}
|
||||||
|
|
||||||
|
{% block tabs %}
|
||||||
|
{{ make_tab('language', 'fa-list', url('language_stats'), _('Language')) }}
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue