• Aucun résultat trouvé

Amélioration des représentations graphiques des résultats de simulations du logiciel PamHyr

N/A
N/A
Protected

Academic year: 2021

Partager "Amélioration des représentations graphiques des résultats de simulations du logiciel PamHyr"

Copied!
60
0
0

Texte intégral

(1)

HAL Id: hal-02600081

https://hal.inrae.fr/hal-02600081

Submitted on 16 May 2020

HAL is a multi-disciplinary open access archive for the deposit and dissemination of sci- entific research documents, whether they are pub- lished or not. The documents may come from teaching and research institutions in France or abroad, or from public or private research centers.

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des établissements d’enseignement et de recherche français ou étrangers, des laboratoires publics ou privés.

Amélioration des représentations graphiques des résultats de simulations du logiciel PamHyr

S. Riess

To cite this version:

S. Riess. Amélioration des représentations graphiques des résultats de simulations du logiciel PamHyr.

Sciences de l’environnement. 2014. �hal-02600081�

(2)

IUT Nancy Charlemagne Université de Lorraine

2 ter Boulevard Charlemagne 54042 Nancy Cedex

Département Informatique

Amélioration des représentations graphiques des résultats de simulations

du logiciel PamHyr

Rapport de stage DUT informatique

Sylvain RIESS

Année Spéciale 2013-2014

(3)
(4)

IUT Nancy Charlemagne Université de Lorraine

2 ter Boulevard Charlemagne 54042 Nancy Cedex

Département Informatique

Amélioration des représentations graphiques des résultats de simulations

du logiciel PamHyr

Rapport de stage DUT informatique

Irstea - UR Hydrologie-Hydraulique Centre de Lyon-Villeurbanne

5 rue de la Doua CS 70077

69626 Villeurbanne Cedex

Stagiaire : Sylvain RIESS

Tuteur en entreprise : Jean-Baptiste FAURE

Parrain de stage : Yann BONIFACE

(5)

Remerciements

Je tiens à remercier dans un premier temps toute l’équipe Hydrologie-Hydraulique pour son accueil chaleureux et sa sympathie.

Je remercie tout particulièrement mon tuteur Jean-Baptiste Faure ainsi que Sylvain Vigneau

pour le temps qu’ils m’ont consacré et l’aide qu’ils m’ont apportée tout au long de ces trois

mois de stage. Cette expérience fut grâce à eux très intéressante et extrêmement enrichissante.

(6)

Table des matie res

I. LE CONTEXTE DU STAGE...6

A. PRESENTATION D’IRSTEA ...6

1. L’INSTITUT ... 6

2. LE CENTRE DE LYON ET SES SERVICES INFORMATIQUES... 7

B. LE STAGE ...8

1. LES PROJETS PAMHYR ET ADIS-TS ... 8

2. LE SUJET DU STAGE ... 9

II. CONSTRUCTION DU CŒUR DE L’APPLICATION : LE MODELE ... 10

A. MISE EN PLACE DE LA STRUCTURE DU CODE ... 10

1. LES DONNEES DE DEPART ... 10

2. LES CHOIX INITIAUX ... 11

3. MODELISATION UML ... 13

B. RECUPERATION DES DONNEES DEPUIS UN CSV ... 16

C. CONSTRUCTION DES OBJETS DE STOCKAGE... 19

III. ÉLABORATION DE LA VUE ... 21

A. CONSTRUCTION DE LA FENETRE DE SELECTION ... 21

1. MISE EN PLACE DES ELEMENTS ... 21

2. AJOUT DE NOUVELLES FONCTIONNALITES AU TABLEAU DE SELECTION ... 23

3. AMELIORATIONS APPORTEES AUX LISTES LATERALES ... 24

B. AFFICHAGE DES GRAPHIQUES DE COURBES... 26

1. JFREECHART ... 26

2. LA MOSAÏQUE DE GRAPHIQUES ... 28

IV. AJOUT DES DIAGRAMMES EN BATONS ET PREPARATION AU BETA-TEST ... 33

A. REUTILISATION/MODIFICATION DES STRUCTURES EXISTANTES... 33

1. LE MODELE ... 33

2. LA VUE ... 34

B. AJOUT DE NOUVELLES STRUCTURES ... 36

1. LE SELECTEUR DE TEMPS ... 36

2. AUTRES ELEMENTS ... 39

(7)

5

Introduction

Irstea est un organisme de recherche qui, depuis plus de 30 ans, travaille sur les enjeux majeurs d’une agriculture responsable et de l’aménagement durable des territoires, la gestion de l’eau et les risques associés, sécheresse, crues, inondations, l’étude des écosystèmes complexes et de la biodiversité. De nombreux projets informatiques y sont développés, et l’environnement de modélisation hydraulique PamHyr, qui simule des écoulements en rivière, en fait partie. On lui intègre actuellement Adis-TS, un code de calcul en ligne de commande pour la simulation du transport de polluants. Grâce à un logiciel externe, ce solveur peur afficher les résultats sous forme de courbes simples. Mon stage consiste à mettre sur pied une interface graphique permettant d’offrir à l’utilisateur un choix plus large de représentations graphiques tout en lui facilitant la sélection des résultats qu’il veut voir apparaître.

La première partie de ce rapport présentera Irstea, le centre de Lyon-Villeurbanne et le

contexte du stage. Le deuxième chapitre abordera la mise en place du cœur du programme,

qui manipule et stocke les données dans les objets adéquats. La troisième partie détaillera

l’implémentation de l’affichage de ces données sous forme de courbes. Nous verrons enfin,

dans un dernier point, la mise en œuvre d’un autre type de représentations graphiques.

(8)

6

I. Le contexte du stage A. Présentation d’Irstea

1. L’institut

Irstea, acronyme d’Institut national de Recherche en Sciences et Technologies pour l’Environnement et l’Agriculture, fait partie des Etablissements Publics à caractère Scientifique et Technologique (EPST) au même titre que, par exemple, le CNRS

1

ou l’INRA

2

. Son historique est présenté en annexe A. Les thèmes de recherche actuels de l’institut sont centrés sur les ressources en eau de surface, les systèmes écologiques aquatiques et terrestres, les espaces à dominante rurale, les technologies pour l’eau, les agrosystèmes et la sûreté des aliments.

L’établissement, dont les services généraux sont situés à Antony (92), possède neuf directions régionales et une implantation hors centre (cf. annexe B) pour un budget de 115 millions d’euros. Ces implantations géographiques regroupent 19 Unités de Recherche propres (UR) et 5 Unités Mixtes de Recherche (UMR) pour un total de 1750 collaborateurs. Ces unités de recherche sont réparties suivant trois départements scientifiques :

le département Eaux,

le département Ecotechnologies,

le département Territoires.

Irstea est engagé dans de nombreux partenariats avec des organismes aussi bien publics (collectivités territoriales, agences de l’eau par exemple) que privés (EDF, Suez Environnement, Veolia, …). L’institut fait aussi partie de plusieurs réseaux nationaux et internationaux.

Figure 1 : logo d'Irstea

1 Centre National de la Recherche Scientifique

2 Institut National de la Recherche Agronomique

(9)

7

2. Le centre de Lyon et ses services informatiques

Le centre de Lyon-Villeurbanne compte environ 220 agents dont 115 permanents, 35 doctorants/post-doctorants, 40 agents contractuels et un nombre variable de stagiaires pouvant aller jusqu’à 40. Son organigramme et son budget à la clôture 2013 sont présentés en annexe B. Le centre possède deux unités de recherche propres appartenant au département Eaux :

MAEP (Milieux Aquatiques, Ecologie et Pollutions) qui cherche à fournir des réponses opérationnelles pour le diagnostic des pollutions et des perturbations induites par les ouvrages hydrauliques ou les aménagements de rivière ;

HH (Hydrologie-Hydraulique) qui traite des problématiques suivantes : lutte contre les crues, inondations et sécheresses ; dimensionnement des aménagements ; entretien et gestion du lit des rivières ; impact des activités humaines et du changement climatique sur la quantité et la qualité des ressources en eaux.

On trouve à Irstea Lyon-Villeurbanne deux services informatiques :

en interne le service SI (Systèmes d’Information), composé de trois personnes qui gèrent à la fois l’infrastructure informatique du centre (installation et maintien des machines, création des comptes des collaborateurs, support informatique, gestion des serveurs) et des missions à compétence nationale ;

le pôle IS (Informatique Scientifique) est une implantation locale d’un service national. Il se consacre aux systèmes d’information spécifiques aux activités de recherche. Regroupant sept collaborateurs, il est chargé de trois tâches :

gestion des bases et entrepôts des données scientifiques,

développement logiciel et modélisation,

calcul numérique et simulation.

Bien que j’aie eu quelques contacts avec les membres de ces deux services, mon stage s’est

déroulé au sein de l’équipe « Hydraulique des Rivières » de l’unité HH dont Jean-Baptiste

Faure, mon tuteur, est le responsable. Détaillons à présent le sujet du stage que j’ai effectué

sous son encadrement.

(10)

8

B. Le stage

1.

Les

projets PamHyr et Adis-TS

Parmi les projets informatiques développés au sein d’Irstea se trouve l’environnement de modélisation hydraulique PamHyr qui réalise des simulations numériques d’écoulements en rivières. Développé depuis 1997, écrit en Java et utilisable sur Windows et Linux, PamHyr pilote le solveur externe MAGE, programmé en Fortran, dont le rôle est d’effectuer tous les calculs hydrauliques relatifs à la simulation. PamHyr permet de gérer les données fournies à ce solveur et de mettre en forme les résultats obtenus.

En 2008 un nouveau moteur de calcul appelé Adis-TS (Advection-dispersion Transport Solide) a été mis au point. Destiné à effectuer des simulations de transport de polluants dissous et de sédiments fins en suspension, il n’est pour l’instant exécutable qu’en ligne de commande sous Linux. Un couplage avec le logiciel de représentations graphiques Gnuplot également en ligne de commande permet de tracer des courbes simples de la forme où x peut être un temps ou une coordonnée spatiale (cf. figure suivante).

Figure 2 : exemple de courbe produite par Gnuplot

Lors d’une simulation d’écoulement sur un réseau hydrographique, MAGE et Adis-TS réalisent des calculs sur un ensemble de points du réseau et les stockent sous forme binaire.

Adis-TS effectue également un enregistrement en certains de ces points sous forme d’un fichier texte. Ces points sont déterminés par une découpe du réseau en tronçons appelés biefs.

Ces biefs, qui constituent donc des portions de cours d’eau, sont reliés par des nœuds (cf.

figure suivante). En plus des biefs, l’utilisateur peut spécifier à Adis-TS d’enregistrer les

résultats en des points particuliers qu’il choisit préalablement au lancement de la simulation.

(11)

9 Figure 3 : découpe d'un réseau en biefs (traits bleus) reliés par des noeuds (ronds colorés), les flèches

indiquant le sens d’écoulement

2. Le sujet du stage

L’intégration d’Adis-TS dans PamHyr est en cours de réalisation, c’est le travail du développeur Sylvain Vigneau qui travaille en étroite collaboration avec Jean-Baptiste Faure.

Lorsque cette intégration sera effective, Adis-TS devra proposer à l’utilisateur une interface adaptée et intuitive qui lui permettra de facilement sélectionner les résultats à afficher, et de les représenter sous diverses formes : courbes, diagrammes circulaires ou en bâtons par exemple. Mon stage consiste à commencer le développement, avec l’assistance de Jean- Baptiste et Sylvain, de cette interface en langage Java. Nous avons pour objectif de rendre opérationnel l’affichage des courbes et des diagrammes en bâtons pour mon départ.

En ce qui concerne mon poste de travail Jean-Baptiste, fervent défenseur des logiciels libres, m’avait demandé préalablement à mon arrivée si j’avais une préférence entre Windows et Linux. Ayant répondu que les deux systèmes d’exploitation me convenaient pareillement, c’est un ordinateur muni de Kubuntu 13.10 qui m’a été dévolu. Le seul outil imposé pour mon stage est le dépôt git du projet PamHyr hébergé sur la forge logicielle

3

d’Irstea. J’en utiliserai personnellement deux autres qui me semblent indispensable pour développer en Java :

l’environnement de développement intégré libre Eclipse,

le logiciel de représentation UML open source ArgoUML, qui me servira de support pour élaborer le diagramme de classes du programme dont le prochain chapitre abordera la construction.

3 Système de gestion de développement collaboratif de logiciels

(12)

10

II. Construction du cœur de l’application : le Modèle A. Mise en place de la structure du code

1. Les données de départ

Une simulation de transport de polluants effectuée par Adis-TS produit, pour chaque polluant, trois fichiers de deux types différents :

un fichier binaire de résultats bruts,

deux fichiers texte au format CSV

4

.

Les fichiers CSV synthétisent les résultats stockés dans le fichier binaire -dont ne nous occuperons pas- et constituent le point de départ de création de l’interface : toute l’implémentation de cette dernière repose sur les informations présentes dans ces deux fichiers. Ils constituent la seule base à partir de laquelle seront extraites toutes les données qui seront retrouvées dans l’application à développer. Leur contenu est le suivant :

un fichier intitulé nom_polluant.csv (cf. tableau I) qui regroupe, pour chaque pas de temps :

les concentrations du polluant en amont (entrée) et en aval (sortie) de chaque bief,

les concentrations du polluant en certains points particuliers définis par l’utilisateur,

le cumul des masses : entrées dans le réseau, sorties du réseau, stockées dans l’eau et déposées au fond,

un bilan de masses ;

Tableau I : structure du fichier nom_polluant.csv

Signification des titres de colonnes Temps Camont

bief 1

Caval

bief 1

Camont

bief 2 … Cpoint1 … ∑masses

entrée

masses

sortie

masses

eau

masses

fond Bilan Titres de colonnes du fichier CSV

T Amont

bief01

Aval bief01

Amont

bief02 … Nom1 … M.entrant M.sortant Stock H2O

Stock

Fond Bilan T0

T1

4 Comma-separated values : format informatique ouvert représentant des données tabulaires sous forme de valeurs délimitées par un caractère de séparation (généralement une virgule)

(13)

11

un fichier intitulé nom_polluant_masse.csv (cf. tableau II) décrivant, pour chaque pas de temps :

la masse du polluant dans chaque bief,

le cumul des masses entrées et sorties du réseau (information déjà présente dans le fichier précédent).

Tableau II : structure du fichier nom_polluant_masse.csv

Signification des titres de colonnes

Temps Masse

bief 1

Masse

bief 2 … ∑masses

entrée

masses

sortie Titres de colonnes du fichier CSV

T Bief_01 Bief_02 … masse entrant masse sortant

T0 T1

Notons que, pour une même simulation, tous les fichiers du type nom_polluant.csv possèdent les mêmes noms de colonnes et tous ceux du type nom_polluant_masse.csv possèdent également les mêmes noms de colonnes. La liste des temps, elle, est commune à tous les fichiers CSV. Les unités de ces derniers sont les suivantes : les temps sont exprimés en jours décimaux, les concentrations en g/L et les masses en kg.

2. Les choix initiaux

Dans un premier temps, plusieurs choix d’implémentation ont été adoptés en concertation

avec mes deux tuteurs. Le plus important d’entre eux, l’utilisation du design pattern MVC

(Modèle-Vue-Contrôleur), s’est naturellement imposé. Cette façon de programmer introduit

une barrière (le Contrôleur) entre les données (le Modèle) et leur représentation (la Vue). Le

Contrôleur a pour rôle de faire le lien entre le Modèle et la Vue, et de centraliser les échanges

d’informations qui s’opèrent entre ces derniers. Ce pattern, qui découpe la structure du code

en trois entités distinctes, a pour principal avantage de faciliter la maintenance et les

modifications ultérieures du programme, et améliore ainsi grandement la souplesse de

l’implémentation. En effet, s’il est décidé dans le futur de modifier le Modèle ou la Vue, seule

une partie du code sera à réécrire car le reste sera réutilisable.

(14)

12

Afin de faciliter mon travail et pour ne pas me perdre dans le code j’ai cherché à suivre des méthodes « agiles ». Leur principe est de programmer en réalisant des cycles successifs courts d’implémentation/test/discussion avec les acteurs du projet/ajustement du code (cf. figure suivante). Particulièrement utile lorsque le but à atteindre est flou, imprécis, ces méthodes itératives permettent une adaptation constante du projet aux besoins apparaissant au cours de son élaboration.

Figure 4 : schéma de fonctionnement des méthodes agiles

Mon but premier a donc été d’obtenir une interface basique, sur laquelle effectuer des tests afin de la faire évoluer dans le bon sens. Pour la mettre au point j’ai choisi de ne gérer pour commencer qu’un seul polluant, soit deux fichiers CSV. Je me suis également concentré sur un seul type de représentation graphique : les courbes représentant la concentration ou la masse dans un bief en fonction du temps. Cette interface prototype, bien que simplifiée, devait cependant être capable d’afficher plusieurs courbes sur un même graphique.

Préalablement à mon arrivée, mes encadrants avaient envisagé d’utiliser un tableau comme

structure principale de sélection des choix de l’utilisateur (cf. tableau III). L’idée m’a plu et

nous avons convenu que chaque ligne du tableau correspondrait à un graphique. Chaque

colonne des fichiers CSV se retrouverait dans le tableau et serait constituée de booléens. Un

booléen « vrai » indiquerait que l’utilisateur veut voir s’afficher la courbe temporelle

correspondante.

(15)

13 Tableau III : structure envisagée pour la sélection des courbes par l'utilisateur

Enfin il était prévu de déléguer l’affichage des graphiques à la bibliothèque open source

JFreeChart que Sylvain avait déjà utilisée par le passé et dont il avait pu tester quelques

possibilités.

3. Modélisation UML

a) Le Modèle

De manière générale en programmation orientée objet, il est essentiel de réfléchir avant toute chose aux classes dont on va avoir besoin dans notre programme. Je me suis donc attaché au début de mon stage à mettre au point un premier diagramme de classes UML, ceci afin de me constituer un schéma de base solide sur lequel m’appuyer pour élaborer mon prototype.

Dans un premier temps je me suis concentré sur la représentation UML du Modèle, qui constitue le cœur du programme. Le premier rôle de l’interface est de montrer à l’utilisateur les résultats dont il dispose. Pour cela, deux classes m’ont paru nécessaires au Modèle :

une classe

MyCsvReader, capable de parcourir un fichier CSV pour en extraire des

données ;

une classe ParamSim, stockant les paramètres de simulation issus des CSV : titres des colonnes et liste de tous les pas de temps de calcul.

Temps initial

Temps final

Amont bief01

Aval bief01

Amont bief02

Aval

bief02 … Nom1 Nom2 …

Graphique A TdébutA TfinA X X X

Graphique B TdébutB TfinB X X X

Graphique C TdébutC TfinC

M.entrant M.sortant Stock H2O

Stock

Fond Bilan Masse bief01

Masse

bief02 …

X

X

X X X X X

(16)

14

Ensuite, considérant que l’interface à mettre en place doit permettre à la fois à l’utilisateur de sélectionner les données qu’il veut afficher et de les afficher, deux nouvelles classes se sont imposées dans le Modèle :

une classe

ParamUser destinée à mémoriser les choix des utilisateurs : courbes à

afficher et intervalle de temps à représenter. Ces courbes sont à sélectionner dans la liste des colonnes des CSV et l’intervalle de temps est obligatoirement compris dans la liste de tous les pas de temps de calcul de la simulation, nous voyons donc que ParamUser est un sous-ensemble de ParamSim. J’ai traduit ce fait dans mon implémentation en faisant hériter ParamUser de ParamSim ;

une classe DataCurve regroupant pour un graphique les données à afficher issues des CSV.

Il apparaît ainsi qu’une seule instance des classes MyCsvReader et ParamSim est nécessaire.

En revanche, chaque ligne du tableau de sélection est liée à une instance de ParamUser et de DataCurve. Cependant cette instance de DataCurve correspond à un graphique qui peut représenter plusieurs courbes. J’ai donc instauré une nouvelle classe

DataY qui contient les

données CSV relatives à une seule courbe. Une instance de DataCurve inclut ainsi plusieurs instances de DataY et l’intervalle de temps qui est commun à toutes les courbes. Pour mieux représenter les choses les tableaux suivants reprennent les tableaux I et II avec les nouvelles notations UML que nous venons de voir :

Tableau IV : extrait du tableau I illustrant la structure de la classe ParamUser

Tableau V : extrait du tableau II illustrant la structure des classes DataY et DataCurve Temps

initial

Temps final

Amont bief01

Aval bief01

Amont bief02

Aval

bief02 …

DataCurve D TdébutA TfinA DataY1 DataY2

DataCurve D’ TdébutB’ TfinBDataY1’ DataY2’

Temps initial courbe

Temps final courbe

Amont bief01

Aval bief01

Amont bief02

Aval

bief02 …

ParamUser P Tdébut Tfin vrai vrai

ParamUser P’ Tdébut’ Tfin’ vrai vrai

(17)

15

Les classes principales du Modèle ont été établies et nous pouvons à présent les relier entre elles avec les bonnes cardinalités (cf. figure suivante).

Figure 5 : diagramme de classes schématique du Modèle

b) La Vue

L’essentiel pour mon début de stage était de réussir à mettre un place un premier diagramme UML se concentrant sur le Modèle, le véritable cœur de l’application. La Vue, certes importante pour ce dernier, m’a semblé moins utile à détailler du point de vue de l’UML.

Ayant été décidé que la structure dédiée aux choix utilisateur prendrait la forme d’un tableau, j’ai envisagé les classes suivantes :

une classe

Table qui hérite de

javax.swing.JTable. Cette classe est basée sur une classe TableModel héritant de javax.swing.table.DefaultTableModel ;

une classe

TablePanel qui hérite de

javax.swing.JPanel, chargée d’afficher le tableau.

Je n’ai pas été plus loin concernant la structure de la Vue, qui serait enrichie ultérieurement.

Le Contrôleur, quant à lui, a pour rôle principal de vérifier les données échangées entre le Modèle et la Vue afin de s’assurer de leur validité. Je l’ai modélisé sous la forme d’une classe

Controller.

J’ai ainsi obtenu une ébauche de diagramme de classes UML (cf. annexe C dont certaines notations sont expliquées au chapitre II.C), qui m’a servi de structure de base pour mon implémentation. Ce diagramme est à prendre comme une première mouture imprécise et incomplète que j’ai fait évoluer parallèlement à mon application tout au long de ces trois mois de stage.

1 1

1..N 0..N

1 1 1

0..N

MyCsvReader ParamSim

ParamUser

DataCurve

DataY

(18)

16

B. Récupération des données depuis un CSV

a) Utilisation d’un parseur

La première étape de l’implémentation a été de mettre en place la lecture du contenu des fichiers CSV. Je pensais initialement coder cela moi-même mais Sylvain m’a suggéré de plutôt chercher sur Internet un parseur CSV adapté à nos besoins. Après quelques recherches et comparaisons j’ai choisi d’utiliser la bibliothèque

opencsv (licence Apache 2.0) qui m’a

semblé rapide et efficace d’après ce que j’avais lu. Elle proposait des fonctions basiques, ce qui n’était pas un problème puisque j’avais juste besoin de parcourir le fichier CSV et d’en extraire certaines valeurs.

J’ai ainsi commencé à intégrer la bibliothèque à ma classe MyCsvReader mais un problème est apparu : les fichiers CSV produits par Adis-TS n’étaient pas d’authentiques CSV. Un fichier CSV au sens strict du terme utilise comme séparateur la virgule (« comma » en anglais). Les autres séparateurs habituels sont le point-virgule et la tabulation. Mais, comme on peut le voir sur la figure suivante, la façon qu’avait Adis-TS d’enregistrer les fichiers résultats faisait en sorte que les valeurs étaient séparées par deux espaces (cf. figure suivante).

Et opencsv s’est révélée totalement incapable de gérer ce type d’écriture de CSV.

Figure 6 : CSV généré par Adis-TS avec une double espace pour séparateur

En effet le parseur n’a jamais accepté la double espace comme délimiteur, il n’autorisait que

des caractères et non des chaînes. Et en essayant avec une espace simple la première était bien

reconnue comme séparateur mais la seconde était lue comme une donnée, ce qui me rajoutait

de nombreuses chaînes vides et inutiles - mais bien présentes - dans le tableau de String

renvoyé par ce dernier. Après avoir essayé un autre parseur et effectué des recherches sur

(19)

17

Internet, j’ai acquis la conviction qu’ils présentaient tous la même restriction. Pour contourner le problème j’ai proposé deux solutions :

exploiter la méthode Java

split(String regex).

En effet l’utilisation du parseur se limitait dans notre cas à la lecture ligne par ligne du fichier CSV. Nous pouvions a priori nous en passer et mettre en œuvre la méthode précédente qui découpe une chaîne de caractères suivant l’expression régulière

5

en paramètre et retourne un tableau de String. Le test préalable que j’avais réalisé en appliquant la méthode split(\\s+) s’était avéré concluant pour éliminer les doubles espaces séparatrices ;

modifier l’écriture des CSV par Adis-TS en introduisant un point-virgule en guise de délimiteur, parfaitement géré par les parseurs.

Après une discussion réunissant mes tuteurs, deux personnes du pôle IS et moi nous avons convenu d’appliquer ma seconde solution (cf. figure suivante), et ce pour trois raisons :

la modification n’était pas difficile à réaliser,

les fichiers CSV issus d’Adis-TS n’étaient utilisés par aucune autre application (donc pas de changements à répercuter),

reconstruire les fichiers dans un format de CSV standard pouvait s’avérer bénéfique en vue d’éventuelles améliorations futures.

Figure 7 : nouveau fichier CSV avec un point-virgule pour séparateur

5 Chaîne de caractères dessinant un motif qui représente un ensemble de chaînes de caractères selon une syntaxe spécifique

(20)

18 b) Gestion des erreurs de lecture

Comme on peut le voir sur les deux figures précédentes, les résultats sont écrits dans les CSV en notation scientifique : une mantisse suivie de la lettre E puis l’exposant. Quelques tests effectués m’ont montré que la méthode Java

parseDouble(String s) gérait parfaitement la

conversion d’une chaîne de caractères représentant un nombre écrit sous forme scientifique en float ou double. Cependant il restait toujours la possibilité que certaines valeurs du fichier CSV ne puissent pas être converties par la méthode précédente, conduisant à la levée d’une NumberFormatException. J’ai donc mis en place un bloc try/catch permettant de capturer cette exception et d’afficher une boîte de dialogue modale

6

(cf. figure suivante) fournissant plusieurs informations :

la ligne et la colonne concernées afin que l’utilisateur puisse aisément consulter la valeur dans le CSV,

un message indiquant que dans la suite des traitements effectués par l’application cette valeur sera considérée nulle.

Figure 8 : boîte de dialogue modale apparaissant en cas d'erreurs de lecture

A noter qu’au début de mon implémentation j’avais utilisé le type float (nombre réel codé sur 4 octets). Je me suis cependant aperçu que cela me générait des imprécisions lors de la lecture des CSV : le dernier chiffre de chaque donnée récupérée était en effet très souvent faussé. Me doutant de l’origine du problème, j’ai transformé les float en double (nombre réel codé sur 8 octets) ce qui a rétabli la justesse des résultats enregistrés.

6 Boîte de dialogue qui bloque toute interaction avec les autres composants tant que l’utilisateur n’a pas mis fin au dialogue

(21)

19

C. Construction des objets de stockage

Je me suis ensuite attaché à implémenter les autres classes du Modèle schématisé à la figure 5 (cf. figure suivante). Leur rôle était de « stocker » diverses informations dont nous allons parler plus en détail.

La classe ParamSim regroupe les informations relatives à la simulation extraites des CSV, à savoir :

columnTitlesCsvConcentrations : liste des titres de colonnes du fichier CSV

nom_polluant.csv ;

columnTitlesCsvMasses : liste des titres de colonnes du

fichier CSV nom_polluant_masse.csv ;

timeList : liste de tous les pas de temps de calcul.

La classe ParamUser a pour rôle de stocker les choix de représentation des utilisateurs. Elle contient l’intervalle de temps et les noms des colonnes sélectionnées (cf. tableau IV), qui sont des sous-ensembles des attributs de ParamSim. Il semble donc intéressant de considérer ParamUser comme héritant de ParamSim.

Les classes DataY et DataCurve servent à stocker les valeurs extraites des CSV correspondant aux choix utilisateur. DataY représente les données relatives à une courbe et inclut :

listY : liste de toutes les valeurs (i.e. toutes les ordonnées) de la courbe ;

columnTitle : titre de la courbe (soit le nom de la colonne du CSV) ;

columnUnit : unité de la courbe.

DataCurve représente les données relatives à un graphique. Puisque ce graphique peut contenir plusieurs courbes, cette classe possède les attributs suivants :

dataYList : liste de DataY relatives à chacune des courbes ;

listX : liste des temps du graphique (i.e. valeurs des abscisses).

J’ai utilisé à plusieurs reprises le terme de « liste » dans la description de mes classes. En

Java, ces rassemblements d’objets de même type peuvent être implémentés par des tableaux

ou par des collections. Lorsque j’ai commencé à coder je me suis interrogé sur le meilleur

choix. En raison de leurs limitations (entre autres l’impossibilité de modifier leur taille) j’ai

rapidement mis de côté l’utilisation des tableaux. Après m’être renseigné sur les différents

types de collections possibles j’ai réduit le choix à Vector et ArrayList. Constatant très peu de

(22)

20

différences j’ai débuté en utilisant la classe Vector. Puis je me suis aperçu à plusieurs reprises qu’elle s’avérait moins pratique que ne l’aurait été ArrayList. N’ayant pas encore beaucoup programmé j’ai alors décidé de basculer mes listes en ArrayList. J’ai également pris la résolution de dorénavant déclarer autant que possible mes listes en utilisant l’interface

List.

Cette façon de faire permet de faciliter une éventuelle nouvelle modification ultérieure puisque toutes les listes (Vector et ArrayList entre autres) implémentent cette interface.

Figure 9 : diagramme de classes UML du Modèle

(23)

21

III. Élaboration de la Vue

A. Construction de la fenêtre de sélection 1. Mise en place des éléments

Après avoir implémenté la structure du Modèle j’ai commencé à travailler sur la Vue, et notamment sur la fenêtre de sélection à travers laquelle les utilisateurs spécifient les graphiques qu’ils veulent construire.

Comme nous l’avons vu dans le chapitre II.A.2, le choix avait été fait de se baser sur un tableau comme élément principal de sélection. Les recherches et analyses que j’avais effectuées pour préparer mon diagramme UML m’avaient amené à prévoir un

DefaultTableModel pour gérer les données de ce tableau. Cependant le passage de

Vector à ArrayList, non gérée par ce type de TableModel, m’a conduit à lui préférer la classe abstraite

AbstractTableModel qui ne posait pas ce genre de problème.

Lors des discussions préalables à l’implémentation que j’avais eues avec mes tuteurs, nous avions prévu de mettre en place un tableau similaire au tableau III vu précédemment. A l’exception de la colonne des temps, chaque colonne présente dans chacun des deux fichiers CSV se retrouvait dans le tableau de sélection (sans toutefois répéter inutilement les colonnes des sommes des masses entrées et sorties qui sont dans les deux fichiers). J’avais encapsulé ce dernier dans un JScrollPane pour faire apparaître une barre de défilement facilitant son parcours. Les premiers affichages que j’ai obtenus ont cependant révélé qu’inclure d’emblée toutes les colonnes dans le tableau n’était pas très pratique. Lors de simulations incluant couramment plusieurs dizaines de biefs et de points particuliers, il devenait bien trop grand pour être aisément manipulable même avec une barre de défilement. J’ai donc apporté des modifications afin que, au lancement :

le tableau n’affiche plus que les deux colonnes de temps,

dans la fenêtre s’affichent deux listes de type

JList contenant les titres de colonnes

des deux fichiers CSV.

J’ai également muni chaque liste de deux composants :

un bouton « Ok » permettant de faire apparaître dans le tableau la ou les colonne(s) sélectionnée(s) dans la liste,

une liste déroulante à deux éléments permettant de trier alphabétiquement cette liste si

besoin.

(24)

22

A ce stade de l’implémentation, le système d’ajout de colonnes dans le tableau se déroule de la manière suivante (cf. annexe D) :

1) Au lancement du programme apparait une première ligne avec deux colonnes

« Début » et « Fin » de valeur 0 (la sélection des temps n’étant pas encore effective) ; 2) L’utilisateur sélectionne dans une liste une ou plusieurs colonnes qu’il veut ajouter ; 3) En cliquant sur « Ok » les colonnes sont créées dans le tableau. Des booléens « vrai »

sont affectés à l’intersection de notre première ligne et de ces colonnes. A noter que le JTable transforme l’affichage des booléens en cases à cocher, ce qui améliore le rendu graphique ;

4) L’utilisateur renouvelle l’opération pour ajouter toutes les colonnes qu’il désire. Il peut également décocher des colonnes s’il change d’avis ;

5) Une fois satisfait il clique sur un bouton « Valider la ligne courante » qui empêche toute nouvelle modification de cette ligne (en rendant les cellules non éditables) et crée une nouvelle ligne. Cette ligne est identique à la précédente à la différence que tous ses booléens sont à « faux » ;

6) L’utilisateur rajoute des colonnes et il peut se passer deux choses :

a. si la colonne n’est pas présente dans le tableau, elle est ajoutée avec un booléen

« faux » pour toutes les lignes du tableau sauf la ligne en cours d’édition qui reçoit un booléen « vrai » ;

b. si elle est déjà présente le booléen correspondant à la ligne en cours d’édition est simplement passé à « vrai ».

7) Lorsqu’il le désire l’utilisateur peut valider la ligne, ce qui la rend alors non éditable et crée une nouvelle ligne munie de booléens « faux ».

Pour l’instant nous ne nous sommes intéressés dans ce chapitre qu’à la Vue. Mais les actions effectuées par l’utilisateur dans le tableau ont bien évidemment des conséquences sur le Modèle et sur les objets de stockage. A chaque validation de ligne, deux instances d’objet sont créées et viennent chacune incrémenter une ArrayList en attribut de MyCsvReader :

une instance de ParamUser qui contient les temps de début et de fin, le nom des colonnes de concentrations et de masses sélectionnées pour cette ligne ;

une instance de DataCurve qui contient la liste des temps de l’intervalle d’étude et la

liste des DataY (les données de chaque colonne, leur unité et leur nom) des colonnes

sélectionnées. Ces valeurs sont extraites des fichiers CSV parcourus avec le parseur.

(25)

23

2. Ajout de nouvelles fonctionnalités au tableau de sélection Une fois la structure du tableau de sélection mise en place nous avons discuté des modifications et améliorations à lui apporter. Une première réflexion nous a conduits à la conclusion que laisser potentiellement la possibilité à l’utilisateur de choisir les bornes de l’intervalle temporel d’observation n’était pas pertinent, du fait que JFreeChart autorise le zoom sur les graphiques. Par conséquent nous avons fixé l’intervalle d’étude au temps total de simulation.

J’ai ensuite enrichi les possibilités offertes par le tableau en lui ajoutant des boutons

« Supprimer » et « Modifier » dont l’action s’effectue uniquement lorsqu’une ligne du tableau est sélectionnée. Le premier bouton, comme son nom l’indique, supprime cette ligne (ainsi que le ParamUser et le DataCurve correspondants). Le second la rend éditable et permet ainsi à l’utilisateur de :

cocher/décocher des cases de la ligne,

ajouter des colonnes via les listes latérales.

J’ai également introduit un bouton « Dessiner ». Inactif tant que la vue n’est pas implémentée, il aura pour fonction de construire les graphiques lorsque cela sera le cas. Il est muni d’un compteur informant l’utilisateur quant au nombre de graphiques qui seront créés.

Afin de me faciliter la tâche avec la gestion des boutons j’ai mis en place un mécanisme de désactivation automatique. J’ai ainsi configuré les boutons de manière à ce qu’ils se grisent dès que leur action est considérée comme non souhaitable. Par exemple le clic sur le bouton « Modifier » désactive aussitôt les boutons « Supprimer » et « Dessiner » dont la fonction rentrerait en conflit avec l’action en cours.

Il est important de noter que le clic sur le bouton « Modifier » bloque aussitôt l’édition de la dernière ligne du tableau. Ainsi il n’y a à tout moment d’une modification qu’une seule ligne éditable sur laquelle s’appliquent tous les changements désirés. Afin que cette ligne soit aisément repérable j’ai choisi de lui appliquer une police rouge (cf. figure suivante). Pour que les modifications soient prises en compte, l’utilisateur doit cliquer sur le bouton « Valider ».

Les ParamUser et DataCurve correspondant à l’ancienne ligne sont alors supprimés puis

recréés avec les nouvelles valeurs.

(26)

24 Figure 10 : les boutons actifs et non actifs lorsqu'une ligne est en cours de modification (les couleurs des

colonnes seront expliquées au chapitre suivant)

Avec la modification de lignes est apparue une complication dans mon implémentation. En effet, j’avais fait en sorte qu’une modification de ligne engendrant une ligne « vide » (i.e. dont tous les booléens sont à « faux ») ne crée pas les ParamUser/DataCurve correspondants. Or j’avais établi la liaison ligne tableau/ParamUser/DataCurve sur le principe : la ligne numéro X du tableau renvoie au ParamUser de position X dans la liste des ParamUser et au DataCurve de position X dans la liste des DataCurve. Avec l’apparition des lignes vides cette correspondance ne pouvait plus être assurée et devait être revue. Après en avoir discuté avec Sylvain nous avons convenu de mettre en place un système de liaison par « clés » : chaque triplet (ligne de tableau, ParamUser, DataCurve) s’est vu attribuer un entier unique s’incrémentant à chaque création de ligne. Ce mécanisme a totalement sécurisé l’association entre les trois objets précédents. En le mettant en place nous savions que les évolutions futures du programme seraient facilitées puisque nous pouvions désormais nous affranchir de toute considération de positionnement dans les listes de ParamUser et de DataCurve.

3. Améliorations apportées aux listes latérales

Comme nous l’avons vu précédemment, le fichier nom_polluant.csv contient à la fois des données de concentrations et de masses (cf. tableau I). Pour faciliter mon travail et améliorer la cohérence des données, il a été décidé de modifier l’écriture des fichiers CSV dans Adis-TS pour que le fichier nom_polluant.csv ne contienne que des données de concentrations et le fichier nom_polluant_masse.csv uniquement des données de masses. Il y a ainsi une complète équivalence liste latérale

fichier CSV et chaque liste est alors dédiée soit aux concentrations, soit au masses.

Concernant les boutons affectés aux listes, j’ai supprimé la liste déroulante permettant de trier

la liste pour rendre ce tri obligatoire. En effet la lecture des CSV est réalisée avec peu

(27)

25

d’informations préalables quant à leur structure : on ne connaît pas le nombre de colonnes - qui peuvent être très nombreuses- ni le nom des points particuliers par exemple. Un tri systématique aurait pour avantage d’organiser ces informations et ainsi aiderait l’utilisateur à s’y retrouver. Jean-Baptiste m’ayant fait comprendre que les colonnes qui intéressaient généralement le plus ces utilisateurs étaient celles des points particuliers, j’ai perfectionné le tri grâce à une expression régulière pour obtenir :

en tête de liste les points particuliers triés alphabétiquement,

puis les biefs également triés alphabétiquement.

J’ai ainsi remplacé la liste déroulante par un bouton « Tout » ayant pour fonction d’ajouter automatiquement toutes les colonnes au tableau. Plusieurs tests successifs m’ont néanmoins fait réaliser que les deux boutons « Ok/Tout » avaient tendance à être moins pratiques à utiliser que prévu. J’ai donc décidé d’implémenter un système de glisser-déposer depuis les listes vers le tableau. Une fois mis en place ce « drag-and-drop », fonctionnant aussi bien en mono qu’en multi-sélection, s’est révélé nettement plus agréable à utiliser que les boutons.

La dernière amélioration notable au sujet des listes latérales est l’introduction de la couleur.

Pour que l’utilisateur puisse d’un coup d’œil identifier quelles colonnes de son tableau sont des concentrations et lesquelles sont des masses, j’ai coloré chaque liste d’une couleur différente : orange et violet. Toute colonne ajoutée dans le tableau voit ses cellules prendre la couleur de la liste correspondante, ce qui améliore la lecture du tableau (cf. figure suivante).

Figure 11 : listes latérales colorées et leur correspondance dans le tableau

(28)

26

B. Affichage des graphiques de courbes 1. JFreeChart

La seconde partie de la Vue consiste en la construction des graphiques spécifiés par l’utilisateur dans le tableau de sélection. Comme je l’ai indiqué précédemment, il avait été décidé avant mon arrivée de déléguer cette tâche à la bibliothèque de représentations graphiques JFreeChart

7

. Cette interface de programmation (API) est open source mais sa documentation en pdf, qui avoisine les 900 pages, est payante. Sylvain la possédait déjà imprimée, ce qui m’a bien servi.

Afin de comprendre le fonctionnement de la bibliothèque pour pouvoir l’utiliser au mieux, j’ai pris le temps de parcourir attentivement la documentation avant toutes choses. J’ai ainsi constaté que JFreeChart possède ses propres objets de stockage de données, appelés de manière générique « datasets » dans le guide du développeur. Selon les informations que j’avais lues, les données relatives à un graphique JFreeChart étaient contenues dans un dataset. Après une première réflexion il m’a donc semblé que le triplet (ligne tableau, ParamUser, DataCurve), qui relie les objets afférents à un même graphique, pouvait être étendu en quadruplet (ligne tableau, ParamUser, DataCurve, dataset). Par conséquent la liaison par clés mise en place pour le triplet devait être prolongée au quadruplet (cf. figure suivante).

Figure 12 : schéma de propagation de la clé le long du quadruplet

Le ParamUser et le DataCurve étant des objets que j’avais créés de toute pièce, il n’avait pas été compliqué de leur rajouter une clé en attribut lorsque cela s’était avéré nécessaire. Le dataset, au contraire, est un objet propre à JFreeChart et, même s’il n’aurait a priori pas été compliqué de créer un nouvel objet ayant pour attribut un dataset et une clé, j’ai préféré opter pour une autre technique : l’utilisation d’une HashMap. Les raisons de ce choix ont été :

l’économie d’une nouvelle classe,

la découverte d’un nouvel objet Java, dont l’implémentation semblait aisée.

7 Voir bibliographie

Ligne tableau ParamUser DataCurve Dataset

clé clé clé

(29)

27

La HashMap, qui fonctionne sur le principe du stockage de couples (clé, valeur) est une collection d’objets repérés par leur clé. J’avais ainsi prévu de créer pour mon application un nouvel objet

DatasetsMapBuilder (cf . figure suivante) qui aurait eu pour rôle principal

d’héberger la HashMap reliant les datasets à leur clé.

Figure 13 : extrait du diagramme UML décrivant le nouvel objet DatasetsMapBuilder

J’ai cependant modifié mes plans après une relecture approfondie de la documentation, lors de laquelle je me suis rendu compte que la construction d’un graphique à deux axes d’ordonnées (axe des concentrations à gauche et axe des masses à droite par exemple) ne pouvait pas être réalisé avec un seul dataset comme je l’avais d’abord pensé. Ce type de graphique un peu spécial nécessitait en effet un dataset par axe, ce qui rendait caduque la HashMap basée sur des couples (clés, dataset). Je suis alors passé par la création d’un nouvel objet DatasetCurves possédant :

un attribut

datasetConcentrationsCurves correspondant au dataset des courbes de

concentrations si le graphique en est pourvu,

un attribut datasetMassesCurves correspondant au dataset des courbes de masses si

le graphique en est pourvu.

C’est alors cet objet

DatasetCurves que j’ai placé dans la

HashMap, couplé avec la clé (cf.

figure suivante).

Figure 14: extrait du diagramme UML illustrant l’ajout de l’objet DatasetCurves

(30)

28

Afin de pouvoir créer ce nouvel objet j’ai été dans l’obligation de modifier les attributs de mon DataCurve. En effet, il s’est avéré nécessaire que je puisse distinguer facilement les DataY concernant des concentrations de ceux de masses. J’ai donc transformé mon attribut dataYList en deux attributs (cf. figure suivante) :

concentrationsList : liste des DataY relatives à des courbes de concentrations,

massesList : liste des DataY relatives à des courbes de masses.

Figure 15 : extrait du diagramme UML illustrant la modification de la classe DataCurve

2. La mosaïque de graphiques

Concernant l’affichage des graphiques, les discussions avec mes tuteurs nous avaient amenés à envisager l’utilisation d’une mosaïque de graphiques : en fonction du nombre de graphiques à représenter la fenêtre est divisée en un certain nombre de cases de même taille, chaque case contenant un graphique. En cliquant sur une case le graphique correspondant s’ouvre dans sa propre fenêtre.

J’ai donc implémenté cette mosaïque en m’efforçant de la rendre la plus agréable possible.

J’ai tout d’abord créé une classe héritant de

JFrame, que j’ai appelée ChartsFrame. Je l’ai

munie du gestionnaire de placement tout indiqué pour ce que je voulais faire à savoir le

GridLayout, qui crée automatiquement une grille possédant le nombre de lignes et de

colonnes fournies en arguments (cf. figure suivante).

(31)

29 Figure 16 : GridLayout composé de 7 lignes et 3 colonnes

J’ai ainsi effectué plusieurs tests pour trouver comment déterminer ces deux arguments à partir du nombre de graphiques, pour que le résultat soit le plus harmonieux possible. J’en suis arrivé à la méthode de division décrite par le tableau suivant.

Tableau VI : division de la fenêtre en fonction du nombre de graphiques

Nombre de graphiques Nombre de lignes Nombre de colonnes

1 à 3 autant que de graphiques 1

4 2 2

5 à 6 3 2

7 à 9 3 3

10 à 12 4 3

13 à 16 4 4

>16 5 autant que nécessaire

A noter que dans certains cas les dernières cases de la grille peuvent de pas contenir de

graphique (par exemple avec 13 graphiques la dernière ligne contient un graphique et 3 cases

vides), ce qui n’est pas gênant visuellement. J’ai également postulé que les utilisateurs

n’essaieraient que rarement d’afficher plus de 16 graphiques à la fois. Dans cette situation j’ai

choisi de limiter le nombre de lignes à 5 et de faire augmenter le nombre de colonnes en

conséquence. J’ai pris cette décision en me basant sur une série de tests et sur le fait que les

écrans d’aujourd’hui sont plus larges que hauts, et de plus en plus souvent dédoublés sur les

(32)

30

postes de travail scientifiques. Je pouvais donc privilégier l’extension en largeur de la mosaïque plutôt qu’en hauteur (cf. figure suivante).

Figure 17 : mosaïque à 4 et 25 graphiques

(33)

31

En lisant la documentation de JFreeChart je me suis aperçu que plusieurs paramètres d’affichages gérés nativement par l’API étaient intéressants à activer - ce que j’ai fait - pour ces graphiques de courbes :

zoom avant/arrière via un rectangle de sélection,

zoom avant/arrière via la molette de la souris,

affichage d’un « crosshair » lors d’un simple clic sur une courbe (cf. figure suivante),

panning (déplacement de souris en maintenant CTRL) : translation du graphique.

J’ai également fait en sorte que dans le cas d’un graphique à deux axes d’ordonnées les courbes relatives à l’axe de droite s’affichent en pointillé. A noter que la bibliothèque fait apparaître nativement un menu contextuel lors d’un clic droit sur un graphique. Ce menu permet de paramétrer plusieurs options d’affichage (couleurs, allure des axes par exemple) et propose l’impression directe et l’export en image au format PNG. De plus, la documentation m’a appris qu’en ajoutant un simple toolkit

8

à JFreeChart, cette dernière pouvait gérer l’export des graphiques en format vectoriel SVG. Ces deux formats d’enregistrement, et tout particulièrement le SVG qui a pour avantage de conserver une qualité d’image constante quel que soit le niveau de zoom, intéressaient particulièrement mes tuteurs. En effet les graphiques obtenus devaient à terme pouvoir être utilisés dans des publications scientifiques, et l’existence de ces deux types d’export gérés quasiment nativement était une très bonne nouvelle !

Figure 18 : activation du crosshair et du menu associé au clic droit

8 Bibliothèque logicielle dédiée à la conception d’interfaces graphiques

(34)

32

J’ai mentionné précédemment le fait qu’un clic sur un graphique ouvre ce dernier dans une fenêtre dédiée facilitant sa lecture. Ma première implémentation utilisait un simple clic pour réaliser cette action. Je me suis cependant rendu compte que cela rentrait en conflit avec l’affichage du crosshair, qui apparaît également avec un clic unique. Pour obtenir la fenêtre individuelle il fallait alors effectuer deux clics de suite, le premier générant automatiquement un crosshair non désiré. J’ai éliminé ce désagrément en déployant la fenêtre individuelle du graphique via un double-clic sur ce dernier.

En mettant en œuvre cette fonctionnalité, bien pratique lorsque la mosaïque est constituée de petites cases peu lisibles, je me suis rendu compte qu’elle contribuait également à multiplier le nombre de fenêtre ouvertes en même temps ce qui pouvait devenir inconfortable au bout d’un moment. J’ai donc implémenté dans ma ChartsFrame deux boutons de fermeture :

un premier bouton pour fermer uniquement les fenêtres dédiées aux graphiques individuels,

un second bouton fermant toutes les fenêtres de graphiques.

Figure 19 : mosaïque avec ses deux types de boutons de fermeture en arrière-plan et fenêtre individuelle au premier plan

(35)

33

IV. Ajout des diagrammes en bâtons et préparation au bêta-test A. Réutilisation/modification des structures existantes

1. Le Modèle

Une fois satisfait de la gestion des courbes j’ai concentré mes efforts sur l’implémentation du deuxième type de représentations graphiques que nous avions évoqué avec mes tuteurs, à savoir les diagrammes en bâtons. Nous avions convenu que pour ces derniers seules les données de masses seraient utiles. L’objectif était de parvenir à représenter les valeurs des masses dans plusieurs biefs (il n’y a pas de points particuliers dans le CSV de masses) à plusieurs temps. En groupant les séries de bâtons par biefs, il serait ainsi aisé de voir, pour chaque bief, l’évolution de la masse en fonction des temps choisis. Pour une meilleure compréhension, la figure suivante montre ce que nous voulions obtenir.

Figure 20 : illustration du type de diagrammes en bâtons désirés

Pour construire ce nouveau type de graphiques il fallait se repencher sur la structure du code,

ce que nous avons fait avec Sylvain. Notre objectif était de réutiliser au mieux les classes

existantes, en les modifiant si besoin, afin d’obtenir une implémentation la plus générique

possible grâce notamment au mécanisme d’héritage proposé par le langage Java. Cette

généricité nous permettrait d’intégrer ultérieurement de nouveaux types de représentations

graphiques avec un minimum de modifications du code.

(36)

34

Nous avons tout d’abord constaté que, pour construire un diagramme en bâtons, l’utilisateur doit sélectionner, comme pour les courbes, une liste de temps et une liste de biefs. Autrement dit, l’objet ParamUser peut, sans modification aucune, être réutilisé pour ces nouveaux diagrammes puisque les attributs sont les mêmes. En poussant plus loin notre réflexion nous nous sommes rendu compte que le DataCurve pouvait lui aussi resservir, moyennant la modification de l’attribut columnTitle de String en List<String>. Nous avons également poussé notre réflexion plus loin en nous interrogeant à propos d’une future mise en place de diagrammes circulaires (familièrement appelés « camemberts ») et nous en sommes arrivés à la conclusion que les modifications précédentes permettraient aussi de les intégrer aisément.

La généricité du code que nous voulions assurer semblait donc fonctionner avec cette adaptation, que j’ai par conséquent implémentée.

Cependant, pour refléter le fait que lesdits objets n’étaient plus seulement dédiés aux courbes mais prenaient une dimension plus générique, j’ai effectué les changements d’appellation illustrés par le tableau suivant.

Tableau VII : correspondance des anciennes et nouvelles appellations de l'UML

Ancien nom Nouveau nom

DataY ValuesSerie

listY valuesList

columnTitle serieTitlesList

columnUnit serieUnit

DataCurve DataPlot

concentrationsList seriesConcentrationsList

massesList seriesMassesList

listX timeList

2. La Vue

Jusqu’à présent j’avais utilisé une classe MyTableModel héritant d’AbstractTableModel pour

gérer les données du tableau de sélection des courbes. Avec l’arrivée des diagrammes en

bâtons nous avons constaté que les TableModel relatifs aux deux types de tableau allaient

avoir beaucoup d’attributs et de méthodes en commun. C’était donc l’occasion idéale de

factoriser le code en instaurant une classe abstraite

MyAbstractTableModel héritant

d’AbstractTableModel et regroupant tout ce qui était commun entre les deux tableaux. De

(37)

35

cette classe dérivent les deux classes concrètes

MyTableModelCurves et MyTableModelBars

(cf. figure suivante). Ainsi l’affichage des tableaux, réalisé par la classe MyTableFrame faisant appel aux méthodes de la classe abstraite, s’en trouve simplifié.

Figure 21 : extrait du diagramme UML illustrant l'introduction de la classe MyAbstractTableModel

La première grosse modification induite par ces diagrammes a été de déterminer comment

afficher le nouveau tableau de sélection dédié. Après en avoir discuté avec mes deux tuteurs

nous avons convenu que le plus simple - à implémenter et à l’utilisation - serait de mettre en

place une gestion par onglets de ces tableaux. Pour l’instant les seuls graphiques sur lesquels

j’avais travaillé étaient les courbes et les diagrammes en bâtons mais d’autres arriveraient par

la suite et des onglets permettraient d’afficher facilement plusieurs tableaux dans un même

espace. J’ai donc inséré chaque tableau de sélection muni de ses éléments latéraux (listes)

dans un nouvel objet Java

JTabbedPane, dédié à l’affichage par onglets. Chaque type de

graphique possédant désormais son onglet, j’ai ensuite pu aisément travailler sur les nouvelles

structures à créer pour les diagrammes en bâtons.

(38)

36

Comme je l’ai indiqué dans le chapitre précédent nous avions établi que seules les données de masse seraient intéressantes à représenter avec ce nouveau type de diagrammes. Nous pouvions donc conserver la liste latérale des masses pour le tableau de sélection. De même, la classe ChartsFrame que j’avais codée pour l’affichage de la mosaïque de courbes était également totalement réutilisable. Je l’avais en effet implémentée de la façon la plus générique envisageable, en faisant le moins possible référence à des objets spécifiques aux graphiques de courbes. C’était donc avec très peu de changements que cette classe pouvait être adaptée à la représentation des diagrammes en bâtons. Précisons cependant que chaque instance de ChartsFrame affichait une mosaïque composée uniquement des mêmes types de graphiques. A ce stade de l’implémentation, il n’était pas possible d’obtenir des courbes et des diagrammes en bâtons au sein de la même fenêtre. En revanche la mise en place des onglets permettait de faire cohabiter en même temps deux instances de ChartsFrame, donnant ainsi la possibilité à l’utilisateur de comparer leur contenu.

B. Ajout de nouvelles structures 1. Le sélecteur de temps

La liste des concentrations pouvait être mise de côté pour les diagrammes en bâtons mais elle devait être remplacée par un nouvel élément permettant à l’utilisateur de choisir un certain nombre de temps de la simulation. En effet pour les courbes nous n’avions pas à nous poser la question puisque le parti avait été pris de les tracer sur la totalité de la durée de l’étude. Pour ce nouveau type de représentation en revanche, seuls quelques moments particuliers sélectionnés par l’utilisateur devaient être pris en compte.

Un problème s’est donc posé à nous : comment rendre cette sélection la plus agréable et simple possible pour l’utilisateur ? Nous avions envisagé principalement deux possibilités :

mettre en place une liste déroulante contenant l’ensemble des temps de la simulation.

Cette solution, très simple à implémenter, possédait néanmoins le gros inconvénient d’être très peu pratique. En effet les simulations pouvaient parfaitement être réalisées sur plusieurs années avec un pas de temps horaire ou journalier, ce qui aurait généré une liste déroulante colossale impossible à parcourir facilement ;

instaurer un simple champ de texte (JTextField) dans lequel l’utilisateur aurait

simplement rentré le temps désiré. Le programme aurait ensuite retenu le temps le plus

(39)

37

proche disponible dans le CSV. La difficulté résidait dans le fait que les temps du CSV étaient exprimés en jours décimaux, unité qu’il paraissait fort peu pratique de faire adopter à un utilisateur.

C’est finalement un mécanisme dérivé la seconde solution que j’ai mis en place. En effectuant des recherches sur Internet j’ai découvert l’existence du composant Java

JSpinner (cf. figure

suivante). Ce dernier consiste en un champ de texte permettant de sélectionner un élément dans une liste ordonnée. Il est muni de deux petites flèches destinées à naviguer dans les éléments de cette liste.

Figure 22 : exemple de JSpinner

J’ai ainsi eu l’idée de créer un sélecteur de temps s’adaptant à la durée de l’étude. Son fonctionnement est le suivant :

1) Partant de la durée totale de la simulation exprimée en jours décimaux, il la convertit - via la réutilisation/modification d’une classe Temps déjà implémentée par Sylvain - en un nombre d’années, semaines, jours, heures, minutes et secondes ;

2) Parmi les six champs précédents il repère les X premiers champs à partir du premier champ non nul et affiche les JSpinner correspondants ;

3) Dans les champs de texte de ces derniers l’utilisateur spécifie les valeurs entières qu’il désire (avec le clavier ou en utilisant les boutons fléchés). J’ai paramétré les champs des secondes et des minutes pour qu’ils acceptent les entiers de 0 à 59, celui des heures va de 0 à 23, celui des jours de 0 à 6 et celui des semaines de 0 à 51 ;

4) Une fois ceci fait l’utilisateur valide son choix et la durée exprimée par l’ensemble de ces champs est convertie en jours décimaux. Le sélecteur recherche alors dans le fichier CSV le temps le plus proche. Si la valeur rentrée est exactement entre deux temps du CSV c’est le temps le plus élevé qui est conservé ;

5) Cette valeur qu’il a obtenue est un double, il utilise alors la classe Temps pour la convertir et afficher dans le tableau X+1 champs successifs sous la forme

« a:sem:j:h:m:sec » (j’expliquerai ci-après ce choix de X+1).

Références

Documents relatifs

[r]

On cherche 0 sur la 1 re ligne du tableau et on lit son image sur la 2 de ligne.. Donne un encadrement de l’antécédent

On cherche 0 sur la 1 re ligne du tableau et on lit son image sur la 2 de ligne.. Donne un encadrement de l’antécédent

On cherche 0 sur la 1 re ligne du tableau et on lit son image sur la 2 de ligne.. Donne un encadrement de l’antécédent

[r]

[r]

[r]

Au pas numéro trois les résultats ne sont plus comparables puisque les deux premières variables choisies ne sont pas les mêmes dans chaque algorithme. TABLEAU