Une introduction aux graphiques avec R


Bonjour.

Je vous propose de faire une introduction à la modélisation de données à travers l’utilisation du langage R. D’après Wikipedia, il s’agit d’un langage libre dédié aux statistiques et à la science des données. Bien entendu, nous n’évoquerons ici qu’une infime partie de ce dont cet écosystème est capable dans la mesure où la majorité des tâches qu’il est à même de réaliser sont incompréhensibles par ma personne… Il faut croire que l’on ne s’improvise pas mathématicien !

Heureusement pour nous, il n’est pas nécessaire de tout maitriser pour pouvoir au moins profiter d’un fragment (et non du moindre !) : les bibliothèques très avancées de représentation des données sous une forme de multitudes de graphes différents. Commençons avec une mise en contact fortement inspirée du tutoriel présent sur le site Harding.

Les bases des graphes en R

Avant tout, il faudra installer le logiciel. Sous Fedora par exemple, un simple sudo dnf install R fera l’affaire.

Le premier contact

Voici une liste d’instructions à renseigner dans votre interpréteur R :

[sourcecode lang= »r » title= »Dessin de notre premier graphique »]
# Définition de deux vecteurs.
> cars <- c(1, 3, 6, 4, 9)
> trucks <- c(2, 5, 4, 5, 12)

# On récupères les deux valeurs extrêmes contenues entre le scalaire 0,
# et l’ensemble des valeurs contenues dans les vecteurs « cars » et « trucks ».
> g_range <- range(0, cars, trucks)
# g_range possède bien deux valeurs : la minimale et la maximale.
> g_range
[1] 0 12

# Cette commande génère une ligne représentant les valeurs de notre vecteur « cars ».
# Pour plus d’information concernant l’utilisation de la fonction «plot »,
# je vous invite à lire la documentation adéquate.
> plot(cars, type="o", col="blue", ylim=g_range,
+ axes=FALSE, ann=FALSE)

# Nous créons l’axe des abscisses, des points 1 à 5, ayant respectivement les valeurs
# contenues dans le vecteur « lab ».
> axis(1, at=1:5, lab=c("Mon","Tue","Wed","Thu","Fri"))

# Création de l’axe des ordonnées, avec un label toutes les quatre entrées,
# de zéro au second élément de g_range, soit la valeur maximale.
> axis(2, las=1, at=4*0:g_range[2])

# Création d’une « boite » au tour du graphique.
> box()

# Ajout d’une ligne correspondant aux valeurs des camions.
> lines(trucks, type="o", pch=22, lty=2, col="red")

# Ajout d’un titre au tableau.
> title(main="Autos", col.main="red", font.main=4)

# Ajout d’un titre à l’axe des abscisses.
> title(xlab="Days", col.lab=rgb(0,0.5,0))
# Ajout d’un titre à l’axe des ordonnées.
> title(ylab="Total", col.lab=rgb(0,0.5,0))

# Création d’un bloc de légende en haut à gauche.
> legend(1, g_range[2], c("cars","trucks"), cex=0.8,
+ col=c("blue","red"), pch=21:22, lty=1:2);
[/sourcecode]

À présent, le tableau ci-dessous devrait être généré. Il n’a rien d’exceptionnel, mais nous pouvons quand même constater la simplicité avec laquelle il aura été réalisé.

Utilisation des véhicules cette semaine
Notre premier graphique en R !

Si nous désirons avoir une sortie autre que via R Graphics, nous pouvons le faire avant de commencer à dessiner le graphe. Par exemple, si nous renseignons l’instruction png(filename="/tmp/figure.png", height=295, width=300, bg="white") avant toutes celles du bloc précédent, l’image sera en fait constituée dans le fichier /tmp/figure.png. De la même façon pdf(file="/tmp/figure.pdf", height=3.5, width=5) permettra d’enregistrer le graphique dans un PDF. Attention toutefois, car à présent le dessin ne se fera plus en temps réel. Il faudra en effet finir avec l’instruction dev.off() pour écrire le fichier sur le disque dur.

Lecture depuis un fichier

Il est bon à savoir que nous pouvons très facilement récupérer les données d’un fichier plutôt que de devoir les écrire en dur dans le code de notre application. On pourrait par exemple avoir le fichier suivant :

[sourcecode lang= »plain » title= »Fichier auto.dat »]
cars trucks suvs
1 2 4
3 5 4
6 4 6
4 5 6
9 12 16
[/sourcecode]

Qui serait utilisé de cette façon :

[sourcecode lang= »r » title= »Chargement d'un fichier en R »]
# On charge le fichier, en disant que la première ligne
# correspond au header, et la tabulation comme séparateur de colonnes.
> autos_data <- read.table("/tmp/auto.dat", header=TRUE, sep="\t")
#Le fichier a bien été chargé.
> autos_data
cars trucks suvs
1 1 2 4
2 3 5 4
3 6 4 6
4 4 5 6
5 9 12 16
# Nous pouvons à présent utiliser les éléments de ce fichier
# comme nous le faisions précédemment avec des vecteurs.
# Voici par exemple la génération de la ligne correspondant
# aux infos des camions.
> lines(autos_data$trucks, type="o", pch=22, lty=2, col="red")
[/sourcecode]

De façon similaire, il serait également possible de récupérer les données depuis des systèmes de gestion de base de données comme SQLite.

L’intégration des graphiques dans des documents LaTeX

Une autre force de R et la grande intégration que l’écosystème partage avec celui de LaTeX, le compositeur de documents. Nous présenterons le module R « tikzDevice », qui permet d’obtenir une sortie TikZ des graphiques. Voici une illustration :

[sourcecode lang= »r » title= »Fichier : figs/auto.R »]
#!/usr/bin/env Rscript
require("tikzDevice")
tikz("auto.tex", width = 5, height = 3)

cars <- c(1, 3, 6, 4, 9)
trucks <- c(2, 5, 4, 5, 12)
g_range <- range(0, cars, trucks)

plot(cars, type="o", col="blue", ylim=g_range, axes=FALSE, ann=FALSE)
axis(1, at=1:5, lab=c("Mon", "Tue", "Wed", "Thu", "Fri"))
axis(2, las=1, at=4*0:g_range[2])
box()
lines(trucks, type="o", pch=22, lty=2, col="red")

title(main="Autos", col.main="red", font.main=4)
title(xlab="Days", col.lab=rgb(0,0.5,0))
title(ylab="Total", col.lab=rgb(0,0.5,0))
legend(1, g_range[2], c("cars","trucks"), cex=0.8, col=c("blue","red"), pch=21:22, lty=1:2);

dev.off()
[/sourcecode]

[sourcecode lang= »tex » title= »Fichier : main.tex »]
\documentclass[a4paper, 10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[top=2cm, bottom=2cm, left=2cm, right=2cm]{geometry}
\usepackage{tikz}
\title{Essais d’intégration \tt{R} dans \LaTeX}
\author{Kevin Hagner}
\date{\today}

\begin{document}

\maketitle

\begin{figure}[h]
\centering
\input{figs/auto.tex}
\caption{Utilisation des véhicules motorisés}
\end{figure}

Voici un graphe représentant l’utilisation des véhicules motorisés ces derniers temps.
\end{document}
[/sourcecode]

Nous pouvons voir que depuis le fichier LaTeX, on importe figs/auto.tex, qui n’existe en fait pas encore. Pour l’obtenir, il faudra exécuter le script R qui le génèrera :

[sourcecode lang= »plain » padlinenumbers= »false » title= »Commandes Linux à exécuter pour générer correctement le document »]
> cd figs
> ./auto.R
> cd ..
> pdflatex main.tex
[/sourcecode]

Le résultat nous montre une intégration parfaite ☺.

http://share.spyzone.fr/blog/r_1.pdf

Une grande variété de types de graphes différents

Pour cette illustration, j’ai employé la plus basique des méthodes de représentation les données : un graphique en deux dimensions. R nous permet d’en utiliser une variété d’autres de façon tout aussi simple. Il est même possible pour chacun d’entre nous de réaliser nos propres systèmes. Cette page en liste quelques-uns.

Ces types de graphes sont également exportables dans les formats précédemment évoqués : PNG, PDF, TikZ, mais aussi beaucoup d’autres (svg, cairo, etc.).

La création de documents Web interactifs

L’interaction côté client

Rédiger des documents texte de qualité est une bonne chose, mais profiter de l’interactivité que peut nous offrir le Web en est une autre, autrement plus intéressante ! Ainsi, un grand nombre de libraires JavaScript de représentation des données permettent d’être directement utilisables depuis R grâce au projet htmlwidget.

De cette façon, au lieu de réaliser une image PNG, un PDF, ou un autre format de dessin statique, nous générerons une page HTML chargeant toutes les dépendances nécessaires à l’affichage de la représentation via la librairie choisie.

Voyons un exemple présent sur le site sus-cité permettant d’utiliser la bibliothèque Bokeh.

[sourcecode lang= »r »]
> library(rbokeh) #Chargement de rbokeh
> # Nous affichons ici un jeu de données préchargé dans l’environnement R
> # à des fins de test. On va l’utiliser pour générer notre graphique.
> iris
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
[…]

> figure() %>%
+ # On affiche un graphe ayant la longueur du sepale
+ # en abscisse, et sa largeur en ordonnée.
+ ly_points(Sepal.Length, Sepal.Width, data = iris,
+ # La couleur et la forme des points dépendra de l’espèce.
+ color = Species, glyph = Species,
+ # Quand on passe la souris sur un point, des informations
+ # complémentaires seront disponible, à savoir la hauteur et largeur du sépale.
+ hover = list(Sepal.Length, Sepal.Width))
[/sourcecode]

C’est tout ce dont on a besoin ! Bon pour être franc, il est vrai que l’intérêt peut se montrer un peu limité pour des développeurs habitués à travailler avec des technologies Web, car plutôt que de passer par R, nous pouvons directement utiliser les libraires sous-jacentes, ce qui permettrait peut-être d’avoir un code plus optimisé. Néanmoins, ça reste une solution intéressante par sa rapidité de mise en œuvre.

[iframe width= »600px » height= »580px » src= »http://share.spyzone.fr/blog/r_2.html »]

Attention, je pense que l’intégration du graphique dans cette page est assez mauvaise, car il s’agit d’une iframe dont l’ensemble des dépendances (notamment bokeh.min.js rbokeh.js htmlwidget.js) on été injectées en base 64 dans le contenu même de la page. Celle-ci est donc beaucoup plus lourde, et surtout ne permet ni la mise en cache les lib par le navigateur, ni la réutilisation dans le cas où plusieurs graphiques seraient sur la même page. Plus d’explications sur la méthode ici.

Shiny : le serveur web dynamique

Là où la chose peut devenir plus intéressante encore, c’est si nous voulons ajouter un cran de plus au niveau de l’interactivité en permettant de charger dynamiquement l’affichage côté serveur. C’est ce que Shiny nous propose.

Prenons par exemple ce graphique, qui représente le prix de diamants en fonction de leurs carats, depuis des données de test :

[sourcecode lang= »r »]
> library(ggplot2)
> # Génération du graphique
> p <- ggplot(diamonds, aes(x=carat, y=price)) + geom_point()
> # Exportation du graphique en SVG
> ggsave(file="diamonds.svg", plot=p, width=6, height=4)
[/sourcecode]

Graphique du prix des diamants en fonction de leurs carats
Prix des diamants en fonction de leurs carats

Nous pouvons trouver que celui-ci affiche bien trop d’éléments à notre goût (53 940 points). Pour pouvoir choisir dynamiquement le nombre de points à représenter, nous pourrions utiliser le code de ces deux fichiers :

[sourcecode lang= »r » title= »Fichier : ui.R »]
library(shiny)

# Les données à utiliser seront celles du jeu "diamonds"
dataset <- diamonds

shinyUI(fluidPage(
# Ici, on dessine la page.
title = ‘Use the DT package in shiny’,
sidebarLayout (
# On utilisera deux colonnes dans notre page.
# La première contiendra un slider.
sidebarPanel (
sliderInput("bins", "Number of bins:",
min= 1, max = nrow(dataset), value = 1000)
),
# La seconde un graphique nommé "distPlot".
mainPanel (plotOutput("distPlot"))
)
))
[/sourcecode]

[sourcecode lang= »r » title= »Fichier : server.R »]
library(shiny)
library(DT)
library(ggplot2)

shinyServer(function(input, output, session) {
# Le dataset ne correspond plus à l’ensemble de éléments
# présent dans "diamonds", mais uniquement des x premières
# lignes, avec x défini par la valeur de notre slider
# "bins".
dataset <- reactive({
diamonds[sample(nrow(diamonds), input$bins),]
})
# On dessine notre graphique qu’on renverra au client
# dans l’élément "distPlot".
output$distPlot <- renderPlot({
p <- ggplot(dataset(), aes_string(x=’carat’, y=’price’)) + geom_point()
print(p)
})
})
[/sourcecode]

Et enfin, de lancer notre application de cette façon :

[sourcecode lang= »r »]
> package("shiny")
> package("ggplot2")
> # Si ui.R et server.R sont dans le dossier courant.
> runApp(".")

Listening on http://127.0.0.1:5642
[/sourcecode]

Maintenant, on aura un serveur Web Shiny qui s’exécutera sur notre machine (ici sur le port 5642), que l’on pourra interroger pour récupérer une page HTML. Deux éléments sont créés depuis le code ui.R : un slider nommé « bins », et un graphique « distPlot ». Ce dernier est généré depuis le fichier server.R, à l’aide de la valeur du slider (initialisée à 1000).

Capture d'écran de notre graphique et de son slider.
Capture d’écran de notre graphique et de son slider.

Encore une fois, cet exemple est très simpliste et est loin de rendre honneur à l’étendue de ce que Shiny peut gérer. Il permet par exemple de concevoir des dashboard entiers. Mais comme évoqué dans le titre de cet article, il ne s’agit ici que d’introductions. Une des questions que je me pose quand même avec Shiny réside dans la consommation en ressources de l’outil, et si un unique serveur est en mesure de gérer plusieurs dashboards.

Conclusion

Je pense en avoir fini avec ce tour des diverses possibilités que nous offre R dans la représentation des données. Il s’agit d’un travail de synthèse que j’ai effectué par curiosité après en avoir entendu parler. Malgré ma vigilance, il est donc probable que des petites erreurs se soient glissées dans le texte, ou alors que je sois passé à côté d’autres outils qui auraient eux aussi mérités leur paragraphe ici. Si tel est le cas, je vous invite à m’en faire part. En attendant, je ne peux que vous encourager à approfondir vos connaissances dans ces outils et à mettre tout cela en pratique !


Crédits images :

  • Le graphique en couverture par 1492ANDIBLAIR.
  • Les autres documents liés à cet articles (les graphes, fichier pdf, etc.) sont tous de moi, et sont inspirés de sources indiqués dans les paragraphes respectifs.

Publication originale :

Cet article a été publié initialement sur le blog Netapsys.
Logo Netapsys