#!/usr/bin/python ## Pierre Hyvernat, TP du cours « info-719 : rappels et compléments de ## programmation » ## TP1 : representation de données import Image # on aura besoin de créer des images ### ### Questions préliminaires ### def renverse(nom): """Lit le fichier 'nom' et crée un fichier 'nom-renverse' qui contient les mêmes lignes que 'nom', mais en partant de la fin. Ne fonctionne pas si le fichier n'existe pas, et ecrase le fichier 'nom-renverse' s'il existe""" fichier_initial = open(nom) # ouverture en lecture fichier_renv = open(nom+'-renverse', 'w+') # ouverture en ecriture lignes = fichier_initial.readlines() fichier_initial.close() t = len(lignes) for i in range(t): fichier_renv.write(lignes[t-i-1]) fichier_renv.close() def maj(nom): """Recopie le fichier 'nom' en 'nom-maj' en mettant la premiere lettre de chaque ligne en majuscule.""" f1 = open(nom) f2 = open(nom+'-maj', 'w+') for l in f1.readlines(): m = l[0].upper() l = l[1:] f2.write(m+l) f1.close() f2.close() def num_lignes(nom): """Recopie le fichier 'nom' en 'nom-lignes' en rajoutant les numéros de lignes""" f1 = open(nom) f2 = open(nom+'-lignes', 'w+') i = 1 for l in f1.readlines(): f2.write(str(i)+' \t'+l) i = i+1 f1.close() f2.close() ### ### diagramme en baton ### ### fonction rectangle du TP0 def rectangle(im, geom, couleur=(255,255,255)): """dessine un rectangle « horizontal » de couleur. - "im" est un objet image (obtenu par "Image.new") - "geom" est un quadruplet (x,y,largeur,hauteur), où "x" et "y" sont les coordonnées du point en haut à gauche du rectangle. """ x, y, largeur, hauteur = geom for j in range(hauteur): for i in range(largeur): im.putpixel((x+i,y+j),couleur) ### la fonction principale pour le diagramme en batons def baton(fichier_donnees, fichier_image, largeur, hauteur, marge=10, coul=(255,0,0), fond=(255,255,255)): """Lit les données (nombres entiers) contenus dans le fichier 'fichier_donnees' et produit un diagramme en baton dans le fichier 'fichier_image.png'. Les données sont "en vrac" dans le fichier : sur plusieurs lignes, séparées par un ou plusieurs espaces, ... Le parametre 'marge' permet de specifier une marge autour de chaque baton, les parametres 'coul' et 'fond' permettent de specifier les couleur des batons et du fond de l'image. """ fd = open(fichier_donnees) donnees = map(int,fd.read().split()) fd.close() ### en détails : ### - fd.read() est la chaine de caractères qui contient tout le fichier ### - .split() permet de decouper une chaine de caractères en un tableau ### en utilisant les caractères blancs comme délimiteur ### - fd.read().split() est donc le tableau de tous les « mots » du fichier ### de données (normalemement, se sont tous des entiers) ### - map(int, ...) applique la fonction "int" à tous les elements du tableau ### Au final, "donnees" est donc un tableau d'entiers qui contient tous ### les nombres contenus dans le fichier. ### On peut faire plus simple, mais plus long im = Image.new("RGB", (largeur,hauteur), fond) val_max = max(donnees) nb_val = len(donnees) largeur_baton = (largeur - marge*(nb_val+1))/ nb_val # largeur d'un baton coeff = (hauteur - 2*marge) / val_max # coeff de proportionalite entre les données et la hauteur de l'image for i in range(nb_val): h = coeff*donnees[i] rectangle(im, (marge + i*(marge+largeur_baton),hauteur-marge-h, largeur_baton, h),coul) im.save(fichier_image + '.png') ### ### boites à moustaches ### def quartiles(donnees): """calcule les 3 quartiles de la liste de nombres 'donnees'. La valeur de retour est un triplet (q1,q2,q3) où q1 est le premier quartile, q2 la valeur médiane et q3 le troisieme quartile.""" n = len(donnees) # pour éviter de modifier le tableau "données", je le recopie tmp = donnees[0:n] # je trie les données tmp.sort() # la mediane est donnée par la valeur du milieu du tableau med = tmp[n/2] # le premier quartile par la valeur au premier quart quart1 = tmp[n/4] # le troisieme quartile par la valeur au premier quart quart3 = tmp[(3*n)/4] return(quart1, med, quart3) ### Rq : si l'un des quartiles ne tombe pas juste, il faudrait probablement ### prendre une moyenne pondérée des valeurs juste au dessus et juste au ### dessous. (???) def ensemble_suivant(fd): """Cette fonction renvoie le prochain ensemble de données du fichier 'fichier' sous forme d'un tableau de flottants. L'argument est un fichier (obtenu par exemple avec un "open").""" donnees = [] fini = False while not fini: ligne = fd.readline() if ligne.strip() == "": fini = True elif ligne[0] == '#': pass else: donnees.extend(map(float, ligne.split())) return(donnees) def boite_a_moustache(fichier, nom_image, largeur, hauteur, marge=10): """Fonction principale pour dessiner des boites à moustaches : - fichier est le nom du fichier de données. - largeur et hauteur sont les dimensions (en pixels) de l'image finale - marge correspont à la marge autour des boites. """ fd = open(fichier) # calculs des informations à partir des données boites = [] donnees = ensemble_suivant(fd) minimum = maximum = donnees[0] # initialisation du min et max globaux while donnees != []: q1, m, q3 = quartiles(donnees) mi = min(donnees) minimum = min(minimum, mi) ma = max(donnees) maximum = max(maximum, ma) boites.append((mi, q1, m, q3, ma)) donnees = ensemble_suivant(fd) print "DEBUG : min = %f et max = %f" %(minimum, maximum) # dessin des boites nb_boites = len(boites) largeur_boite = int((largeur - marge*(nb_boites+1))/ nb_boites) coeff = (hauteur - 2*marge) / (maximum-minimum) im = Image.new("RGB", (largeur,hauteur), (255,255,255)) for i in range(nb_boites): mi, q1, m, q3, ma = boites[i] ymi = int(hauteur - (marge + coeff*(mi - minimum))) yq1 = int(hauteur - (marge + coeff*(q1 - minimum))) ym = int(hauteur - (marge + coeff*(m - minimum))) yq3 = int(hauteur - (marge + coeff*(q3 - minimum))) yma = int(hauteur - (marge + coeff*(ma - minimum))) rectangle(im, (marge + i*(marge+largeur_boite) + largeur_boite/4,yma, largeur_boite/2, ymi-yma),(150,150,150)) rectangle(im, (marge + i*(marge+largeur_boite),yq3, largeur_boite, yq1-yq3),(50,50,50)) rectangle(im, (marge + i*(marge+largeur_boite)-2,ym-1, largeur_boite+4, 3),(0,0,0)) im.save(nom_image + ".png", "PNG") if __name__ == "__main__": boite_a_moustache("./donnees", "moustaches", 400, 400)