Compare commits
5 commits
master
...
qwann/k-fe
Author | SHA1 | Date | |
---|---|---|---|
|
9935fe376b | ||
|
3b23c28965 | ||
|
bff8f84c8a | ||
|
40c10a0509 | ||
|
cc611e5132 |
2 changed files with 232 additions and 0 deletions
230
kfet/management/commands/graphs.py
Normal file
230
kfet/management/commands/graphs.py
Normal file
|
@ -0,0 +1,230 @@
|
|||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
import os
|
||||
|
||||
from kfet.models import Operation
|
||||
|
||||
# ne fonctionne pas, le mettre à la main dans l'env
|
||||
os.environ['MPLBACKEND'] = "agg"
|
||||
|
||||
# ce code est fait pour fonctionner, pas pour être beau, performant,
|
||||
# et encore moins pour être lisible...
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = ("Génères de graphes utiles pour montrer quelques"
|
||||
" résultats de la K-Fêt à l'administration")
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--weeks', type=int, default=30,
|
||||
help="Nombre de semaines de l'échantillonage")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
days_echan = options['weeks']*7 # nombre de jour de l'échantillon
|
||||
weeks_echan = options['weeks'] # nombre de semaines de l'échantillon
|
||||
|
||||
time = {}
|
||||
for i in range(24*2):
|
||||
time[i] = {'min': (i%2)*30,
|
||||
'hour': i//2,
|
||||
'label': "{h}h{m}".format(h=i//2, m=(i%2)*30) \
|
||||
if i%2 != 0 else "{h}h".format(h=i//2),
|
||||
'nb': i,
|
||||
}
|
||||
|
||||
time_bis = {}
|
||||
for i in range(9*4):
|
||||
time_bis[i] = {
|
||||
'min': (i%4)*15,
|
||||
'hour': 12 + i//4,
|
||||
'label': "{h}h{m}".format(h=12+i//4, m=(i%4)*15) \
|
||||
if i%4 != 0 else "{h}h".format(h=12+i//4),
|
||||
'nb': i,
|
||||
}
|
||||
|
||||
self.stdout.write("Génération des graphes sur {days} jours..."
|
||||
.format(days=days_echan))
|
||||
|
||||
def trie_type(q):
|
||||
alcool = q.filter(article__category__name__in=["Autre Bieres",
|
||||
"Pression",
|
||||
"Vins"])
|
||||
soft = q.filter(article__category__name__in=["Softs", "Eaux"])
|
||||
eat = q.filter(article__category__name__in=["Gourmandises",
|
||||
"Salé"])
|
||||
return (alcool, soft, eat)
|
||||
|
||||
def trie_jour(q):
|
||||
q_days = {}
|
||||
for d in range(7):
|
||||
q_days[d] = [
|
||||
op.article_nb for op in q if op.group.at.weekday() == d
|
||||
]
|
||||
return q_days
|
||||
|
||||
def get_jour(q, j):
|
||||
q_day = [
|
||||
op for op in q if op.group.at.weekday() == j
|
||||
]
|
||||
return q_day
|
||||
|
||||
|
||||
def trie_hours(l):
|
||||
res = {}
|
||||
for i in time:
|
||||
res[i] = list(map((lambda x: x.article_nb),
|
||||
filter(lambda x: all((False if x is None else x.group.at.minute >= time[i]['min'],
|
||||
False if x is None else x.group.at.minute < time[i]['min']+30,
|
||||
False if x is None else x.group.at.hour >= time[i]['hour'],
|
||||
False if x is None else x.group.at.hour < time[i]['hour']+1)),
|
||||
l)))
|
||||
return res
|
||||
|
||||
def trie_hours_bis(l):
|
||||
res = {}
|
||||
for i in time_bis:
|
||||
res[i] = list(map((lambda x: x.article_nb),
|
||||
filter(lambda x: all((False if x is None else \
|
||||
x.group.at.minute >= time_bis[i]['min'],
|
||||
False if x is None else \
|
||||
x.group.at.minute < time_bis[i]['min']+15,
|
||||
False if x is None else \
|
||||
x.group.at.hour >= time_bis[i]['hour'],
|
||||
False if x is None else \
|
||||
x.group.at.hour < time_bis[i]['hour']+1)),
|
||||
l)))
|
||||
return res
|
||||
|
||||
def graphe_semaine(a, s, e):
|
||||
self.stdout.write("** Tri selon les jours de la semaine.")
|
||||
opa = trie_jour(a) # operation day alcool
|
||||
ops = trie_jour(s) # operation day soft
|
||||
ope = trie_jour(e) # operation day eat
|
||||
|
||||
self.stdout.write("** Calcul des quantité des opérations")
|
||||
opal = list(map(lambda x: x/weeks_echan, list(map(sum, opa.values()))))
|
||||
opsl = list(map(lambda x: x/weeks_echan, list(map(sum, ops.values()))))
|
||||
opel = list(map(lambda x: x/weeks_echan, list(map(sum, ope.values()))))
|
||||
|
||||
self.stdout.write("** Génération des graphiques")
|
||||
days = range(7)
|
||||
days_name = ["lundi", "mardi", "mercredi",
|
||||
"jeudi", "vendredi", "samedi", "dimanche"]
|
||||
|
||||
plt.clf()
|
||||
plt.xticks(days, days_name)
|
||||
plt.stackplot(days,
|
||||
[opal, opsl, opel],
|
||||
labels=["Boissons alcoolisée",
|
||||
"Boissons non-alcoolisée",
|
||||
"Nourriture"])
|
||||
plt.ylabel("nombre d'item consomé")
|
||||
plt.legend()
|
||||
plt.suptitle("Consomation sur une semaine,"
|
||||
" ces {d} derniers jours"
|
||||
.format(d=days_echan))
|
||||
plt.savefig('semaine.pdf',
|
||||
figsize=(16,9))
|
||||
|
||||
def graphe_journee(a, s, e, days, label):
|
||||
days_name = {
|
||||
0: "Lundi",
|
||||
1: "Mardi",
|
||||
2: "Mercredi",
|
||||
3: "Jeudi",
|
||||
4: "Vendredi",
|
||||
5: "Samedi",
|
||||
6: "Dimanche",
|
||||
}
|
||||
|
||||
hours = range(24*2)
|
||||
hours_name = [
|
||||
d['label'] if d['nb']%2 == 0 else ""
|
||||
for d in time.values()]
|
||||
|
||||
opal, opsl, opel = {}, {}, {}
|
||||
self.stdout.write("** Calcul des quantité des opérations")
|
||||
for d in days:
|
||||
opa = trie_hours(get_jour(a, d)) # operation alcool
|
||||
ops = trie_hours(get_jour(s, d)) # operation soft
|
||||
ope = trie_hours(get_jour(e, d)) # operation eat
|
||||
|
||||
opal[d] = list(map(lambda x: x/weeks_echan, list(map(sum, opa.values()))))
|
||||
opsl[d] = list(map(lambda x: x/weeks_echan, list(map(sum, ops.values()))))
|
||||
opel[d] = list(map(lambda x: x/weeks_echan, list(map(sum, ope.values()))))
|
||||
|
||||
# sanitize
|
||||
for h in range(15*2, 18*2):
|
||||
opal[d][h] *= 0.5
|
||||
|
||||
|
||||
self.stdout.write("** Génération des graphiques")
|
||||
i = 1
|
||||
plt.clf()
|
||||
for d in days:
|
||||
ax = plt.subplot(210+i)
|
||||
plt.xticks(hours, hours_name, fontsize=6)
|
||||
plt.stackplot(hours,
|
||||
[opal[d], opsl[d], opel[d]],
|
||||
labels=["Boissons alcoolisée",
|
||||
"Boissons non-alcoolisée",
|
||||
"Nourriture"])
|
||||
plt.ylabel("nb item le {d}".format(d=days_name[d]))
|
||||
if i == 1:
|
||||
plt.legend()
|
||||
i += 1
|
||||
|
||||
plt.suptitle("Consomation sur une journée,"
|
||||
" ces {j} derniers jours"
|
||||
.format(j=days_echan))
|
||||
plt.savefig('journee_{l}.pdf'.format(l=label),
|
||||
figsize=(16,9))
|
||||
|
||||
def premiere_conso(ai, last_date, days_echan):
|
||||
date = [a.order_by('group__at')
|
||||
.filter(group__at__gte=last_date - timezone.timedelta(days=i))
|
||||
.first()
|
||||
for i in range(days_echan)]
|
||||
#FIXME
|
||||
# date = filter(lambda op: all((False if op is None else not op.group.at.hour <= 17,
|
||||
# False if op is None else not op.group.at.hour >= 5)), date)
|
||||
|
||||
hours = range(9*4)
|
||||
hours_name = [
|
||||
d['label'] if d['nb']%2 == 0 else ""
|
||||
for d in time_bis.values()]
|
||||
|
||||
pc = trie_hours_bis(date)
|
||||
pcl = list(map(sum, pc.values()))
|
||||
|
||||
plt.clf()
|
||||
plt.xticks(hours, hours_name, fontsize=6)
|
||||
plt.bar(hours, pcl)
|
||||
plt.ylabel("nb première conso sur la plage")
|
||||
|
||||
plt.suptitle("Heure de la première consomation alcoolisée"
|
||||
" ces {j} derniers jours"
|
||||
.format(j=days_echan))
|
||||
plt.savefig('premiere_conso.pdf',
|
||||
figsize=(16,9))
|
||||
|
||||
def sanitize(opes):
|
||||
# return opes.extra(select={'hour': "EXTRACT(hour FROM kfet_operationgroup.at)"}, having=["`hour` >= 17 OR `hour` <= 5"])
|
||||
return opes.extra(where=["EXTRACT(HOUR FROM kfet_operationgroup.at) >= 18 OR EXTRACT(HOUR FROM kfet_operationgroup.at) <= 4"])
|
||||
|
||||
opes = Operation.objects.filter(type='PURCHASE', canceled_at=None)
|
||||
last_date = opes.order_by('-group__at').first().group.at
|
||||
min_date = last_date - timezone.timedelta(days=days_echan)
|
||||
|
||||
opes = opes.filter(group__at__gte=min_date)
|
||||
a, s, e = trie_type(opes)
|
||||
# a = sanitize(a)
|
||||
#print(a.query)
|
||||
|
||||
graphe_semaine(a, s, e)
|
||||
graphe_journee(a, s, e, [3,4], "soirée")
|
||||
graphe_journee(a, s, e, [1,6], "calme")
|
||||
premiere_conso(a, last_date, days_echan)
|
|
@ -20,6 +20,8 @@ git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_customma
|
|||
ldap3
|
||||
channels==1.1.5
|
||||
python-dateutil
|
||||
numpy==1.12.1
|
||||
matplotlib==2.0.0
|
||||
wagtail==1.10.*
|
||||
wagtailmenus==2.2.*
|
||||
django-cors-headers==2.2.0
|
||||
|
|
Loading…
Reference in a new issue