TangenteX.com

Le problème

Restituer graphiquement des résultats

Les utilisateurs de Python, MatLab, SciLab ou Maple peuvent aisément restituer leurs résulats sous forme graphique, ces langages possèdent des librairies graphiques natives. Cette page ne s'adresse pas à eux.

Les lecteurs de TangenteX qui programment en C ou en FORTRAN, et plus généralement dans un langage qui ne possède pas de librairie graphique native se posent souvent cette question : comment restituer graphiquement les résultats sous forme de courbes 1D ou 2D, ou de diagrammes ?

Dans plusieurs pages de TangenteX, celles qui présentent des programmes en C et en FORTRAN, j'ai utilisé plusieurs techniques sans trop m'appesantir sur le sujet. Pour répondre aux questions qui me sont régulièrement posées à ce propos, je vais revenir dans cette page sur les différentes solutions : utiliser gnuplot, écrire un script Python spécifique, solutions les plus simples, ou bien mettre en oeuvre une librairie graphique externe.

Le programme exemple

Pour illustrer le besoin, je vais utiliser un programme C nommé TestGraphique.c, qui simule le comportement du pendule simple non linéaire en utilisant la méthode d'intégration de l'équation différentielle RK4. Vous pouvez le télécharger dans la bibliothèque de codes de TangenteX.

A chaque pas de calcul, l'équation est intégrée et les valeurs du pas de temps, de l'angle et de la vitesse angulaire courants sont stockés dans un fichier de données nommé Pendule.dat, qui sera créé sur le répertoire de travail du programme TestGraphique.exe. Voici le code du programme :

int main(int argc, char *argv[])
{
  double theta,thetapoint;
  double Yin[N],Yout[N];

  // définition du domaine temporel
  double t;
  double t0 = 0.0;
  double tmax = 10.0;
  double dt = 0.01
  // conditions initiales
  double theta0 = PI/6.0;
  double thetapoint0 = 0.0;
  // variables du fichier de sauvegarde des données, construit dans le répertoire de travail du programme
  FILE *fp;
  char NomFile[] = "Pendule.dat";

  // ouverture du fichier
  if ((fp = fopen(NomFile,"w+")) == NULL)
     {
     printf("Erreur ouverture fichier: %s\n", strerror(errno));
     exit(1);
     }
  // boucle de calcul
  t = t0;
  theta = theta0;
  thetapoint = thetapoint0;
  while (t < tmax)
     {
        Yin[0] = theta;
        Yin[1] = thetapoint;
        RK4(Yin, Yout, dt);
        theta = Yout[0];
        thetapoint = Yout[1];
        t += dt;
        fprintf(fp,"%.5e %.5e %.5e\n", t, theta, thetapoint);
     };
  fclose(fp);

  printf("Fin du programme \n");
  return 0;
}

A noter que j'ai utilisé ici un espace comme séparateur entre les données. C'est un choix, mais peut-être pas le plus pertinent. Il vaut mieux choisir un format standard comme le format csv (Comma-Separated Values), en utilisant une virgule comme séparateur entre les données. Une petite remarque : le format csv implique que le séparateur de champs soit toujours une virgule. Pour ma défense, les programmeurs C et FORTRAN sont plus anciens que le format csv et eux utilisaient (utilisent..) l'espace comme séparateur. Vous comprendrez vite pourquoi lorsque vous serez confrontés aux différentes écritures des nombres décimaux (point ou virgule comme séparateur décimal ?)

L'objectif

Mon objectif est de vous donner les moyens de tracer des courbes simples 1D à l'aide de différents outils facilement accessibles. Plus précisément, il s'agit de définir un environnement graphique, de tracer des axes avec des labels puis de tracer une courbe d'une couleur donnée. Les points (x,y) pour tracer cette courbe seront lus dans le fichier de données constitué lors de l'exécution du programme exemple.

L'usage des outils proposés, que ce soit gnuplot, Python/matplotlib ou une librairie graphique, nécessite une appropriation plus ou moins approfondie selon votre usage. Je fournirai ici les commandes essentielles. Pour plonger dans les outils, vous trouverez sur le net des tutoriels de tous les niveaux. Dans la bibliothèque de codes de TangenteX, vous trouverez aussi de nombreux exemples de mise en oeuvre.

Utiliser gnuplot

Présentation générale

Gnuplot est un programme open source, gratuit et d'usage très répandu dans les universités et les laboratoires du monde entier. Il fonctionne sur les OS Windows, Mac OSX et Linux. Pour ma part, je l'utilise sur Mac et Windows 10, dans sa version 5.2 patchlevel 5 (en mai 2020). Vours pouvez le télécharger et l'installer très facilement sur votre machine.

C'est un langage de commandes, qui supporte l'introduction des commandes depuis le prompt du programme mais aussi qui peut exécuter des fichiers de commandes.

Pour utiliser gnuplot, il vous suffit de lancer le programme. Il vous affichera un prompt qui est 'gnuplot>' par défaut, comme au bon vieux temps des OS en mode commande. A partir de ce prompt, vous pourrez utiliser toutes les commandes que nous allons voir ci-dessus. Si vous êtes curieux, vous pouvez aussi taper 'help', sans les quotes bien sur, et vous aurez accés à la documentation complète du produit.

Deux commandes qui peuvent vous être utiles, sans être des commandes graphiques :

  • pwd : gnuplot affiche le répertoire de travail courant.
  • cd : vous permet de changer de répertoire de travail en tapant : cd 'chemin de votre répertoire'. Attention : n'utilisez que les simples quotes, les doubles quotes " peuvent provoquer des choses bizarres sous Windows.

Enfin, pour quitter gnuplot, il suffit de taper la commande 'quit'.

Tracer la trajectoire du pendule

Je vais donc exploiter le fichier Pendule.dat pour tracer la trajectoire du pendule simple calculée par la méthode RK4. Les données à tracer sont dans les deux premiers champs de chaque enregistrement du fichier : le premier champ contient le pas temporel et le deuxième champ l'angle correspondant. Voici les commandes (en gras) que je vais utiliser :

je trace la grille sur la figure : gnuplot> set grid
je définis le titre de la figure : gnuplot> set title "Trajectoire du pendule"
je définis les labels pour les deux axes :
gnuplot> set xlabel "Temps"
gnuplot> set ylabel "Angle"
je définis les limites min et max pour les deux axes :
gnuplot> set xrange[0:10]
gnuplot> set yrange[-1.0:1.0]
et enfin je trace la courbe : gnuplot> plot 'Pendule.dat' using 1:2 with line linetype rgb "blue" 

Cette dernière commande est un peu plus compliquée : j'indique d'abord le nom du fichier de données et éventuellement son chemin d'accès. Puis j'indique que je vais utiliser les deux premières colonnes du fichier, ici le temps et l'angle. Enfin, j'indique que je veux relier les points par une ligne de couleur bleue.

Voici la courbe obtenue :

Courbe Gnuplot 1

Il existe des commandes pour modifier la taille et la nature des polices de caractères du titre et des labels des axes, pour changer le pas de la grille, la couleur et la forme de la courbe, pour incruster une légende et bien d'autres choses. Vous trouverez toutes ces commandes dans le 'help' de Gnuplot.

Si cela vous ennuie de retaper ces lignes de commandes à chaque fois que vous voulez tracer cette courbe, vous pouvez les stocker dans un fichier texte (format ASCII) avec une extension '.gnuplot' et depuis le prompt gnuplot vous l'exécuterez par la commandet load "Pendule.gnuplot", si vous avez nommé votre fichier Pendule.gnuplot bien sur.

Tracer du portrait de phase

En utilisant les mêmes commandes ou presque, je trace le portait de phase du pendule simple obtenu par la méthode RK4 :
set grid
set title "Portrait de phase"
set xlabel "Angle"
set ylabel "Vitesse angulaire"
set xrange [-1.0:1.0]
set yrange [-1.0:1.0]
plot "Pendule.dat" using 2:3 with lines linetype rgb "red"

Remarquez qu'ici, je demande à gnuplot d'utiliser les colonnes 2 et 3 du fichier de données, qui contiennent les valeurs d'angle et de vitesse angulaire nécessaires au tracé du portait de phase. La courbe obtenue :

Courbe Gnuplot 1

Autres fonctions intéressantes de gnuplot

Gnuplot offre beaucoup de possibilités dont vous trouverez l'exposé dans la documentation en ligne du produit et dans les différents tutoriels que l'on trouve sur le net. En voici quelques unes qui pourraient vous intéresser :

  • tracer la courbe représentative d'une fonction, car gnuplot embarque la plupart des fonctions classiques et quelques une qui le sont moins : fonctions beta et gamma, fonctions d'erreur, fonctions de Bessel. Gnuplot gère un jeu de variables (x et t) et de constantes prédéfinies, ce qui fait que vous pouvez sans autre forme de procès tracer un sinus cardinal ou une gaussienne. Utile pour se faire une idée rapide de la forme d'une fonction.
  • tracer des surfaces z = f(x,y) avec toutes les options que l'on trouve dans les grandes librairies graphiques.
  • construire des histogrammes et des diagrammes statistiques avec boites d'erreurs et autres fioritures.
  • créer des animations en 2D et 3D.

Bref, un logiciel à creuser !

Créer un script Python

La méthode

Python est un langage généraliste, interprété, pour lequel on trouve des environnements de développement gratuits, IDLE ou Anaconda par exemple. Si vous êtes familiers de TangenteX, je ne vous le présente pas : je l'emploie dans presque toutes les pages. Sinon, je vous renvoie à sa présentation sur cette page.

Python possède en standard une librairie graphique très complète, matplotib. Sa mise en oeuvre est aisée, particulièrement s'agissant de nos besoins relativement simples. Aussi, il n'est pas incongru d'écrire un script pour tracer des courbes à partir de résultats obtenus avec un programme C/C++ ou FORTRAN.

Voici un exemple de script, TraceCourbe.py, qui trace la trajectoire et le portrait de phase de notre pendule simple, comme le fait gnuplot. Après avoir ouvert et lu les fichier de données et stocké les données dans trois vecteurs temps, angle et vitesse angulaire, le reste du code met en oeuvre la librairie graphique matplotlib. On reconnait les mêmes fonctions que celles utilisées dans le script de gnuplot, avec des noms similaires.

from scipy import loadtxt
from matplotlib.pylab import figure, grid, title,xlabel,ylabel,plot, xlim,ylim

# récupération des données dans le fichier Spectre.dat
nomfile = 'Pendule.dat'
temps, theta, thetaprime = loadtxt(nomfile,dtype = 'f8,f8,f8', unpack = True)

# tracé de la trajectoire
fig1 = figure(figsize=(10,8))
grid(True)
title('Trajectoire du pendule')
xlabel('Temps')
ylabel('Angle')
xlim(0.0,10.0)
ylim(-1.0,1.0)
plot(temps, theta,'b')

#tracé du portait de phase
fig2 = figure(figsize=(10,8))
grid(True)
title('Portrait de phase')
xlabel('Angle')
ylabel('Vitesse angulaire')
xlim(-1.0,1.0)
ylim(-1.0,1.0)
plot(theta, thetaprime,'r')

La création et la mise en oeuvre d'un script Python est presque aussi facile qu'avec gnuplot, si l'on possède un environnement de développement Python et que l'on soit familiarisé avec le langage. Notons qu'il est possible d'appeler un script Python depuis un programme, le langage possédant une API utilisable en C et en FORTRAN. J'ai testé cette possibilité en C avec Python 2.7, mais pas encore en 3.5.

Les résultats

Les courbes obtenues avec le script Python sont heureusement identiques à celle obtenue avec gnuplot :

Trajectoire Python
Portrait de phase Python

Utiliser une librairie graphique

Il existe plusieurs librairies graphiques qui sont utilisables en C et en FORTRAN, la plus connue et la plus universelle étant sans doute Open GL. Cette librairie fonctionne sur beaucoup d'OS dont Windows 10, Mac OSX et Linux. Sa mise en oeuvre est relativement lourde, sans parler de son installation sur votre machine.

Il existe des librairies plus spécialisées en physique, qui ont été produites par des laboratoires de physique. La plus connue est sans doute ROOT du CERN de Genève, librairie généraliste de calcul et de traitement de données, qui contient une partie graphique très intéressante. Mais pour elle aussi, la mise en oeuvre n'est pas très simple.

Le Max Planck Institute pour le système solaire, et plus spécifiquement Helmut Michels, diffuse depuis de longues années une librairie graphique simple et assez complète, utilisable sur nos environnements de développement, la librairie dislin.

L'installation de la librairie dislin commence par le choix du package à télécharger sur le site du Max Planck. Il dépend de l'environnement de compilation gcc ou gfortran que vous utilisez : Cygwin, MinGW ou bien VC pour les utilisateurs de Visual Studio. L'installation est facile. Le plus pénible est de configurer votre environnement de développement : Dev-ccp, Codes::block, Eclipse ou que sais-je encore. Pour ma part, je travaille avec Eclipse-CDT et MinGW.

J'ai donc modifié le code de TestGraphique.c pour tracer la trajectoire du pendule avec dislin. Voici ce code, dans lequel j'ai surligné en gras les instructions graphiques :

//============================================================================
// Name        : TestGraphique.c
// Author      : Dominique Lefebvre
// Version     : 1.0
// Copyright   : www.tangentex.com
// Description : Simulation du pendule simple non linéaire
// ============================================================================

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include "dislin.h"

//******************************************************************************
// Définition des constantes et des paramètres
//******************************************************************************
#define N        2          // nombre d'équations dans le système différentiel
#define PI       3.1415927

double omega2 = 1.0;
//******************************************************************************
// définition du système différentiel
//******************************************************************************
void Derivee(double Y[], double dY[])
{
   dY[0] = Y[1];
   dY[1] = -omega2*sin(Y[0]);
   return;
}
//******************************************************************************
// Routine RK4
//******************************************************************************
void RK4(double yin[], double yout[], double h)
{
   int i;
   double dydx[N], dydxt[N], yt[N], k1[N], k2[N], k3[N], k4[N];

   Derivee(yin, dydx);
   for (i = 0; i < N; i++)
    {
      k1[i] = h*dydx[i];
      yt[i] = yin[i] + 0.5*k1[i];
    }
   Derivee(yt, dydxt);
   for (i = 0; i < N; i++)
    {
      k2[i] = h*dydxt[i];
      yt[i] = yin[i] + 0.5*k2[i];
    }
   Derivee(yt, dydxt);
   for (i = 0; i < N; i++)
    {
      k3[i] = h*dydxt[i];
      yt[i] = yin[i] + k3[i];
    }
   Derivee(yt, dydxt);
   for (i = 0; i < N; i++)
    {
      k4[i] = h*dydxt[i];
      yout[i] = yin[i] + k1[i]/6. + k2[i]/3. + k3[i]/3. + k4[i]/6.;
    }
  return;
}
//*****************************************************************************
// Programme principal
//*****************************************************************************
int main(void)
{
  double theta,thetapoint;
  double Yin[N],Yout[N];
  // définition du domaine temporel
  double t;
  double t0 = 0.0;
  double tmax = 10.0;
  double dt = 0.01;
  // conditions initiales
  double theta0 = PI/6.0;
  double thetapoint0 = 0.0;
  FILE *fp;
  char NomFile[] = "Pendule.dat";
  // initialisation de l'affichage graphique (lib dislin)
  metafl("XWIN");
  disini();
  pagera();
  pagfll(255);
  color("black");   // couleur des axes
  hwfont();
  titlin("Trajectoire du pendule simple",1);
  name("Temps","x");
  name("Angle","y");
  graf(t0,tmax,t0,1.0,-1.0,1.0,-1.0,0.2);
  title();
  grid(1,1);
  color("blue");          // couleur de la courbe
  rlstrt(0.0,theta0);     // positionnement aux valeurs initiales

  // ouverture du fichier
  if ((fp = fopen(NomFile,"w+")) == NULL)
     {
     printf("Erreur ouverture fichier: %s\n", strerror(errno));
     exit(1);
     }
  // boucle de calcul
  theta = theta0;
  thetapoint = thetapoint0;
  t = t0;
  while (t < tmax)
     {
        Yin[0] = theta;
        Yin[1] = thetapoint;
        RK4(Yin, Yout, dt);
        theta = Yout[0];
        thetapoint = Yout[1];
        t += dt;
        fprintf(fp,"%.5e %.5e %.5e\n", t, theta, thetapoint);
        rlconn(t,theta);
     };
  fclose(fp);
  rpng("EssaiDislin.png");      // sauvegarde de l'image dans un fichier .png
  disfin();

  printf("Fin du programme \n");
  return 0;
}

La configuration du linker pour indiquer les librairies à utiliser est pénible et dépend de votre environnement. Si vous avez le même que moi (Eclipse-CDT et MinGW), je pourrais vous aider (voir ici), sinon, il faudra chercher sur le net...

Et voici le résultat obtenu :

Trajectoire du pendule - dislin

Je n'ai fait aucun effort d'embellisement de l'image. Comme vous le constatez, la mise en oeuvre de cette librairie dans un programme n'est pas forcément simple. Pas sûr que le jeu en vaille la chandelle par rapport à l'usage d'un script Python ou de gnuplot. C'est une question de choix...


Contenu et design par Dominique Lefebvre - www.tangenteX.com mai 2020  Licence Creative Commons  Contact :