Série 4 – Diagrammes tige et feuille

Introduction

Le but de cette série est de visualiser, au moyen de diagrammes tige et feuille, la distribution des heures des rendus acceptés par notre serveur pour les quatre premières étapes du projet. La construction de ces diagrammes constitue un bon exemple d'utilisation des tables associatives et des listes.

Un diagramme tige et feuille (stem-and-leaf plot, souvent abrégé stemplot en anglais) permet de visualiser la distribution d'un ensemble de valeurs entières. Il est similaire à un histogramme à barres horizontales, mais dont les barres sont les chiffres des unités des valeurs elle-mêmes.

Par exemple, admettons l'existence d'une équipe de 14 jeunes sportifs dont la taille en centimètres est { 152, 152, 154, 160, 161, 161, 162, 163, 163, 173, 173, 175, 175, 191 }. Pour créer un diagramme tige et feuille à partir de ces données, on commence par séparer chaque valeur en une tige, composée de tous les chiffres sauf celui des unités, et une feuille, le chiffre des unités. Par exemple, la valeur 152 a pour tige 15 et pour feuille 2, tandis que la valeur 154 a également 15 comme tige mais 4 comme feuille. Cette séparation faite, on produit le diagramme en affichant une ligne par tige possible entre la plus petite et la plus grande tige trouvées dans les données. Chaque ligne est composée de la tige qui lui correspond, suivie d'une barre verticale et de toutes les feuilles ayant cette tige, triées en ordre croissant. Pour les valeurs données plus haut, on obtient le diagramme suivant :

15|224
16|011233
17|3355
18|
19|1

Un tel diagramme permet d'une part de visualiser la distribution des données, puisque la longueur de chaque ligne est proportionnelle au nombre de valeurs ayant la tige correspondant à la ligne, et d'autre part de connaître précisément les valeurs présentes dans les données. Ainsi, au moyen du diagramme ci-dessus, il est trivial de reconstituer la totalité des données.

Il est également possible de construire des diagrammes tige et feuille bidirectionnels, permettant de comparer les distributions de deux ensembles de valeurs. Par exemple, admettons que les hauteurs des jeunes sportifs données plus haut soient celles de 8 filles de hauteurs { 152, 152, 160, 161, 163, 173, 175, 175 } et 6 garçons de hauteurs { 154, 161, 162, 163, 173, 191 }. On peut représenter ces deux ensembles de données au moyen du diagramme bidirectionnel suivant, les filles étant à gauche et les garçons à droite :

 22|15|4
310|16|123
553|17|3
   |18|
   |19|1

Squelette

Pour démarrer, nous vous fournissons une archive Zip contenant :

  • quatre fichiers de données (stage-1.txt à stage-4.txt) dans le répertoire data, contenant les dates et heures des rendus acceptés par notre serveur de rendu pour les étapes 1 à 4,
  • une classe TimestampReader permettant de lire ces fichiers de données,
  • une classe Main lisant un fichier de données et l'affichant à l'écran,
  • un squelette de classe StemPlot représentant un diagramme tige et feuille, à compléter.

Importez le contenu de cette archive dans un nouveau projet Eclipse, et ajoutez-y le répertoire data comme répertoire source, en suivant les indications données en bas de notre guide d'importation dans Eclipse.

Une fois cela fait, vous devriez pouvoir exécuter la méthode main de la classe Main et voir s'afficher à l'écran la liste des heures de rendu de l'étape 1, sous forme d'entiers (voir plus bas pour leur format) :

[172, 172, 172, 172, 172, 171, 171, 171, 171, …

Si vous obtenez une exception, vérifiez que vous avez bien ajouté le répertoire data comme répertoire source, comme expliqué ci-dessus.

Exercice 1 : Diagramme unidirectionnel

Le but du premier exercice est de compléter la méthode print de la classe StemPlot, permettant d'afficher un diagramme tige et feuille unidirectionnel.

Méthode print

La méthode print prend en argument une collection d'entiers supposés positifs et affiche le diagramme tige et feuille correspondant.

Pour afficher ce diagramme, nous vous conseillons de construire une table associative de type Map<Integer, List<Integer>> associant à chaque tige (un entier) la liste de ses feuilles (des entiers à un seul chiffre), triées par ordre croissant. Une fois cette table construite, l'affichage du diagramme est relativement simple.

Dans un premier temps, contentez-vous d'écrire la méthode print de la manière qui vous semble la plus naturelle, et vérifiez qu'elle fonctionne en dessinant le diagramme tige et feuille correspondant au rendu de l'étape 1.

Notez que la méthode hours de la classe Main que nous vous fournissons, qui transforme les heures en entiers à dessiner sous forme de diagramme tige et feuille, représente les heures au moyen d'entiers compris entre 0 et 235. Les deux premiers chiffres représentent l'heure, le dernier la dizaine de minutes. Par exemple, 16h57 est représenté par l'entier 165.

Alignement des tiges

La méthode print que vous avez écrite présente probablement le problème suivant : les tiges ne sont pas toutes alignées, car certaines font un caractère de large, d'autres deux. Dans ce cas, les lignes des tiges 9 et 10 se présentent ainsi :

9|01115
10|12334455

Pour résoudre ce problème d'alignement, le plus simple est d'utiliser la méthode format de la classe String. Cette méthode permet de formatter différents types de données sous forme de chaîne de caractères et prend un nombre variable d'arguments :

  • le premier est la chaîne de formattage, qui contient un mélange de texte libre et de séquences de formattage, commençant chacune par le caractère pourcent (%) et destinées à être remplacées par une donnée formattée,
  • les suivants (un par séquence de formattage présente dans la chaîne de formattage) sont les données à insérer.

Le format de la chaîne de formattage est bien documenté mais assez complexe. Toutefois, l'alignement des tiges peut se faire très simplement, comme l'exemple ci-dessous l'illustre :

String s1 = String.format("%2d", 9);  // " 9"
String s2 = String.format("%2d", 10); // "10"

Les deux chaînes s1 et s2 font deux caractères, mais la première commence par une espace afin justement que le nombre qu'elle formatte ait une largeur de deux caractères. Ce comportement est dû à la chaîne de formattage passée (%2d), qui spécifie que :

  • la prochaine valeur (%),
  • doit être formattée sur deux caractères (2),
  • sous la forme d'un entier décimal (d).

Inspirez-vous de cet exemple pour aligner correctement les tiges.

Utilisation de computeIfAbsent

Pour terminer cet exercice, essayez de rendre votre méthode print plus concise en vous aidant de la méthode computeIfAbsent de l'interface Map, qui n'a pas été examinée au cours mais dont vous devriez pouvoir comprendre le fonctionnement en lisant sa documentation.

Exercice 2 : Diagramme bidirectionnel

Ajoutez à la classe StemPlot une seconde variante de la méthode print prenant deux collections d'entiers en arguments et dessinant un diagramme tige et feuille bidirectionnel avec ces données.

Pour que les feuilles de la partie gauche fassent toutes la même longueur, vous pouvez une fois de plus utiliser la méthode format de la classe String, en vous inspirant de l'extrait de programme suivant :

String s1 = String.format("%5s", "ah");  // "   ah"
String s2 = String.format("%5s", "bon"); // "  bon"

Notez que cette fois la chaîne de formattage utilise un s (pour string) à la place du d (pour decimal) utilisé plus haut, car ici la donnée à formatter est une chaîne de caractères.

N'hésitez pas, dans un premier temps en tout cas, à utiliser une largeur fixe de 30 caractères (p.ex.) pour aligner les feuilles de la partie gauche du diagramme.

Une fois votre méthode terminée, testez-la en dessinant un diagramme tige et feuille bidirectionnel pour les heures de rendu des étapes 3 et 4, par exemple.