Création de graphes statistiques et géométriques avec PHP et la bibliothèque GD

Andry Aimé

GD est une bibliothèque PHP qui sert à manipuler et créer des flux ou fichiers images. Cet article vous donne une initiation pour créer des graphes statistiques (diagramme des effectifs, histogramme, camembert) et géométriques à partir des différentes formes de base. Commentez

- Titre : Création de graphes statistiques et géométriques avec PHP et la bibliothèque GD

- Auteur : Andry Aimé

- Parution : 29 septembre 2009

- Mise à jour : 30 novembre 2019

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2009 Andry Aimé. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.

Sommaire

- I. Introduction

- II. Les graphes statistiques

- II-A. Création des tables

- II-B. Diagramme des effectifs

- II-B-1. La requête SQL

- II-B-2. Résultat de la requête

- II-B-3. Préparation des données

- II-B-4. Préparation de l'image

- II-B-5. Traçage du diagramme

- II-B-6. Graphe obtenu

- II-C. Histogramme

- II-C-1. La requête SQL

- II-C-2. Résultat de la requête

- II-C-3. Préparation des données

- II-C-4. Préparation de l'image

- II-C-5. Traçage du diagramme

- II-C-6. Graphe obtenu

- II-D. Camembert ou diagramme circulaire

- II-D-1. La requête SQL

- II-D-2. Résultat de la requête

- II-D-3. Traçage du diagramme

- II-D-4. Graphe obtenu

- III. Les graphes géométriques

- III-A. Courbe d'une fonction

- III-B. Courbe représentant une équation polaire

- III-B-1. Capture d'écran

- IV. Conclusions

- V. Remerciements

- VI. Téléchargement des codes source

I - Introduction

Un beau graphe vaut mieux qu'un long discours. Les graphes sont des moyens moins précis que les tableaux pour la lecture des données, mais plus faciles à lire pour une prise de décision.

II - Les graphes statistiques

Comme on le sait, il y a plusieurs méthodes pour présenter les données statistiques ; par exemple, il y a les tableaux, les polygones, les diagrammes, les disques, les toiles d'araignées, etc. Ces différentes représentations sont en général complémentaires, car chaque méthode a ses avantages et aussi ses inconvénients. Il appartient donc à l'opérateur de choisir ses types de représentation selon les buts et les objectifs qui lui sont fixés. Toutefois, dans certains cas, il peut arriver qu'on rencontre des difficultés dans le choix de l'échelle de représentation.
Tout au long de cette section, nous allons dessiner des graphes pour le suivi des ventes de produits dans un magasin.

II-A - Création des tables

CREATE TABLE type_produit (
id_type INT NOT NULL AUTO_INCREMENT,
libelle_type VARCHAR(45) NOT NULL,
PRIMARY KEY (id_type))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

CREATE TABLE produit (
id_produit INT NOT NULL AUTO_INCREMENT,
id_type INT NOT NULL,
libelle_produit VARCHAR(45) NOT NULL,
PRIMARY KEY (id_produit),
INDEX fk_produit_type_idx (id_type ASC),
CONSTRAINT fk_produit_type
FOREIGN KEY (id_type)
REFERENCES type_produit (id_type))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

CREATE TABLE vente (
id_vente INT NOT NULL AUTO_INCREMENT,
id_produit INT NOT NULL,
quantite INT NOT NULL DEFAULT 0,
dates DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id_vente),
INDEX fk_produit_vente_idx (id_produit ASC),
CONSTRAINT fk_produit_vente
FOREIGN KEY (id_produit)
REFERENCES produit (id_produit)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

II-B - Diagramme des effectifs

Le diagramme des effectifs montre de manière immédiate les fluctuations réelles des données sur une échelle plus vaste. Il permet ainsi une meilleure compréhension plus ou moins immédiate de l'état d'une situation donnée et permet son évaluation.

II-B-1 - La requête SQL

select month(dates) as mois, libelle_produit, sum(quantite) as qtvendu from produit p join vente v using(id_produit)
where year(dates) = 2008 and p.id_produit = 1   GROUP BY mois ORDER BY mois ASC

II-B-2 - Résultat de la requête

II-B-3 - Préparation des données

Comme MySQL ne peut pas retourner le nom des mois en français, nous allons les mettre dans un tableau dont l'indice correspond au numéro du mois retourné par la requête. Nous allons aussi mettre le résultat de la requête dans un tableau pour avoir la quantité minimale et la quantité maximale pour adapter l'échelle du graphe et n'utiliser que les valeurs nécessaires afin de faciliter le traitement des données.

$host="localhost";
$utilisateur="tuto";
$motdepasse="tuto";
$base="tutoriel";
$conexion = new PDO('mysql:host='.$host.';dbname='.$base, $utilisateur, $motdepasse);
$conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sqlQuery = "select month(dates) as mois, libelle_produit, sum(quantite) as qtvendu from produit p join vente v using(id_produit)
where year(dates) = :year and p.id_produit = :idProduit   GROUP BY mois ORDER BY mois ASC";
$sth = $conexion->prepare($sqlQuery, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':year' => 2008, ':idProduit' => 1));

$moisFr=array('Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Decembre');
$resultat=array();
$i=0;
foreach($sth->fetchAll(PDO::FETCH_OBJ) as $row)
{
//Mettre la ligne dans le tableau
$resultat[$row->mois]=$row->qtvendu;
//Prendre la première quantité vendue comme minimum et maximum
if($i==0)
{
$min=$row->qtvendu;
$max=$row->qtvendu;
}
//Tester si la quantité vendue est inférieure au minimum et le prendre s’il l'est
if($row->qtvendu < $min)
{
$min=$row->qtvendu;
}
//Tester si la quantité vendue est inférieure au maximum et le prendre s’il l'est
else
{
if($row->qtvendu > $max)
{
$max=$row->qtvendu;
}
}
$i++;
}

II-B-4 - Préparation de l'image

Nous adaptons maintenant la largeur de l'image et l'échelle par rapport au nombre de mois de vente de l'année et la quantité maximale et celle minimale, tracer les grilles et allouer les couleurs nécessaires dans le graphe.

//Type mime de l'image
header('Content-type: image/png');
//Chemin vers la police à utiliser
$font_file = './arial.ttf';
//Adapter la largeur de l'image avec le nombre de données
$largeur=$i*50+90;
$hauteur=400;
//Hauteur de l'abscisse par rapport au bas de l'image
$absis=80;
//Création de l'image
$courbe=imagecreatetruecolor($largeur, $hauteur);
//Allouer les couleurs à utiliser
$bleu=imagecolorallocate($courbe, 0, 0, 255);
$ligne=imagecolorallocate($courbe, 220, 220, 220);
$fond=imagecolorallocate($courbe, 250, 250, 250);
$noir=imagecolorallocate($courbe, 0, 0, 0);
$rouge=imagecolorallocate($courbe, 255, 0, 0);
//Colorier le fond
imagefilledrectangle($courbe,0 , 0, $largeur, $hauteur, $fond);
//Tracer l'axe des abscisses
imageline($courbe, 50, $hauteur-$absis, $largeur-10,$hauteur-$absis, $noir);
//Tracer l'axe des ordonnées
imageline($courbe, 50,$hauteur-$absis,50,20, $noir);
//Decaler 10px vers le haut le si le minimum est différent de 0
if($min!=0)
{
$absis+=10;
$a=10;
}
//Nombres des grides verticales
$nbOrdonne=10;
//Calcul de l'échelle des abscisses
$echelleX=($largeur-100)/$i;
//Calcul de l'échelle des ordonnées
$echelleY=($hauteur-$absis-20)/$nbOrdonne;
$i=$min;
//Calcul des ordonnées des grides
$py=($max-$min)/$nbOrdonne;
$pasY=$absis;
while($pasY<($hauteur-19))
{
//Affiche la valeur de l'ordonnée
imagestring($courbe, 2,10 , $hauteur-$pasY-6, round($i), $noir);
//Trace la gride
imageline($courbe, 50, $hauteur-$pasY, $largeur-20,$hauteur-$pasY, $ligne);
//Decaller vers le haut pour la prochaine gride
$pasY+=$echelleY;
//Valeur de l'ordonnée suivante
$i+=$py;
}

II-B-5 - Traçage du diagramme

Pour tracer un diagramme d'effectifs, nous calculons la position du point correspondant à la quantité vendue, dessiner un point rouge, tracer le segment vertical (bâton) proportionnel à l'abscisse du point rouge, écrire la quantité vendue en bleu et relier ensuite les points obtenus.

$j=-1;
//Position du premier mois de vente
$pasX=90;
//Parcourir le tableau pour le traçage du diagramme
foreach ($resultat as $mois => $quantite) {
//calculer la hauteur du point par rapport à sa valeur
$y=($hauteur) -(($quantite -$min) * ($echelleY/$py))-$absis;
//dessiner le point
imagefilledellipse($courbe, $pasX, $y, 6, 6, $rouge);
//Afficher le mois en français avec une inclinaison de 315°
imagefttext($courbe, 10, 315, $pasX, $hauteur-$absis+20, $noir, $font_file, $moisFr[$mois-1]);
//Tacer une ligne verticale de l'axe de l'abscisse vers le point
imageline($courbe, $pasX, $hauteur-$absis+$a, $pasX,$y, $noir);
if($j!==-1)
{
//liée le point actuel avec la précédente
imageline($courbe,($pasX-$echelleX),$yprev,$pasX,$y,$noir);
}
//Afficher la valeur au-dessus du point
imagestring($courbe, 2, $pasX-15,$y-14 , $quantite, $bleu);
$j=$quantite;
//enregister la hauteur du point actuel pour la liaison avec la suivante
$yprev=$y;
//Decaller l'abscisse suivante par rapport à son échelle
$pasX+=$echelleX;
}
//Envoyer le flux de l'image
imagepng($courbe);
//Désallouer le mémoire utilisée par l'image
imagedestroy($courbe);

II-B-6 - Graphe obtenu

En ouvrant la page dans un navigateur, nous allons obtenir le diagramme de fréquence correspondant au résultat de la requête.

II-C - Histogramme

Un histogramme représente les mêmes informations que le diagramme des effectifs, mais il est représenté par des rectangles de couleurs différentes selon les produits et de hauteurs différentes selon les quantités.

II-C-1 - La requête SQL

select month(dates) as mois, libelle_produit, sum(quantite) as qtvendu from produit p join vente v using(id_produit)
where year(dates) = 2008 and p.id_type = 1   GROUP BY mois, libelle_produit ORDER BY mois ASC

II-C-2 - Résultat de la requête

II-C-3 - Préparation des données

Cherchons la quantité de vente minimum et maximum des produits pour calculer l'échelle et adapter la largeur de l'image selon le nombre de lignes.

$host="localhost";
$utilisateur="tuto";
$motdepasse="tuto";
$base="tutoriel";
$conexion = new PDO('mysql:host='.$host.';dbname='.$base, $utilisateur, $motdepasse);
$conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sqlQuery = 'select month(dates) as mois, libelle_produit, sum(quantite) as qtvendu from produit p join vente v using(id_produit)
where year(dates) = :year and p.id_type = :idType   GROUP BY mois, libelle_produit ORDER BY mois ASC';
$sth = $conexion->prepare($sqlQuery, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':year' => 2008, ':idType' => 1));
$result = $sth->fetchAll(PDO::FETCH_OBJ);
$i=0;
$element=array();
$js=array();
foreach($result as $row)
{
//Prendre la première quantité vendue comme le minimum et maximum
//Mettre les noms de produit et les mois de ventes dans des tableaux
if($i==0)
{
$min=$row->qtvendu;
$max=$row->qtvendu;
array_push($element, $row->libelle_produit);
array_push($js, $row->mois);
}
//Inserer le nom de produit dans le tableau s'il n'est pas encore enregistrer
if(!in_array($row->libelle_produit,$element))
{
array_push($element, $row->libelle_produit);
}
//Inserer le mois de vente dans le tableau s'il n'est pas encore enregistrer
if(!in_array($row->mois,$js))
{
array_push($js, $row->mois);
}

if($row->qtvendu < $min)
{
$min=$row->qtvendu;
}
else
{
if($row->qtvendu > $max)
{$max=$row->qtvendu;}
}
$i++;
}
//Mettre les mois en francais dans un tableau
$moisFr=array('Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Decembre');

II-C-4 - Préparation de l'image

Connaissant le nombre de lignes, la quantité minimum et maximum, et le nombre de mois de vente de l'année, nous allons adapter l'échelle et la largeur de l'image par rapport à ces données. Nous allons aussi générer des couleurs suivant les produits vendus.

//type mime de l'image
header('Content-type: image/png');
//Chemin vers la police à utiliser
$font_file = './arial.ttf';
//Adapter la largeur de l'image par rapport au nombre de lignes et nombre de mois
$largeur=$i*20+(count($js)*10)+100;
$hauteur=400;
$absis=80;
$courbe=imagecreatetruecolor($largeur, $hauteur);
//Générer un tableau de couleurs
$couleur=array();
$red=0;
$blue=0;
$green=0;
for($n=0;$n<count($element);$n++)
{
$x = $n%3;
switch ($x){
case(0):
$red+=85;
break;
case(1):
$blue+=85;
break;
case(2):
$green+=85;
break;
}
$couleur[$n]=imagecolorallocate($courbe, $red,$green , $blue);
}
//Les autres couleurs utiles
$ligne=imagecolorallocate($courbe, 220, 220, 220);
$fond=imagecolorallocate($courbe, 250, 250, 250);
$noir=imagecolorallocate($courbe, 0, 0, 0);
$blanc=imagecolorallocate($courbe, 255, 255, 255);
$rouge=imagecolorallocate($courbe, 255, 0, 0);
//Colorer le fond
imagefilledrectangle($courbe,0 , 0, $largeur, $hauteur, $fond);
//Tracer l'abscisse et l'ordonnée
imageline($courbe, 50, $hauteur-$absis, $largeur-10,$hauteur-$absis, $noir);
imageline($courbe, 50,$hauteur-$absis,50,20, $noir);
if($min!=0)
{
$absis+=30;
$a=30;
}
$nbOrdonne=10;
//Calculer les échelles suivants les abscisses et ordonnées
$echelleX=($largeur-90-((count($js)*10)))/$i;
$echelleY=($hauteur-$absis-20)/$nbOrdonne;
$i=$min;
$py=($max-$min)/$nbOrdonne;
$pasY=$absis;
//Tracer les grides
while($pasY<($hauteur-19))
{
imagestring($courbe, 2,10 , $hauteur-$pasY-6, round($i), $noir);
imageline($courbe, 50, $hauteur-$pasY, $largeur-20,$hauteur-$pasY, $ligne);
$pasY+=$echelleY;
$i+=$py;
}

II-C-5 - Traçage du diagramme

Pour tracer l'histogramme, dessinons des rectangles dont les hauteurs sont calculées par rapport à l'échelle et aux quantités de produits vendus durant le mois avec les couleurs qui sont générées pour chacun d'eux.

$pasX=60;
$mois=0;
foreach($result as $row)
{
if($mois<($row->mois))
{
//Ecrire le mois en français en abscisse
imagestring($courbe, 2, $pasX,$hauteur-$absis+32 , $moisFr[$row->mois-1], $noir);
//Décaller 10 px du mois précédent
$pasX+=10;
}
//Calculer la hauteur du rectangle
$y=($hauteur) -(($row->qtvendu -$min) * ($echelleY/$py))-$absis;
//Prendre la couleur correspondante au produit
$clr=$couleur[array_search($row->libelle_produit, $element)];
//Dessiner le rectangle
imagefilledrectangle($courbe,$pasX-10 , $hauteur-$absis+$a, $pasX+10, $y, $clr);
//Ecrire la valeur en verticale
imagefttext($courbe, 10, 270, $pasX-3, $y+5, $blanc, $font_file, $row->qtvendu);
//Decaller le prochain rectangle
$pasX+=$echelleX;
$mois=$row->mois;
}
//La legende
$pasX=50;
//Hauteur de la première
$pasY=$hauteur-$absis+47;
foreach ($element as $index=>$libelle)
{
if(($index % 4)==3)
{
$pasX+=120;
$pasY=$hauteur-$absis+47;
}
//Le nom du produit avec sa couleur
imagestring($courbe, 2, $pasX,$pasY , $libelle, $couleur[$index]);
//Un petit rectangle
imagefilledrectangle($courbe,$pasX+80 , $pasY, $pasX+100, $pasY+12, $couleur[$index]);
$pasY+=20;
}
imagepng($courbe);
imagedestroy($courbe);

II-C-6 - Graphe obtenu

II-D - Camembert ou diagramme circulaire

Un camembert est une représentation des données dans un disque dont la somme des angles est égale à 360°. Il sert souvent à la comparaison.
Nous allons comparer la vente des produits durant une année.

II-D-1 - La requête SQL

select sum(quantite) as qtvendu, libelle_produit FROM vente v join produit using(id_produit)
where YEAR(dates)=2008 AND id_type=1 GROUP BY libelle_produit ORDER BY libelle_produit

II-D-2 - Résultat de la requête

II-D-3 - Traçage du diagramme

Pour le diagramme circulaire, nous devons calculer la somme des produits vendus, calculer l'angle pour chaque produit et dessiner pour chacun d'eux un arc plein avec les couleurs qui lui sont attribuées.

<?php
$host="localhost";
$utilisateur="tuto";
$motdepasse="tuto";
$base="tutoriel";
$conexion = new PDO('mysql:host='.$host.';dbname='.$base, $utilisateur, $motdepasse);
$conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sqlQuery = "select sum(quantite) as qtvendu, libelle_produit FROM vente v join produit using(id_produit)
where YEAR(dates)=:year AND id_type=:idType GROUP BY libelle_produit ORDER BY libelle_produit";
$sth = $conexion->prepare($sqlQuery, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':year' => 2008, ':idType' => 1));

$element=array();
$total=0;
foreach($sth->fetchAll(PDO::FETCH_OBJ) as $row)
{
$element[$row->libelle_produit]=$row->qtvendu;
$total+=$row->qtvendu;
}
header('Content-type: image/png');
$largeur=400;
$hauteur=350;
$courbe=imagecreatetruecolor($largeur, $hauteur);
$couleur=array();
$red=0;$blue=0;$green=0;
$nbe=count($element);
$pas=round(255*3/$nbe);
for($n=0;$n<$nbe;$n++)
{
$x = $n%3;
switch ($x){
case(0):
$red+=$pas;
break;
case(1):
$blue+=$pas;
break;
case(2):
$green+=$pas;
break;
}
$couleur[$n][0]=imagecolorallocate($courbe, $red-15,($green==0?$green:($green-15)) , ($blue==0?$blue:($blue-15)));
$couleur[$n][1]=imagecolorallocate($courbe, $red,$green , $blue);
}
$ligne=imagecolorallocate($courbe, 220, 220, 220);
$fond=imagecolorallocate($courbe, 250, 250, 250);
$noir=imagecolorallocate($courbe, 0, 0, 0);
imagefilledrectangle($courbe,0 , 0, $largeur, $hauteur, $fond);
for ($i = 150; $i > 130; $i--)
{
$debut=80;
$j=0;
foreach ($element as $libelle=>$quantite)
{
$valeur=$quantite/$total*360;
$fin=$debut+$valeur;
imagefilledarc($courbe, 200, $i, 350, 220, $debut,$fin, $couleur[$j][0], IMG_ARC_PIE);
$j++;
$debut=$fin;
}
}
$j=0;
$pasX=20;
$pasY=270;
foreach ($element as $libelle=>$quantite)
{
$valeur=$quantite/$total*360;
$fin=$debut+$valeur;
imagefilledarc($courbe, 200, $i, 350, 220, $debut, $fin, $couleur[$j][1], IMG_ARC_PIE);
$debut=$fin;
if(($j % 5)==4)
{
$pasX+=150;
$pasY=270;
}
imagefilledrectangle($courbe,$pasX+120 , $pasY, $pasX+140, $pasY+12, $couleur[$j][1]);
imagestring($courbe, 2, $pasX,$pasY , $libelle.': '.$quantite, $couleur[$j][1]);
$pasY+=20;
$j++;
}
imagepng($courbe);
imagedestroy($courbe);
?>

II-D-4 - Graphe obtenu

III - Les graphes géométriques

Jusqu'ici nous n'avons vu que la génération des graphes, mais maintenant nous allons voir comment les utiliser avec une autre page et un formulaire.
Les graphes géométriques sont des courbes représentant des équations généralement à variable continue.

III-A - Courbe d'une fonction

Créons un petit formulaire pour que les utilisateurs puissent entrer la fonction qu'ils veulent tracer. Utilisons la méthode « POST » pour le formulaire et pour transmettre les données à la page qui va générer la courbe, nous passons la fonction à notre fichier qui génère le graphe en GET.

formulaire

<html>
<head>
<title>Courbe</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<form method="POST">
fonction f(x) =  <input type="text" name="fct" />
<input type="submit" value="Tracer"/>
</form>
<?php if(isset($_POST['fct']))
{
//Affiche la fonction à tracer
echo 'f(x) = '.$_POST['fct'].' <br />';
//appel de la page qui génère l'image en mettant la fonction en URL
echo'<img src="fonction.php?fct='.urlencode($_POST['fct']).'"/>';
}
?>
</body>
</html>

Récupérons ensuite la fonction dans la page qui va tracer la courbe. Les simples utilisateurs ne sauront pas comment sont utilisées les variables en PHP et utilisent les notations de fonction standard (exemple f(x)=sin(x)*2) or PHP ne connait pas la variable x, nous devons alors transformer les x en $x. Dans le cas de l'exponentielle (exp(x)), il sera transformé en e$xp($x) ainsi il faut reconstituer.
Pour tracer la courbe d'une fonction y=f(x), il faut calculer la valeur de y à chaque déplacement de x et nous obtiendrons les coordonnées du point (x,y), calculer ensuite les coordonnées du point suivant et tracer une ligne qui joint les points consécutifs pour obtenir la courbe.

Attention !

L'utilisation de la fonction eval est déconseillée, surtout avec des données provenant d'un utilisateur. Ce code n'est qu'un exemple pour des tests.

fonction.php

<?php
header('Content-type: image/png');
//taille de l'image
$largeur=1000;
$hauteur=800;
//création de l'image
$courbe=imagecreatetruecolor($largeur, $hauteur);
//Allocation des couleurs
$bleu=imagecolorallocate($courbe, 0, 0, 255);
$blanc=imagecolorallocate($courbe, 255, 255, 255);
$rouge=imagecolorallocate($courbe, 255, 0, 0);
$trait=3;
//borne inférieure
$xmin=-10;
//borne supérieure
$xmax=10;
//Calcul des échelles
$echelleX=($largeur-10)/($xmax-$xmin);
$echelleY=$echelleX;
//déclaration de la variable globale pour la fonction
global $fct;
//affectation de la fonction passer en URL dans la variable
$fct=($_GET['fct']);
//Remplacer x par $x pour une variable php
$fct=str_replace('x', '$x', $fct);
//Remplacer e$x par ex pour la fonction exponentielle
$fct=str_replace('e$x', 'ex', $fct);

function f($x)
{
global $fct;
try
{
//evaluer la chaine fct pour avoir une instruction mathématique afin de calculer y
eval( "\$y = $fct;");
}
catch (Exception $exception)
{
$y=0;
}
return($y);
}
//Colorier le fond
imagefilledrectangle($courbe,0 , 0, $largeur, $hauteur, $bleu);
//Tracer les axes de l'abscisse et ordonnée
imageline($courbe, 0, $hauteur/2, $largeur,$hauteur/2, $blanc);
imageline($courbe, $largeur/2,0,$largeur/2,$hauteur, $blanc);
//Ecrire les graduations négatives de l'abscisse
$pasX=$largeur/2;
$i=0;
while($pasX>0)
{
//Ecrire la valeur
if($i!=0)
{
imagestring($courbe, 1, $pasX-$trait,$hauteur/2+10 , -$i, $blanc);
}
//Le petit trait
imageline($courbe, $pasX, $hauteur/2-$trait, $pasX,$hauteur/2+$trait, $blanc);
$pasX=$pasX-$echelleX;
$i++;
}
//Ecrire les graduations positives de l'abscisse
$pasX=$largeur/2;
$i=0;
while($pasX<$largeur)
{
if($i!=0)
{
imagestring($courbe, 1, $pasX-$trait,$hauteur/2+10 , $i, $blanc);
}
imageline($courbe, $pasX, $hauteur/2-$trait, $pasX,$hauteur/2+$trait, $blanc);
$pasX=$pasX+$echelleX;
$i++;
}
//Ecrire les graduations négatives de l'ordonnée
$pasY=$hauteur/2;
$i=0;
while($pasY>0)
{
if($i!=0)
{
imagestring($courbe, 1, $largeur/2-10,$pasY-3 , $i, $blanc);
}
imageline($courbe, $largeur/2-$trait, $pasY, $largeur/2+$trait, $pasY, $blanc);
$pasY=$pasY-$echelleY;
$i++;
}
//Ecrire les graduations positives de l'ordonnée
$pasY=$hauteur/2;
$i=0;
while($pasY<$hauteur)
{
if($i!=0)
{
imagestring($courbe, 1, $largeur/2-14,$pasY-3 , -$i, $blanc);
}
imageline($courbe, $largeur/2-$trait, $pasY, $largeur/2+$trait, $pasY, $blanc);
$pasY=$pasY+$echelleY;
$i++;
}

//Traçage de la courbe
$j=false;
$pas=0.01;
$xmin=-10;
$xmax=-$xmin;
while($xmin<$xmax)
{
//Calculer l'ordonnée du point
$y=round(-f($xmin)*$echelleY)+($hauteur/2);
if($j)
{
//Joindre le point présent avec la précédente
imageline($courbe,round(($xmin-$pas)*$echelleX)+($largeur/2),$yprev,round(($xmin)*$echelleX)+($largeur/2),$y,$rouge);
}
$j=true;
//Sauvegarder l'ordonnée du point actuel
$yprev=$y;
$xmin+=$pas;
}
//Envoie du flux de l'image
imagepng($courbe);
imagedestroy($courbe);
?>

III-B - Courbe représentant une équation polaire

Pour tracer une courbe d'une équation polaire, nous utilisons une paramétrisation cartésienne pour faciliter la tâche, c'est-à-dire utiliser deux équations, l'une pour calculer x et l'autre pour calculer y en fonction de l'angle thêta pour obtenir les coordonnées d'un point(x,y). Nous prenons comme exemple les cas des épicycloïdes et hypocycloïdes. Une hypocycloïde et une épicycloïde ont la même équation, mais seulement le paramètre q de l'hypocycloïde prend la valeur négative de celui de l'épicycloïde.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Dessin</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<?php $st='selected="selected"'?>
</head>
<body>
<form method="POST">
<table>
<tr>
<td>Type de courbe:</td>
<td>
<select name="type">
<option value="2" <?php if(isset($_POST['type'])&& $_POST['type']=="2") echo $st;?>>Epicycloïde</option>
<option value="3" <?php if(isset($_POST['type'])&& $_POST['type']=="3") echo $st;?>>Hypocycloïde</option>
<option value="4" <?php if(isset($_POST['type'])&& $_POST['type']=="4") echo $st;?>>Epi&Hypo-cycloïde</option>
</select>
</td>
</tr>
<tr><td>Couleur :</td>
<td>
<select name="couleur">
<option value="1" <?php if(isset($_POST['couleur'])&& $_POST['couleur']=="1") echo $st;?>>Bleue</option>
<option value="2" <?php if(isset($_POST['couleur'])&& $_POST['couleur']=="2") echo $st;?>>Rouge</option>
<option value="3" <?php if(isset($_POST['couleur'])&& $_POST['couleur']=="3") echo $st;?>>Verte</option>
</select>
</td></tr>
<tr>
<td >q : </td>
<td>
<input type="text" name="k" size="4" <?php if(isset($_POST['k']))
{echo ' value="'.$_POST['k'].'"';}
else {echo ' value="1.8"';} ?>/>
</td>
</tr>
<tr><td colspan="2" align="center"><input type="submit" value="Dessiner"/> </td></tr>
</table>
</form>
<?php if(isset($_POST['type']))
{
echo'<img src="dessin.php?type='.$_POST['type'].'&q='.$_POST['k'].'&couleur='.$_POST['couleur'].'"/>';
}
else
{
echo'<img src="dessin.php?type=2&q=1.8&couleur=1"/>';
}
?>
</body>
</html>

dessin.php

<?php
header('Content-type: image/png');
$largeur=400;
$hauteur=400;
$courbe=imagecreatetruecolor($largeur, $hauteur);
$fond=imagecolorallocate($courbe, 245, 245, 245);
imagefilledrectangle($courbe,0 , 0, $largeur, $hauteur, $fond);
if(isset($_GET['type'])&& !empty ($_GET['type']))
{
$type=$_GET['type'];
if($_GET['couleur']=="2")
{
$couleur=imagecolorallocate($courbe, 255,0, 0);
}
else{
if
(
$_GET['couleur']=="1"){$couleur=imagecolorallocate($courbe, 0,0, 255);
}
else
{
$couleur=imagecolorallocate($courbe, 0,255, 0);
}
}
$q=$_GET['q'];
eval( "\$q = $q;");
switch ($type)
{
//Epicycloïde
case '2':
{
$xmin=-8*M_PI;
$xmax=8*M_PI;
$echelleX=70;
$echelleY=$echelleX;
while($xmin<($xmax)) {
$x=(($q+1)*cos($xmin)-(cos(($q+1)*$xmin)))/$q;
$y=(($q+1)*sin($xmin)-(sin(($q+1)*$xmin)))/$q;
imagesetpixel($courbe,round($x*$echelleX)+($largeur/2),round(-$y*$echelleY)+($hauteur/2),$couleur);
$xmin+=0.001;
}
break;
}
//Hypocycloïde
case'3':
{
$xmin=-8*M_PI;
$xmax=8*M_PI;
$echelleX=70;
$echelleY=$echelleX;
while($xmin<($xmax)) {
$x=(($q-1)*cos($xmin)+(cos(($q-1)*$xmin)))/$q;
$y=(($q-1)*sin($xmin)-(sin(($q-1)*$xmin)))/$q;
imagesetpixel($courbe,round($x*$echelleX)+($largeur/2),round(-$y*$echelleY)+($hauteur/2),$couleur);
$xmin+=0.001;
}
break;
}
//Superposition d'une Hypocycloïde et Epicycloïde
case '4':
{
$xmin=-8*M_PI;
$xmax=8*M_PI;
$echelleX=70;
$echelleY=$echelleX;
while($xmin<($xmax)) {
$x=(($q+1)*cos($xmin)-(cos(($q+1)*$xmin)))/$q;
$y=(($q+1)*sin($xmin)-(sin(($q+1)*$xmin)))/$q;
imagesetpixel($courbe,round($x*$echelleX)+($largeur/2),round(-$y*$echelleY)+($hauteur/2),$couleur);
$x=(($q-1)*cos($xmin)+(cos(($q-1)*$xmin)))/$q;
$y=(($q-1)*sin($xmin)-(sin(($q-1)*$xmin)))/$q;
imagesetpixel($courbe,round($x*$echelleX)+($largeur/2),round(-$y*$echelleY)+($hauteur/2),$couleur);
$xmin+=0.001;
}
break;
}
}
}
imagepng($courbe);
imagedestroy($courbe);
?>

III-B-1 - Capture d'écran

IV - Conclusions

Nous avons pu voir comment utiliser la bibliothèque GD pour créer quelques graphes statistiques, mais il en manque encore d'autres comme le diagramme de fréquence, la toile d'araignée, les pyramides d'âges, etc. Ces autres diagrammes se basent sur les mêmes principes que les exemples que nous avons pris dans cet article. Par exemple pour les diagrammes de fréquence du suivi des ventes d'un produit au cours d'une année, il suffit de calculer la quantité vendue en un mois sur la quantité de vente totale durant l'année.

V - Remerciements

Mes remerciements à RideKick pour la relecture de cet article.

VI - Téléchargement des codes source

Télécharger les codes source