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 exemples, 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 la suivie 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 visuellement et 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 de 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é vendu comme minimum et maximum
if($i
==
0)
{
$min
=
$row
->
qtvendu;
$max
=
$row
->
qtvendu;
}
//Tester si la quantité vendu est inférieur au minimum et le prendre si il l'est
if($row
->
qtvendu <
$min
)
{
$min
=
$row
->
qtvendu;
}
//Tester si la quantité vendu est inférieur au maximum et le prendre si 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 aux nombres 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 le police à utiliser
$font_file
=
'
./arial.ttf
'
;
//Adapter la largeur de l'image avec le nombre de donnée
$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'echelle des abscisses
$echelleX
=
($largeur
-
100)/
$i
;
//Calcul de l'echelle des ordonnees
$echelleY
=
($hauteur
-
$absis
-
20)/
$nbOrdonne
;
$i
=
$min
;
//Calcul des ordonnees des grides
$py
=
($max
-
$min
)/
$nbOrdonne
;
$pasY
=
$absis
;
while($pasY
<
($hauteur
-
19))
{
//Affiche la valeur de l'ordonnee
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'ordonnee 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 de la première mois de vente
$pasX
=
90;
//Parcourir le tableau pour le traçage de la diagramme
foreach ($resultat
as $mois
=>
$quantite
) {
//calculer la hateur 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 veticale 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 echelle
$pasX
+=
$echelleX
;
}
//Envoyer le flux de l'image
imagepng($courbe
);
//Desallouer le memoire utiliser 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 premiere quantite 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 le police à utiliser
$font_file
=
'
./arial.ttf
'
;
//Adapter la largeur de l'image par rapport au nombre de ligne 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 autre couleurs utils
$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 de la 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 premiere
$pasY
=
$hauteur
-
$absis
+
47;
foreach ($element
as $index
=>
$libelle
)
{
if(($index
%
4)==
3)
{
$pasX
+=
120;
$pasY
=
$hauteur
-
$absis
+
47;
}
//Le nom du poduit 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
);
?>