summaryrefslogblamecommitdiff
path: root/trace_courbe.py
blob: 968ca7ba2f770681dcedc53347540fa206e3582c (plain) (tree)
1
2
3
4
5
6
7
8
9

                       
                                

                          
                                                                              
                                                  

                                                                                                                                                                                                                    
                        
 
 

                               

                                                                                                              

 
                                                                                                 



                                                                                                             
                                                                                                       



                                                                                                     
                                                                                                                           
        
                                                                                                                                                        



                                                      

                                                                             
                        
                                                                          
                                                
                                                      
             
                                                   

                                  



                                                                                                                      
        
                                                        
                                                                                           
                                                                              
    
                                                                             

                                                                               
                                        





                                                                   
                                                                              




                                                                                                  
                                                                                                   


                                               
 


                                                                               
                                                                                                 
                                                            
    
                                                                                           
 
                                                                                        
                                          



                                               
                                                                                              
                                               
                                 
                                                                         
                                            
             
                                                                         
                                     

                                               
                               
                                                                       
                                                           
                                 
                                                                      
                                                         
             
                                                                      
                                                  
         

                                                                      
    
                                                                      
   
                                                                                                                  
                                                                         
 
    
                                                                                             
        
                                             
           
                                                                                      
                 
    
                                                                                   
        
                                                      

                                                   
                                                              



                                                                                                                    
                                                                                    
                                                                  

                          






                                                                                                                       
                    
 
                                                          
                           
                                               
                                                                                      
 
                                                               
        
                              
                     

                                                                                                                     
                                                                                        





                                                          

                                                                                                   





                                                                              


                                                                                                                       


                                                                                                                                                                                                                                                                                                                 
 










                                                                         
                       
                                       


                                                                    
        



                                                                                        
                                                                                            













                                                                                                     
                                                                



















                                                                                                                                                  
                                                    
                                                                           
















                                                                                                                                                        
                                                 


                                                                                                                                           
                        
                                                                 
                                                                            













                                                                                                                                                     
                                                 


                                                                                                                                            


                                                                       



                                                            

                                                                               
                           



                                                                                         
    

















                                                                  
                                                  

                                                            














                                                                            
                                                  









                                                                            
                                                         







                                                                   

                                                                                                                          
                                                       



                                                                       
 

                              
                                                         
                                                                         
 

                      
    
                                                         



              
 
                                                                  
 



                                                                                          


                                                                                     



                                                                                                          
    

    



                                                                                 



                         




























                                                                                                   
    
                                                          

                    

                                                                 

                       

                                                                                  
 










                                                                                 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from configuration import CONFIG
import gestionOMS as oms
import gestion_unites as u
from gestion_donnees import calcule_max_graphique, convertit_jours_vers_python
from gestion_erreurs import debug, erreur, warning
from calculs_extrapole import calcule_donnee_extrapolee, calcule_age_extrapole, interpole_lineaire, interpole_lineaire_ordonnee, formate_resultat_donnee, formate_resultat_age, formate_interpole, formate_extrapole

from numpy import arange


import matplotlib.pyplot as plt

# Essentiellement, la fonction qui trace la courbe, mais on y trouve également les fonctions d'extrapolation.
# Ainsi que les calculs additionnels.


def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err, enfants_add = []):
    """ conf est le dictionnaire de config. l_jours et l_poids les listes des temps (en jours) et de données
    (donc pas forcément du poids)
    typedonnee est le type de données (voir CONFIG["liste_typedonnees"]
    liste_err la liste des erreurs à compléter (voir gestion_erreurs))
    Renvoie la figure tracée, et les calculs additionnels sont mis sous forme de chaîne dans la liste
    liste_extracalculs
    
    Les enfants en plus sont dans la liste enfants_add. Pour chaque item de la liste, il faut prendre
    item[typed] pour avoir accès au nom, ljours, et ldonnees"""
    debug("debut de cree_figure. Config : "+str(conf)+". Nombre d'enfants additionnels : "+str(len(enfants_add)),liste_err)
    try:
        liste_data_labels_p,liste_data_labels_z = oms.renvoie_liste_labels(conf,CONFIG["liste_data_choisie_p"],CONFIG["liste_data_choisie_z"],liste_err)
    except:
        erreur("bug avec liste data labels",liste_err)
        return ""

    ######################## Gestion des bornes #############################
    # y a-t-il un maxi saisi par l'utilisateur ?
    if conf["maxi"] ==0:
        # Est-ce qu'on a donné un maxi quand même (car même échelle) ?
        if conf["non_sauve"].get("maxi",0) == 0:
            jour_maxi = calcule_max_graphique(l_jours)
        else:
            jour_maxi = conf["non_sauve"]["maxi"]+1
    else:
        jour_maxi = conf["maxi"]+1
    
    # Si on cherche à extrapoler au-delà
    if conf["non_sauve"]["calculextradata_type"] == typedonnee and conf["non_sauve"]["calculextradata_age"]>jour_maxi:
        jour_maxi =  int(conf["non_sauve"]["calculextradata_age"]) +1
        
    # On s'assure que c'est bien compris dans les bornes
    jour_maxi = max(CONFIG["jours_mini_courbe"],min(jour_maxi,CONFIG["jours_maxi_courbe"]))
    debug("cree_figure : gestion du jour max : "+str(jour_maxi),liste_err)    
    
    ##################### Gestion des unités ###############################
    # si l'unité n'est pas précisée, ni en "non sauvé" ni par l'utilisateur
    if conf["unite"] == "" and conf["non_sauve"].get("unite","") == "":
        unite = u.choix_unite(jour_maxi)
        debug("Unité non précisée, on choisit "+unite,liste_err)
    elif conf["unite"] != "":
        unite = conf["unite"]
    else:
        unite = conf["non_sauve"]["unite"]
    
    ##################### Gestion de la prématurité #######################"
    prema = int(convertit_jours_vers_python(conf["prematurite"],liste_err))
    ## Gestion des prémas, deux cas :
    # Si agecorrige est oui, alors on veut juste soustraire la valeur de préma
    # à toutes les données.
    # Si agecorrige est non, alors on veut ajouter la valeur de préma aux courbes de référence.
    debug("Prématurité : "+str(prema)+" age corrigé : "+conf["agecorrige"],liste_err)           
    if prema>0 and conf["agecorrige"] == "oui":
        l_jours = [j-prema for j in l_jours]
        jour_maxi = jour_maxi - prema


    ###################### Conversion des unités ###########################""
    l_jours_conv = u.convertit_tableau(l_jours,unite,liste_err)
    # Attention, comme les jours commencent à partir de 0, faut enlever 1 pour avoir la borne...
    age_maxi = u.convertitunite(jour_maxi-1,unite,liste_err)
    
    debug("cree_figure : conversion des unités ok : "+str(l_jours_conv),liste_err)        

    #####################" Courbes OMS  et titre ######################################"
    titre = "Courbe de "+typedonnee+" OMS"
    if conf["typecourbe"] == "P":
        # percentiles
        liste_data_labels = liste_data_labels_p
        if conf["sexe"] == "M":
            fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_garcon"]#f_poids_perc_garcon
            titre  += " (percentiles, garçon)"
        elif conf["sexe"] == "F":
            fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_fille"]
            titre += " (percentiles, fille)"
        else:
            fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_mixte"]
            titre += " (percentiles)"
    elif conf["typecourbe"] == "Z":
        liste_data_labels = liste_data_labels_z
        if conf["sexe"] == "M":
            fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_garcon"]
            titre += " (moyenne et écarts-types, garçon)"
        elif conf["sexe"] == "F":
            fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_fille"]
            titre += " (moyenne et écarts-types, fille)"
        else:
            fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_mixte"]
            titre += " (moyenne et écarts-types)"
    else:
        erreur("Type de courbe invalide"+conf["typecourbe"],liste_err)
        return ""
    
    ## On finira le titre plus tard quand on aura su qui est concerné
   
    #debug("cree_figure : géré le type de courbe ok. Liste des data labels : "+str(liste_data_labels),liste_err)
    debug("Fichier d'où extraire les données : "+fichier_oms,liste_err)
 
    
    #### On extrait les données des courbes, et on convertit les jours dans l'unité voulues
    try:
        t = oms.lire_fichier_csv(fichier_oms)
    except:
        erreur("cree_figure : Impossible d'ouvrir le fichier "+fichier_oms, liste_err)
        return ""
    
    debug("cree_figure : Conversion des données OMS à la bonne unité",liste_err)
    try:
        coljour= (oms.extraire_colonne(t,0,jour_maxi))
        if prema>0 and conf["agecorrige"] != "oui":
            coljour = [j + prema for j in coljour]
        coljour = u.convertit_tableau(coljour,unite,liste_err)
    except:
        erreur("Problème à la conversion du tableau OMS. jour_maxi = "+str(jour_maxi)+" unite = "+unite,liste_err)
        return ""
    
    ##################### Création de la figure et du graphique ###################
    debug("cree_figure : prête à créer la figure",liste_err)   
    #### La figure, params
    
    fig = plt.figure(num=None, figsize=(conf["largeur"], conf["hauteur"]), dpi=100, facecolor=conf["couleurs"]["fond"])
    plt.rcParams['axes.facecolor'] = conf["couleurs"]["fond"]
    plt.rcParams['axes.edgecolor']= conf["couleurs"]["cadretxt"]
    plt.rcParams['xtick.color'] = conf["couleurs"]["cadretxt"]
    plt.rcParams['ytick.color'] = conf["couleurs"]["cadretxt"]
    plt.rcParams['grid.color'] = conf["couleurs"]["grille"]
    plt.rcParams['legend.edgecolor'] = conf["couleurs"]["grille"]
    ax = plt.axes() 

    ###################### Tracé des différentes courbes
    #Tracé des courbes OMS
    for (i,label,couleur) in liste_data_labels:
        ax.plot(coljour,oms.extraire_colonne(t,i,jour_maxi),label=label,color=couleur)

    debug("cree_figure : tracé des courbes OMS ok",liste_err) 
        
    ### Tracé pour de bon    
    if l_jours != []:
        print(conf["symbole"])
        ax.plot(l_jours_conv,l_poids,label=conf["nom"],color=conf["couleurs"]["courbeenfant"],marker=conf["symbole"])
        debug("Tracé de la courbe enfant, avec les jours "+str(l_jours_conv),liste_err)


        listenoms = []
        if conf["nom"] != "": # Ajouter le nom de l'enfant
            listenoms.append(conf["nom"])

#        if enfants_add != []:
#            debug("Il y a des enfants en plus à tracer. Données : "+str(enfants_add), liste_err)
        for enfant in enfants_add: # Enfants additionnels éventuels
            conf_add, lj, ld = enfant[typedonnee]  # On récuère les données
            if lj != []: # pas la peine de tracer si y'a rien à tracer
                # Ajouter le nom de cet enfant-là
                listenoms.append(conf_add["nom"])
                lj_conv = u.convertit_tableau(lj,unite,liste_err)
                debug("Tracé de la courbe additionnelle de "+conf_add["nom"]+" config : "+str(conf_add), liste_err)
                ax.plot(lj_conv, ld, label=conf_add["nom"], color=conf_add["couleurcourbe"],marker=conf_add["symbole"])
                print("bla")
                if conf["sexe"] != conf_add["sexe"]:
                    warning("Attention, tous les enfants n'ont pas le même sexe. La courbe de référence est celle de "+conf["nom"]+" et ne sera pas forcément pertinente pour les autres. Vous pouvez éventuellement essayer la courbe neutre. Remarque : cette alerte s'affichera quand même.", liste_err)


        # Si y'a un nom on met "courbe de machin"
        if listenoms != []:
            titre += " de " +", ".join(listenoms)

        if prema>0:
            titre+= ", préma de "+conf["prematurite"]
            if conf["agecorrige"] == "oui":
                titre+=" (courbe en âge corrigé)"
            else:
                titre+=" (courbe en âge réel, données OMS décalées)"
        
        print("coucou")
        #### extrapolatios éventuelles
        # a-t-on demndé des calculs ?
        jextrapole =  conf["non_sauve"]["prolongercourbes"] == "oui"
        # Est-ce qu'on a demandé un calcul sur cette donnée ?
        
        for calextra in CONFIG["extradata"]:
            jextrapole = jextrapole or conf["non_sauve"][calextra+"_type"] == typedonnee
        
        #print(jextrapole)
        ############################## Là où on extrapole ################################
        if jextrapole:
            try:
                debug("Il faut extrapoler les courbes !", liste_err)
                # Prendre l'ensemble des dates "source"
    #            print(conf["non_sauve"]["nbdataextra"])
                if conf["non_sauve"]["nbextradata"] == 0:
                    sources_extrap = l_jours
                    sources_extrap_data = l_poids
                else:
                    sources_extrap = l_jours[-conf["non_sauve"]["nbextradata"]:] # les derniers jours
                    sources_extrap_data = l_poids[-conf["non_sauve"]["nbextradata"]:]
                
                debug("On extrapole sur les jours : "+str(sources_extrap), liste_err)
               
                # On récupère toutes les données extrapolées
                dates_extrapole, donnees_extrapole =  prolongecourbe(t, sources_extrap, sources_extrap_data, conf["typecourbe"], liste_err)
                debug("données extrapolées !", liste_err)
                #debug(str(dates_extrapole[0:10])+str(donnees_extrapole[0:10]), liste_err)            
                
                # QUe veut-on maintenant sur ces données extrapolées ?
                # Afficher la courbe
                if conf["non_sauve"]["prolongercourbes"] == "oui":
                    # On va prendre les extrapolations de la dernière donnée jusqu'à l fin du graphe
                    debut_extr = int(l_jours[-conf["non_sauve"]["nbextradata"]])
                    i_debut_extr = dates_extrapole.index(debut_extr)
                    i_fin_extr = dates_extrapole.index(jour_maxi)
                    # Voilà ce qu'on veut tracer
                    dates_extrapole_trace = dates_extrapole[i_debut_extr:i_fin_extr+1]
                    donnees_extrapole_trace = donnees_extrapole[i_debut_extr:i_fin_extr+1]                
                    dates_extrapole_trace = u.convertit_tableau(dates_extrapole_trace,unite,liste_err)
                    
                    # tracé des données extrapolées
                    plt.plot(dates_extrapole_trace, donnees_extrapole_trace,color=conf["couleurs"]["cadretxt"], linestyle=(0, (5,7)), marker=None)
                    debug("Tracé de la courbe extrapolée ok", liste_err)
                
                ### Calculer une donnée à l'âge x
                if conf["non_sauve"]["calculextradata_type"] == typedonnee:
                    # On essaie l'interpolation
                    r = interpole_lineaire(l_jours,l_poids,conf["non_sauve"]["calculextradata_age"], liste_err)
                    if r==-1:
                        # ça sera donc une extrapolation
                        r = calcule_donnee_extrapolee(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextradata_age"], liste_err)          
                        message=formate_extrapole(conf["non_sauve"]["nbextradata"])
#                        if  == 0:
#                            message+="l'ensemble des données"
#                        else:
#                            message+="les "+str(conf["non_sauve"]["nbextradata"])+" dernière"+met_s(conf["non_sauve"]["nbextradata"])+" données"
                    else:
                        message=formate_interpole()
                    
                    texte = formate_resultat_donnee(conf["non_sauve"]["calculextradata_age"], r, typedonnee, message, liste_err)
                    debug("calcul de la donnée extrapolée : "+texte, liste_err)
                    if texte!="":
                        liste_extracalculs.append(texte)
                        print(liste_extracalculs)
                        # Ajouter le trait ?
                        if conf["non_sauve"]["calculextradata_trace"] == "oui":
                            dessine_guides(conf["non_sauve"]["calculextradata_age"], r, conf["couleurs"]["cadretxt"], unite, ax, liste_err)
                        
                ### Calculer un âge où on atteint cette donnée
                if conf["non_sauve"]["calculextratemps_type"] == typedonnee:
                    # interpolation
                    r = interpole_lineaire_ordonnee(l_jours,l_poids,conf["non_sauve"]["calculextratemps_val"], liste_err)
                    if r==-1:
                        # ça sera donc une extrapolation
                        r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], liste_err)          
                        message=formate_extrapole(conf["non_sauve"]["nbextradata"])
                    else:
                        message=formate_interpole()
                    
                    texte = formate_resultat_age(r, conf["non_sauve"]["calculextratemps_val"], typedonnee, message, liste_err)
                    
                    #r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err)
                    if texte!="":
                        liste_extracalculs.append(texte)
                        print(liste_extracalculs)
                        # Ajouter le trait ?
                        if conf["non_sauve"]["calculextratemps_trace"]:
                            dessine_guides(r, conf["non_sauve"]["calculextratemps_val"], conf["couleurs"]["cadretxt"], unite, ax, liste_err)
                    
            except: 
                warning("Des problèmes pour extrapoler...", liste_err)
        
    else:
        debug("On ne trace pas de courbe enfant", liste_err)

    ###################" Gestion de l'échelle #####################
    debug("Courbes tracées. Il n'y a plus qu'à gérer l'échelle", liste_err)
    ### échelle à régler

    # On extrait la valeur min et la valeur max des poids des courbes OMS et des données
    (colonne_min,_,_) = liste_data_labels[-1]
    (colonne_max,_,_) = liste_data_labels[0]
    
    # poids max OMS
    poids_min = min(oms.extraire_colonne(t,colonne_min,jour_maxi))
    poids_max = max(oms.extraire_colonne(t,colonne_max,jour_maxi))
    if l_jours != []:
        poids_min = min(min(l_poids),poids_min)
        # Pour le poids max, voir la dernière valeur du tableau
        i = 0
        while i<len(l_jours) and l_jours[i]<jour_maxi:
            i=i+1
        poids_max = max(max(l_poids[0:i+1]),poids_max)
    # On ajuste un peu ces min et max
    # min : valeur min -1kg
    poids_min = max(0,poids_min-1)
    #max : +5% 
    poids_max = poids_max * 1.05
       

    # Grille custom ?
    if conf["non_sauve"]["grilleamelio"] == "oui":
        debug("On a choisi la grille plus jolie", liste_err)
        pas=u.choix_echelle_data(typedonnee, poids_max)
        # data_min_arrondie
        minechelle = int(poids_min/pas[0])*pas[0]
    
        debug("pas choisis pour l'échelle en y : "+str(pas), liste_err)    
        echellemajeure = arange(minechelle, poids_max, pas[0])
        
        if pas[1] >0:
            echellemineure = arange(minechelle, poids_max, pas[1])
        else:
            echellemineure = []
        
        ax.set_yticks(echellemajeure, minor=False)
        ax.set_yticks(echellemineure, minor=True)
    
        # échelle en temps
        pas=u.choix_echelle_temps(unite, age_maxi)
        debug("pas choisis pour l'échelle en x : "+str(pas), liste_err)    
    
        echellemajeure = arange(0,age_maxi, pas[0])
        if pas[1] >0:
            echellemineure = arange(0,age_maxi, pas[1])
        else:
            echellemineure = []
        ax.set_xticks(echellemajeure, minor=False)
        ax.set_xticks(echellemineure, minor=True)    

    ################################# Aspect du graphique

    debug("On commende la déco du graphique", liste_err)

    # La grille
    ax.grid(conf["grille"]=="oui")
    ax.grid(conf["grille"] == "oui", which="minor", linestyle="--")


    plt.xlabel("Âge en "+unite,color=conf["couleurs"]["cadretxt"])
    plt.ylabel(typedonnee.capitalize()+" en "+CONFIG["unites_typedonnees"][typedonnee],color=conf["couleurs"]["cadretxt"])
    plt.title(titre,color=conf["couleurs"]["cadretxt"])
    if l_jours_conv == []:
        plt.axis([0,age_maxi, poids_min, poids_max])
    else:
        plt.axis([min(0,l_jours_conv[0]),age_maxi,poids_min,poids_max])

    
    if conf['legende']=="oui":
        legende = plt.legend(loc=conf['positionlegende'])
        plt.setp(legende.get_texts(), color=conf["couleurs"]["cadretxt"])


    fig.tight_layout()
    
    debug("Fin de cree_figure, tout va bien.", liste_err)
    return fig




######################################## Pour extrapoler la courbe

def prolongecourbe(tableauOMS, dates, donnees, typecourbe, liste_err):
    """ tableauOMS est le ableau des données OMS. dates et donnees sont les dates (jours)
    et les données d'où on extrapole. On calcule toutes les dates comme des sauvages.
    On renvoie la liste des jours totale et la liste des data_totales
    (tableaux de jours)
    typecourbe est P ou Z. Pour P il faut commencer à regarder à l'indice 4, pour Z
    à l'indice 1
    On renvoie [],[] si pas pu extrapoler. """    
    # les lignes OMS correspondant aux dates données
    lignesoms = [tableauOMS[int(date)] for date in dates]
    debug("prolongecourbe : Lignes OMS :"+str(lignesoms)+" valeur de données : "+str(donnees), liste_err)
    
    
    
    # Principe : on cherche dans quel intervalle de "colonnes" on se situe.
    # On va donc regarder pour chaque donnée entre quels i on se situe,et après
    # prendre le plus grand intervalle.
    # Numéros de colonnes d'où on part. Pour la fin c'est forcément longueur-1
    if typecourbe == "P":
        idep=4
    else:
        idep = 1

    liste_indices = []
    for k in range(len(dates)):
        i= idep
        ligne = lignesoms[k]
        while i<len(ligne) and ligne[i]<donnees[k]:
            i+=1
        debug("prolongecourbe : on a trouvé la valeur de i : "+str(i),liste_err)
        if i>=len(ligne):
            warning("prolongation de courbe : pas réussi... donnée trop haute !", liste_err)
            return [],[]
        if i==idep:
            warning("prolongation de courbe : pas réussi... donnée trop basse !", liste_err)
            return [],[]
        liste_indices.append(i)
    imin=min(liste_indices) -1
    imax=max(liste_indices)
    debug("Les données se situent dans les indices : "+str(imin)+", "+str(imax),liste_err)
    # Maintenant on doit trouver les coeffs : on se situe en coeff * l[imin]+ (1-coeff)*ligne[imax]
    # Et faire la moyenne de ces coeffs
    total = 0
    for k in range(len(dates)):
        ligne = lignesoms[k]
        donnee = donnees[k]
        total += (donnee - ligne[imax])/(ligne[imin] - ligne[imax])
        #print(k)        
    coeff_moyen = total/len(dates)

    debug("Coeff moyen calculé : "+str(coeff_moyen), liste_err)
    
    # On utilisera la même chose pour les nouvelle donnee
    
    # extrapolations
    nouvdates =oms.extraire_colonne(tableauOMS,0) # On sort tout.
    #print(nouvdates)
    nouvdonnees = []
    for j in nouvdates:
        ligne2 = tableauOMS[int(j)]
        nouvdonnees.append(coeff_moyen*ligne2[imin]+ (1-coeff_moyen)*ligne2[imax])

    return nouvdates,nouvdonnees


def dessine_guides(t, data, couleur, unite, ax, liste_err):
    """ dessine deux lignes, horizontales et verticales qui vont "vers" la courbe
    jusqu'aux points (t, data). En pointillés et avec un point dessus."""
    debug("Début de dessine_guides"+str(t)+", "+str(data), liste_err)
    t_conv = u.convertitunite(t,unite,liste_err)
    ax.vlines(t_conv, 0, data, colors=couleur, linestyles="dashed")
    ax.hlines(data, 0, t_conv, color=couleur, linestyles="dashed")
    ax.plot([t_conv], [data], color=couleur, marker="*", ms=13)