Outils pour utilisateurs

Outils du site


issue96:python

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
issue96:python [2015/05/23 16:27] andre_domenechissue96:python [2015/05/24 11:39] (Version actuelle) fredphil91
Ligne 50: Ligne 50:
 dc.GetFullTextExtent dc.GetFullTextExtent
  
-Ce sont les seules routines wxPython que nous utiliserons, bien qu'il y en ait plein d'autres qui rendraient notre programme beaucoup plus joli. Nous combinerons ces commandes dans nos propres routines « logiques » comme Drawbars, DrawAxis, DrawValues et ainsi de suite. Bien que j'aie pu faire une ou deux grosses routines, je voulais les découper en routines qui aient un sens pour la formation. Ainsi, commençons à regarder dans le code. Créez un fichier nommé mygraph.py. Je ne trouvais quelque chose de plus parlant, car PyChart, PyGraph et équivalents sont déjà tous pris. Peut-être que si j'avais eu un peu plus de temps, j'aurai trouvé autre chose, mais ce n'est pas important. Démarrons. D'abord faisons les imports comme nous le faisons toujours.+Ce sont les seules routines wxPython que nous utiliserons, bien qu'il y en ait plein d'autres qui rendraient notre programme beaucoup plus joli. Nous combinerons ces commandes dans nos propres routines « logiques » comme Drawbars, DrawAxis, DrawValues et ainsi de suite. Bien que j'aie pu faire une ou deux grosses routines, je voulais les découper en routines qui aient un sens pour la formation. Allez, commençons à regarder le code. Créez un fichier nommé mongraphe.py. Je n'ai rien trouvé de plus parlant, car PyChart, PyGraph et équivalents sont déjà tous pris. Peut-être que si j'avais eu un peu plus de temps, j'aurai trouvé autre chose, mais ce n'est pas important. Démarrons. D'abord faisons les imports comme nous le faisons toujours.
  
 #!/usr/bin/python #!/usr/bin/python
  
-mygraph.py+mongraphe.py
  
 import wx import wx
Ligne 74: Ligne 74:
 Évidemment, nous avons besoin d'importer la bibliothèque wxPython et celle des maths nous aidera pour certains calculs. Les bibliothèques de date et de temps sont utilisées pour les étiquettes de l'axe horizontal. Évidemment, nous avons besoin d'importer la bibliothèque wxPython et celle des maths nous aidera pour certains calculs. Les bibliothèques de date et de temps sont utilisées pour les étiquettes de l'axe horizontal.
  
-Quelque chose à garder à l'esprit à partir de maintenant... Quand vous pensez à un dessin dans un contexte, le coin en haut à gauche de la fenêtre conteneur (notre dc) est x=0, y=0. X est l'axe horizontal et Y, l'axe vertical. Plus nous sommes près de l'angle en bas à droite, plus les nombres deviennent grands. Dans notre programme, nous commencerons par dessiner une boîte qui définit la zone de notre graphe, qui commence en haut à gauche à x=10, Y=10 et finit à X=800, y=700. Cependant, avant de passer à cela, nous devons définir une classe pour manipuler les routines et la routine <nowiki>__init__</nowiki>. J'espère que vous vous souvenez des sessions précédentes.+Quelque chose à garder à l'esprit à partir de maintenant... Quand vous pensez à un dessin dans un contexte, le coin en haut à gauche de la fenêtre conteneur (notre dc) est x=0, y=0. X est l'axe horizontal et Y, l'axe vertical. Plus nous sommes près de l'angle en bas à droite, plus les deux nombres deviennent grands. Dans notre programme, nous commencerons par dessiner une boîte qui définit la zone de notre graphe, qui commence en haut à gauche à X=10, Y=10 et finit à X=800, Y=700. Cependant, avant de passer à cela, nous devons définir une classe pour manipuler les routines et la routine <nowiki>__init__</nowiki>. J'espère que vous vous souvenez des sessions précédentes.
  
 En haut à droite, vous trouvez la définition de classe et la routine <nowiki>__init__</nowiki>. En haut à droite, vous trouvez la définition de classe et la routine <nowiki>__init__</nowiki>.
  
-Notre classe s'appelle Line et nous créerons une frame wxFrame pour faire notre dessin. Ce pourrait être un panneau dans une frame ou toute autre option. Mon choix a été d'avoir un pop-up Frame dans le graphe avec les données dedans. La première fois que la classe est instanciée, la routine <nowiki>__init__</nowiki> est appelée par le nom de l'objet parent, l'identifiant de cet objet, le titre de la frame (dans la barre de titre) les données que l'on veut mettre en graphe et enfin le titre du graphe lui-même. Ensuite, nous créons l'objet wx.frame qui a une taille de 1024x768 pixels. Puis nous relions l'événement paint (qui est appelé quand la frame est créée, déplacée, couverte, découverte...) à notre routine d'événement OnPaint. Souvenez-vous, comme c'est à l'intérieur d'une classe, nous utilisons « self. » pour dire que la routine appartient à la classe et pas à une autre. Nous déclarons les variables (BoxWidthBoxHeightChartTitledata) pour les utiliser plus tard. Après avoir défini self.data comme une liste vide, nous appelons une routine appelée SetData pour trouver notre échelle de données, dont nous parlerons plus tard. Enfin, nous déclarons que la frame est centrée sur l'écran et nous appelons la routine Show. La routine OnPaint est appelée automatiquement parce que nous créons Frame.+Notre classe s'appelle Ligne et nous créerons une « wxFrame » pour faire notre dessin. Ce pourrait être un panneau dans une frame ou toute autre option. Mon choix a été d'avoir une fenêtre surgissante dans le graphe avec les données dedans. La première fois que la classe est instanciée, la routine <nowiki>__init__</nowiki> est appelée avec le nom de l'objet parent, l'identifiant de cet objet, le titre de la fenêtre (dans la barre de titre) les données que l'on veut mettre en graphe et enfin le titre du graphe lui-même. Ensuite, nous créons l'objet wx.frame qui a une taille de 1024x768 pixels. Puis nous relions l'événement paint (qui est appelé quand la frame est créée, déplacée, couverte, découverte...) à notre routine d'événement OnPaint. Souvenez-vous, comme c'est à l'intérieur d'une classe, nous utilisons « self. » pour dire que la routine appartient à la classe et pas à une autre. Nous déclarons les variables (LargeurBoiteHauteurBoiteTitreGraphedonnees) pour les utiliser plus tard. Après avoir défini self.donnees comme une liste vide, nous appelons une routine appelée ReglerDonnees pour trouver l'échelle de nos données, dont nous parlerons plus tard. Enfin, nous déclarons que la fenêtre est centrée sur l'écran et nous appelons la routine Afficher. La routine OnPaint est appelée automatiquement parce que nous créons une Frame.
  
 **Next (above) we will write a routine that will create a box that shows the area that we want to constrict our graph to.  This is not a clipping or constraining box, it is simply to draw the eye to what we want the user to look at. **Next (above) we will write a routine that will create a box that shows the area that we want to constrict our graph to.  This is not a clipping or constraining box, it is simply to draw the eye to what we want the user to look at.
Ligne 90: Ligne 90:
 This routine is longer than most of the others, but part of that is the comments I put in. The first two lines set the font and the pen style that we will be using. In the first line (SetFont), we define the font to be the “default” font, 20 points, not italic and bold.  Next we set the colour of the pen to black and the width to be 20. Now we need to figure out the width of the text that we will be drawing so we know how to center it in the box.  We get this information by calling the GetFullTextExtent with the text that we will be drawing using the font, font size, pen width and so on that we just defined.  The tuple that is returned contains Width, Height, Decent (how far down letters like “g” and “y” will go below the base line) and any leading space.  For our purposes, all we are concerned with the width.  If you remember, we defined the width of the box back in the __init__ function as 790. To find the center of our text within our box we take the box width minus the width of the text and then divide it by 2.  That will be the X value we use to draw our text. Finally, we reset the pen size and colour.  Rather than use some default values we pick out of nowhere, we could have called the dc.GetPen function before we started, but when I started the project, I didn’t think about it.** This routine is longer than most of the others, but part of that is the comments I put in. The first two lines set the font and the pen style that we will be using. In the first line (SetFont), we define the font to be the “default” font, 20 points, not italic and bold.  Next we set the colour of the pen to black and the width to be 20. Now we need to figure out the width of the text that we will be drawing so we know how to center it in the box.  We get this information by calling the GetFullTextExtent with the text that we will be drawing using the font, font size, pen width and so on that we just defined.  The tuple that is returned contains Width, Height, Decent (how far down letters like “g” and “y” will go below the base line) and any leading space.  For our purposes, all we are concerned with the width.  If you remember, we defined the width of the box back in the __init__ function as 790. To find the center of our text within our box we take the box width minus the width of the text and then divide it by 2.  That will be the X value we use to draw our text. Finally, we reset the pen size and colour.  Rather than use some default values we pick out of nowhere, we could have called the dc.GetPen function before we started, but when I started the project, I didn’t think about it.**
  
-Ensuite (ici au-dessus), nous écrirons une routine qui créera une boîte qui montre la zone dans laquelle le graphe sera confiné. Ce n'est pas une boîte découpante ou contraignante, c'est simplement pour attirer l’œil de l'utilisateur sur ce que nous voulons qu'il regarde.+Ensuite (ci-dessus), nous écrirons une routine qui créera une boîte qui affiche la zone dans laquelle le graphe sera confiné. Ce n'est pas une boîte découpante ou contraignante, c'est simplement pour attirer l’œil de l'utilisateur sur ce que nous voulons qu'il regarde.
  
-Pas vraiment difficile. Nous utiliserons la fonction Drawline plusieurs fois tout au long de ce programme. Ensuite, nous créerons une routine qui tracera les lignes d'axes X (horizontal) et Y (vertical) à l'écran. Nous passons à nouveau le dc de la frame dans la routine.+Pas vraiment difficile. Nous utiliserons la fonction Drawline plusieurs fois tout au long de ce programme. Ensuite, nous créerons une routine qui tracera les lignes d'axes X (horizontal) et Y (vertical) à l'écran. Nous passons à nouveau le dc de la fenêtre à la routine.
  
-Pour ce qui est de la méthode DrawLine dont nous venons de parler, il n'y a rien d'extraordinaire. Nous dessinons une ligne de 580 pixels qui descend le long du Frame, commençant à x=60 et terminant à X=700. Ensuite nous traçons une ligne qui part de X=60, Y=580 et va jusqu'à X=60, Y=80. Cette ligne est tirée de bas en haut, mais vous pourriez la tracer de haut en bas.+Pour ce qui est de la méthode DrawLine dont nous venons de parler, il n'y a rien d'extraordinaire. Nous dessinons une ligne de 580 pixels qui descend le long du Frame, commençant à X=60 et terminant à X=700. Ensuite nous traçons une ligne qui part de X=60, Y=580 et va jusqu'à X=60, Y=80. Cette ligne est tirée de bas en haut, mais vous pourriez la tracer de haut en bas.
  
-Ensuite, nous nous occuperons de la routine DrawTitle. Une fois encore, nous passons le dc de la frame ainsi que le texte que nous voulons dessiner. Durant le processus, pensez à dessiner du texte plutôt qu'à l'imprimer. Ce n'est pas grand chose, mais ça aide.+Ensuite, nous nous occuperons de la routine DessineTitre. Une fois encore, nous passons le dc de la fenêtre ainsi que le texte que nous voulons dessiner. Durant le processus, pensez que l'on dessine du texte plutôt que l'afficher. Ce n'est pas grand chose, mais ça aide.
  
 Cette routine est plus longue que la plupart des autres, mais c'est dû en partie aux commentaires que j'ai mis. Les deux premières lignes initialisent la police et le style d'écriture que nous utiliserons. Dans la première ligne (SetFont), nous définissons la police qui sera celle par défaut, 20 points, pas italique et grasse. Ensuite, nous déclarons noire la couleur du crayon et la largeur à 20. Maintenant nous devons estimer la largeur du texte pour le centrer dans la boîte. Nous obtenons cette information en appelant GetFullTextExtent avec le texte que nous voulons dessiner, en donnant la police et sa taille, la largeur du trait et tout ce que nous venons de définir. Le tuple qui est retourné contient Width, Height, Decent (largeur, hauteur, décalage - jusqu'à quel point des lettres comme « g » ou « y » passeront sous la ligne de base) et toute espace initiale. Pour nos besoins, seule la largeur nous importe. Si vous vous souvenez, nous avons défini une largeur de boîte de 790 dans la fonction <nowiki>__init__</nowiki>. Pour trouver le centre de notre texte dans la boîte, nous prenons la largeur de la boîte moins la largeur du texte et nous divisons par 2. Ce sera la valeur X à utiliser pour tracer le texte. Enfin, nous réinitialisons la taille du crayon et la couleur. Plutôt que d'utiliser des valeurs par défaut prises on ne sait où, nous aurions pu appeler la fonction dc.GetPen avant de commencer, mais quand j'ai commencé le projet, je n'y ai pas pensé. Cette routine est plus longue que la plupart des autres, mais c'est dû en partie aux commentaires que j'ai mis. Les deux premières lignes initialisent la police et le style d'écriture que nous utiliserons. Dans la première ligne (SetFont), nous définissons la police qui sera celle par défaut, 20 points, pas italique et grasse. Ensuite, nous déclarons noire la couleur du crayon et la largeur à 20. Maintenant nous devons estimer la largeur du texte pour le centrer dans la boîte. Nous obtenons cette information en appelant GetFullTextExtent avec le texte que nous voulons dessiner, en donnant la police et sa taille, la largeur du trait et tout ce que nous venons de définir. Le tuple qui est retourné contient Width, Height, Decent (largeur, hauteur, décalage - jusqu'à quel point des lettres comme « g » ou « y » passeront sous la ligne de base) et toute espace initiale. Pour nos besoins, seule la largeur nous importe. Si vous vous souvenez, nous avons défini une largeur de boîte de 790 dans la fonction <nowiki>__init__</nowiki>. Pour trouver le centre de notre texte dans la boîte, nous prenons la largeur de la boîte moins la largeur du texte et nous divisons par 2. Ce sera la valeur X à utiliser pour tracer le texte. Enfin, nous réinitialisons la taille du crayon et la couleur. Plutôt que d'utiliser des valeurs par défaut prises on ne sait où, nous aurions pu appeler la fonction dc.GetPen avant de commencer, mais quand j'ai commencé le projet, je n'y ai pas pensé.
Ligne 110: Ligne 110:
 Notre prochaine routine dessinera les traits d'échelle le long de l'axe horizontal en bas du graphe. Nous les voulons équidistants tout le long de la ligne. Nous passons (comme d'habitude) dc et une valeur que j'ai appelé dcount qui est le nombre de dates que nous voulons afficher. Comme le nombre de jours d'un mois varie entre 28 et 31, j'ai voulu que ce soit un peu dynamique. Nous utilisons simplement une boucle for pour compter le nombre de lignes à tracer, lesquelles tracer et où. Si vous avez été très attentifs, nous démarrerons les lignes à la position 85, elles auront 20 pixels de haut et seront espacées de 20 pixels. Notre prochaine routine dessinera les traits d'échelle le long de l'axe horizontal en bas du graphe. Nous les voulons équidistants tout le long de la ligne. Nous passons (comme d'habitude) dc et une valeur que j'ai appelé dcount qui est le nombre de dates que nous voulons afficher. Comme le nombre de jours d'un mois varie entre 28 et 31, j'ai voulu que ce soit un peu dynamique. Nous utilisons simplement une boucle for pour compter le nombre de lignes à tracer, lesquelles tracer et où. Si vous avez été très attentifs, nous démarrerons les lignes à la position 85, elles auront 20 pixels de haut et seront espacées de 20 pixels.
  
-Quand nous passons au tracé des dates sur le graphe, nous voulons les dessiner en biais. De cette manière, les textes ne se chevaucheront pas et, avouons-le, ce sera plus chouette. Pour cela, nous utiliserons la fonction DrawRotateText. La fonction prend le texte que nous voulons voir dessiné, la position en X et Y comme point de départ et l'angle que nous choisissons pour le tracé. Dans le cas présent, nous voulons un texte tourné de 45 degrés en rotation anti-horaire, ce qui s'écrit « -45 ». Nous réglerons les paramètres de la police et du crayon à chaque tracé du texte. Nous parlerons de la véritable fonction de dessin de date un peu plus tard.+Quand nous passons au tracé des dates sur le graphe, nous voulons les dessiner en biais. De cette manière, les textes ne se chevaucheront pas et, avouons-le, ce sera plus chouette. Pour cela, nous utiliserons la fonction DessineTexteRot. La fonction prend le texte que nous voulons voir dessiné, la position en X et Y comme point de départ et l'angle que nous choisissons pour le tracé. Dans le cas présent, nous voulons un texte tourné de 45 degrés en rotation anti-horaire, ce qui s'écrit « -45 ». Nous réglerons les paramètres de la police et du crayon à chaque tracé du texte. Nous parlerons de la véritable fonction de dessin de date un peu plus tard.
  
 Nous voudrons aussi tracer les valeurs le long de l'axe vertical, avec des traits d'échelle tout le long. Si nous avions chaque fois la même étendue des données, ce serait facile à faire. Cependant, la réalité montre que la plage des données de notre graphe peut varier d'un mois sur l'autre. Une fois, la valeur la plus haute peut être 300. La fois suivante, cela pourrait être 3 000. Comment créer une routine générique qui en tient compte ? Je vais essayer ici de vous expliquer mon raisonnement. Nous voudrons aussi tracer les valeurs le long de l'axe vertical, avec des traits d'échelle tout le long. Si nous avions chaque fois la même étendue des données, ce serait facile à faire. Cependant, la réalité montre que la plage des données de notre graphe peut varier d'un mois sur l'autre. Une fois, la valeur la plus haute peut être 300. La fois suivante, cela pourrait être 3 000. Comment créer une routine générique qui en tient compte ? Je vais essayer ici de vous expliquer mon raisonnement.
Ligne 124: Ligne 124:
 If it is a tuple, we create two lists, one for the dates and one for the values. We then walk the list splitting the data between the two lists. Once we have that done, we then find the highest value (max(self.ValList)) and send it the roundup function (shown above) so we can get our scaling value. If the data isn’t in tuples, then we clear BOTH lists and do the same steps as above.** If it is a tuple, we create two lists, one for the dates and one for the values. We then walk the list splitting the data between the two lists. Once we have that done, we then find the highest value (max(self.ValList)) and send it the roundup function (shown above) so we can get our scaling value. If the data isn’t in tuples, then we clear BOTH lists and do the same steps as above.**
  
-Disons que pour un calcul donné notre valeur maximum sera 395. Nous pourrions simplement tracer une barre de 395 pixels de haut pour représenter la valeur. Au calcul suivant, ce maximum est de 2 345. Si nous essayons de tracer la barre à sa pleine hauteur, ça dépassera le haut du graphe. De façon à montrer cette valeur, je dois l'arrondir au 500 le plus près au-dessus, c'est-à-dire 2 500, à prendre comme valeur la plus haute de l'axe. Nous pouvons alors mettre à l'échelle en divisant 2 500 par 500 soit un facteur d'échelle de 4. Maintenant, si nous prenons nos données et que nous divisons chacune par le facteur d'échelle, nous pouvons tracer les valeurs, qui tiendront dans le graphe.+Disons que pour un calcul donné notre valeur maximum sera 395. Nous pourrions simplement tracer une barre de 395 pixels de haut pour représenter la valeur. Au calcul suivant, ce maximum est de 2 345. Si nous essayons de tracer la barre à sa pleine hauteur, ça dépassera le haut du graphe. De façon à montrer cette valeur, je dois l'arrondir au 500 le plus près au-dessus, c'est-à-dire 2 500, à prendre comme valeur la plus haute de l'axe. Nous pouvons alors mettre à l'échelle en divisant 2 500 par 500 soit un facteur d'échelle de 5. Maintenant, si nous prenons nos données et que nous divisons chacune par le facteur d'échelle, nous pouvons tracer les valeurs, qui tiendront dans le graphe.
  
-Aussi (montré en haut à droite), nous avons besoin de trouver la valeur la plus haute dans nos données et de l'arrondir au multiple de 500 supérieur le plus proche. Ainsi, pour 375, ce sera 500 ; pour 3 750, ce sera 4 000 et ainsi de suite.+Aussi (voir en haut à droite), nous avons besoin de trouver la valeur la plus haute dans nos données et de l'arrondir au multiple de 500 supérieur le plus proche. Ainsi, pour 375, ce sera 500 ; pour 3 750, ce sera 4 000 et ainsi de suite.
  
-Ensuite, nous devons décider quel type de données nous allons utiliser. Nous verrons plus loin dans le programme que je fournis deux types différents de données dans les listes. L'un assure que les plages de dates que nous utiliserons, le long de l'axe des X, sont les données pour octobre, mais vous pouvez facilement suivre le code (montré dans un petit instant) et changer pour le mois que vous voulez. La seconde liste de données est plus générique et fournit à la fois une date et une valeur comme une liste de tuples. Ceci permet de passer des données de n'importe quelle période. La date est une chaîne et la valeur est soit un entier, soit en virgule flottante. La fonction SetData regarde la première valeur de la liste de données et détermine si c'est un tuple. Si c'est le cas, nous supposons que la structure de la liste correspond à la seconde option, sinon, c'est la première.+Ensuite, nous devons décider quel type de données nous allons utiliser. Nous verrons plus loin dans le programme que je fournis deux types différents de données dans les listes. L'un assure que les plages de dates que nous utiliserons, le long de l'axe des X, sont les données pour octobre, mais vous pouvez facilement suivre le code (montré dans un petit instant) et changer pour le mois que vous voulez. La seconde liste de données est plus générique et fournit à la fois une date et une valeur comme une liste de tuples. Ceci permet de passer des données de n'importe quelle période. La date est une chaîne et la valeur est soit un entier, soit en virgule flottante. La fonction ReglerDonnees regarde la première valeur de la liste de données et détermine si c'est un tuple. Si c'est le cas, nous supposons que la structure de la liste correspond à la seconde option, sinon, c'est la première.
  
-Si c'est un tuple, nous créons deux listes, une pour les dates et une pour les valeurs. Ensuite, nous parcourons la liste en la séparant en deux listes. Une fois cela fait, nous trouvons la plus haute valeur (max(Self.ValList)) et nous lançons la fonction d'arrondi (montrée ci-dessus) pour déterminer notre facteur d'échelle. Si les données ne sont pas en tuples, nous effaçons les DEUX listes et faisons les mêmes étapes qu'au-dessus.+Si c'est un tuple, nous créons deux listes, une pour les dates et une pour les valeurs. Ensuite, nous parcourons la liste en la séparant en deux listes. Une fois cela fait, nous trouvons la plus haute valeur (max(Self.ListeValeurs)) et nous lançons la fonction d'arrondi (voir ci-dessus) pour déterminer notre facteur d'échelle. Si les données ne sont pas en tuples, nous effaçons les DEUX listes et faisons les mêmes étapes qu'au-dessus.
  
 **Now that we have our scale value we can draw our tics and the values that will represent our vertical axis. We again use a for loop, this time from 580 to 30 with a step of -50 to work our way up the line and draw a 10 pixel line.  Next we set the font (just in case it gets changed somehow) and draw the value of each of our values.  **Now that we have our scale value we can draw our tics and the values that will represent our vertical axis. We again use a for loop, this time from 580 to 30 with a step of -50 to work our way up the line and draw a 10 pixel line.  Next we set the font (just in case it gets changed somehow) and draw the value of each of our values. 
Ligne 142: Ligne 142:
 Maintenant que nous avons notre facteur d'échelle, nous pouvons tracer les traits d'échelle et les valeurs qui vont représenter l'axe vertical. Nous utilisons à nouveau une boucle for, cette fois-ci de 580 à 30 par pas de -50 le long de la ligne, en traçant des traits de 10 pixels. Après, nous configurons la police (juste au cas où elle aurait changé) et nous dessinons chaque valeur. Maintenant que nous avons notre facteur d'échelle, nous pouvons tracer les traits d'échelle et les valeurs qui vont représenter l'axe vertical. Nous utilisons à nouveau une boucle for, cette fois-ci de 580 à 30 par pas de -50 le long de la ligne, en traçant des traits de 10 pixels. Après, nous configurons la police (juste au cas où elle aurait changé) et nous dessinons chaque valeur.
  
-Maintenant, nous regardons les routines qui créeront les traits d'échelle pour les dates le long de l'axe des X si nous choisissons d'avoir une simple liste de données sans inclure les dates. Nous avons deux routines de renfort, une appelée DateToStamp et l'autre Timestamp2Date (Oui, j'étais un peu fainéant quand j'ai écrit celle-ci.) Plutôt que de passer par un paquet de routines DateTime compliquées pour déterminer le nombre de jours d'un mois donné, je vais utiliser une date de début et une date de fin et convertir les deux en horodatage Unix pour obtenir le bon jour du mois dans la séquence. Je vous ai montré la routine DateToStamp précédemment et la routine Timestamp2Date exécute le processus inverse.+Maintenant, regardons les routines qui créeront les traits d'échelle pour les dates le long de l'axe des X si nous choisissons d'avoir une simple liste de données sans inclure les dates. Nous avons deux routines de renfort, une appelée DateToStamp et l'autre Timestamp2Date (Oui, j'étais un peu fainéant quand j'ai écrit celle-ci.) Plutôt que de passer par un paquet de routines DateTime compliquées pour déterminer le nombre de jours d'un mois donné, je vais utiliser une date de début et une date de fin et convertir les deux en horodatage Unix pour obtenir le bon jour du mois dans la séquence. Je vous ai montré la routine DateToStamp précédemment et la routine Timestamp2Date exécute le processus inverse.
  
 La routine suivante prend les dates de début et de fin, comme présenté auparavant, les convertit en horodatage Unix, puis ajoute 86 400 (le nombre de traits dans une période de 24 heures) pour être sûr d'avoir la dernière valeur de la séquence, puis utilise une autre boucle for pour dessiner le texte en biais où nous le voulons. La routine suivante prend les dates de début et de fin, comme présenté auparavant, les convertit en horodatage Unix, puis ajoute 86 400 (le nombre de traits dans une période de 24 heures) pour être sûr d'avoir la dernière valeur de la séquence, puis utilise une autre boucle for pour dessiner le texte en biais où nous le voulons.
  
-Nous arrivons maintenant au gestionnaire d'événements OnPaint qui appelle toute les routines d'aide que nous devons gérer. Souvenez-vous, quand nous avons utilisé la routine PaintDC, chaque fois que la frame est bougée, redimensionnée, couverte ou découverte, le gestionnaire d'événement OnPaint est appelé, assurant de ce fait que notre graphe sera persistant.+Nous arrivons maintenant au gestionnaire d'événements OnPaint qui appelle toute les routines utilitaires que nous devons gérer. Souvenez-vous, en utilisant la routine PaintDC, à chaque fois que la fenêtre est bougée, redimensionnée, couverte ou découverte, le gestionnaire d'événement OnPaint est appelé, assurant de ce fait que notre graphe sera persistant.
  
 **First (shown on the next page, top left) we get an instance of our dc, and then we call the DrawBox, DrawAxis, DrawTitle, and the DrawDateTicks routines. We then determine if the DateList list (created in the SetData routine called from __init__ routine) is empty or if it has dates for us to draw. If so, we call the DrawDates routine with the proper values. We then call the DrawValues routine and finally the DrawBars routine. Now you should understand why I broke everything down into little bitty chunks. **First (shown on the next page, top left) we get an instance of our dc, and then we call the DrawBox, DrawAxis, DrawTitle, and the DrawDateTicks routines. We then determine if the DateList list (created in the SetData routine called from __init__ routine) is empty or if it has dates for us to draw. If so, we call the DrawDates routine with the proper values. We then call the DrawValues routine and finally the DrawBars routine. Now you should understand why I broke everything down into little bitty chunks.
Ligne 156: Ligne 156:
 Until next time, have fun coding.** Until next time, have fun coding.**
  
-D'abord (présenté en haut à gauche de la page suivante), nous obtenons une instance de notre dc, puis nous appelons les routines DrawBoxDrawAxisDrawTitle et DrawDateTicks. Ensuite, nous déterminons si la liste Datelist (créée dans la routine SetData appelée par la routine <nowiki>__init__</nowiki>) est vide ou si des dates peuvent en être extraites. Si c'est le cas, nous appelons la routine DrawDates avec les bonnes valeurs. Puis nous appelons la routine DrawValues et, enfin, la routine DrawBars. Maintenant, vous devriez comprendre pourquoi j'ai découpé le sujet en tout petits bouts.+D'abord (voir en haut à gauche de la page suivante), nous obtenons une instance de notre dc, puis nous appelons les routines DessineBoiteDessineAxeDessineTitre et DessineBarresDates. Ensuite, nous déterminons si la ListeDates (créée dans la routine ReglerDonnees appelée par la routine <nowiki>__init__</nowiki>) est vide ou si des dates peuvent en être extraites. Si c'est le cas, nous appelons la routine DessineDates avec les bonnes valeurs. Puis nous appelons la routine DessineValeurs et, enfin, la routine DessineBarres. Maintenant, vous devriez comprendre pourquoi j'ai découpé le sujet en tout petits bouts.
  
-La dernière chose que nous avons à regarder est la routine d'exécution. Vous vous souvenez probablement que le « if <noxiki>__name__</nowiki> == “<nowiki>__main__</nowiki>” » fonctionne si nous appelons le programme seul plutôt que comme une bibliothèque. Les deux lignes suivantes sont les données fictives que j'ai utilisées pour tester le programme. Vous pouvez commenter la première et lancer le programme avec la seconde ligne qui est celle qui utilise le tuple. Les trois dernières lignes instanceront les routines wxPython, puis la classe Line et enfin appellera la routine wxPython app.MainLoop pour lancer la frame.+La dernière chose que nous avons à regarder est la routine d'exécution. Vous vous souvenez probablement que le « if <nowiki>__name__</nowiki> == “<nowiki>__main__</nowiki>” » fonctionne si nous appelons le programme seul plutôt que comme une bibliothèque. Les deux lignes suivantes sont les données fictives que j'ai utilisées pour tester le programme. Vous pouvez commenter la première et lancer le programme avec la seconde ligne qui est celle qui utilise le tuple. Les trois dernières lignes instancieront les routines wxPython, puis la classe Ligne et enfin appellera la routine wxPython app.MainLoop pour lancer la fenêtre.
  
-Voila ! Nos programme et bibliothèque personnels de graphe/tableau. J'ai mis le code complet sur pastebin à : http://pastebin.com/m2feeh5P.+Et voilà notre programme et notre bibliothèque personnalisés de graphe/tableau. J'ai mis le code complet sur pastebin à : http://pastebin.com/fJ00bhud.
  
 Jusqu'à la prochaine fois, amusez-vous bien à coder. Jusqu'à la prochaine fois, amusez-vous bien à coder.
 +
 +====== code encadré orangé page 17 haut ======
 +
 +class Ligne(wx.Frame):
 +    def __init__(self, parent, id, TitreFenetre, DonneesEntrantes, TitreGraphe):
 +        wx.Frame.__init__(self, parent, id, TitreFenetre, size=(1024, 768))
 +        self.Bind(wx.EVT_PAINT, self.OnPaint)
 +        self.LargeurBoite = 790
 +        self.HauteurBoite = 690
 +        self.TitreGraphe = TitreGraphe
 +        self.donnees = []
 +        self.ReglerDonnees(DonneesEntrantes)
 +        self.Centre()
 +        self.Show(True)
 +
 +====== page 17 milieu ======
 +
 +modifier uniquement la 1ère ligne du code :
 +    def DessineBoite(self,dc):
 +
 +puis traduire le texte en noir (et laisser la dernière ligne en orange) :
 +
 +C'est plutôt simple. On passe le dc de la fenêtre puis on dessine 4 lignes.
 +Les paramètres de la fonction DrawLine sont :
 +
 +====== page 17 bas ======
 +
 +    def DessineAxe(self,dc):
 +        # Horizontal
 +        dc.DrawLine(60,580,700,580)
 +        # Vertical
 +        dc.DrawLine(60,580,60,80)
 +
 +====== page 18 haut ======
 +
 +    def DessineTitre(self,dc,txt):
 +        dc.SetFont(wx.Font(20,wx.DEFAULT,wx.NORMAL,wx.BOLD))
 +        dc.SetPen(wx.Pen(wx.NamedColour('black'),20))
 +        # Recupere la longueur du texte a dessiner
 +        vals = dc.GetFullTextExtent(txt)
 +        # Retourne (Largeur,hauteur,Decalage,espacementInitial)
 +        # Recupere la position gauche (x) pour centrer le texte
 +        txtleft = (self.LargeurBoite-vals[0])/2
 +        dc.DrawText(txt,txtleft,30)
 +        # Raz taille et couleur du stylo
 +        dc.SetPen(wx.Pen(wx.NamedColour('black'),2))
 +
 +====== page 18 milieu ======
 +
 +modifier juste la 1ère ligne :
 +    def DessineBarresDates(self,dc,dcount):
 +
 +====== page 18 bas ======
 +
 +modifier juste la 1ère ligne :
 +    def DessineTexteRot(self,dc,txt,x,y):
 +
 +====== page 19 haut ======
 +
 +    #==================================
 +    # Arrondi au 500 le plus proche
 +    #==================================
 +    def arrondi(self,x):
 +        return int(math.ceil(x/500.0))*500
 +
 +====== page 19 milieu ======
 +
 +    def ReglerDonnees(self,DonneesAUtiliser):
 +        if type(DonneesAUtiliser[1]) is tuple:
 +            self.ListeDates=[]
 +            self.ListeValeurs=[]
 +            for l in DonneesAUtiliser:
 +                self.ListeDates.append(l[0])
 +                self.ListeValeurs.append(l[1])
 +            self.ValeurMax = self.arrondi(max(self.ListeValeurs))
 +            self.ValeurEchelle = self.ValeurMax/500
 +        else:
 +            self.ListeValeurs=[]
 +            self.ListeDates=[]
 +            for l in DonneesAUtiliser:
 +                self.ListeValeurs.append(l)
 +            self.ValeurMax = self.arrondi(max(self.ListeValeurs))
 +            self.ValeurEchelle = self.ValeurMax/500
 +
 +====== page 19 bas ======
 +
 +modifier juste la 1ère ligne :
 +    def DessineValeurs(self,dc):
 +
 +et la dernière :
 +            c2 = c2 + (50 * self.ValeurEchelle)
 +
 +====== page 20 haut ======
 +
 +modifier juste la 1ère ligne :
 +    def DessineBarres(self,dc):
 +
 +====== page 20 milieu ======
 +
 +    #==================================
 +    #  Convertit dd/mm/yy en timestamp unix
 +    #==================================
 +    def DateToStamp(self,x):
 +        x = x+" 00:00:00"
 +        return(time.mktime(time.strptime(x, "%d/%m/%Y %H:%M:%S")))
 +    #==================================
 +    #  Convertit un horodatage unix en dd/mm/yy
 +    #==================================
 +    def Timestamp2Date(self,tstmp):
 +        return datetime.fromtimestamp(int(tstmp)).strftime('%d/%m/%Y')
 +
 +====== page 20 bas ======
 +
 +    #==================================
 +    #  Dessine les dates en biais
 +    #==================================
 +    def DessineDates(self,dc,startdate,enddate):
 +        sd = int(self.DateToStamp(startdate))
 +        ed = int(self.DateToStamp(enddate))
 +        ed = ed + 86400
 +        stp = 1
 +        for cntr in range(sd,ed,86400):
 +            dt = self.Timestamp2Date(cntr)
 +            self.DessineTexteRot(dc,dt,65+(stp*20),600)
 +            stp = stp + 1
 +
 +====== page 21 milieu ======
 +
 +    #==================================
 +    #  Routine principale
 +    #==================================
 +    def OnPaint(self,event):
 +        dc = wx.PaintDC(self)
 +        self.DessineBoite(dc)
 +        self.DessineAxe(dc)
 +        self.DessineTitre(dc,self.TitreGraphe)
 +        # Barres de dates et dates
 +        self.DessineBarresDates(dc,31)
 +        leng = len(self.ListeDates)
 +        if leng > 0:
 +            sd = self.ListeDates[0]
 +            ed = self.ListeDates[4]
 +            self.DessineDates(dc,sd,ed)
 +        else:
 +            self.DessineDates(dc,"02/01/2015","03/01/2015")
 +        # Barres de valeurs - Dessine 10 barres 
 +        self.DessineValeurs(dc)
 +        # Enfin on dessine les barres de donnees
 +        self.DessineBarres(dc)
 +
 +====== page 21 bas ======
 +
 +modifier « data » en « donnees » sur les 2 premières lignes, et remplacer la ligne :
 +
 +    Ligne(None, -1, 'Bar Chart',donnees,"Ventes mensuelles - Colorado Springs")
 +
issue96/python.1432391237.txt.gz · Dernière modification : 2015/05/23 16:27 de andre_domenech