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)