working
This commit is contained in:
parent
a0979c220b
commit
cc611e5132
3 changed files with 233 additions and 1 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) >= 17 OR EXTRACT(HOUR FROM kfet_operationgroup.at) <= 5"])
|
||||||
|
|
||||||
|
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)
|
|
@ -9,7 +9,7 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4"
|
||||||
|
|
||||||
# Installation de paquets utiles
|
# Installation de paquets utiles
|
||||||
apt-get update && apt-get install -y python3-pip python3-dev python3-venv \
|
apt-get update && apt-get install -y python3-pip python3-dev python3-venv \
|
||||||
libmysqlclient-dev libjpeg-dev git redis-server
|
libmysqlclient-dev libjpeg-dev git redis-server python3-tk
|
||||||
pip install -U pip
|
pip install -U pip
|
||||||
|
|
||||||
# Configuration et installation de mysql. Le mot de passe root est le même que
|
# Configuration et installation de mysql. Le mot de passe root est le même que
|
||||||
|
|
|
@ -21,3 +21,5 @@ git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_customma
|
||||||
ldap3
|
ldap3
|
||||||
git+https://github.com/Aureplop/channels.git#egg=channels
|
git+https://github.com/Aureplop/channels.git#egg=channels
|
||||||
python-dateutil
|
python-dateutil
|
||||||
|
numpy==1.12.1
|
||||||
|
matplotlib==2.0.0
|
||||||
|
|
Loading…
Reference in a new issue