Comme nous tous, vous vous êtes laissé séduire par ggplot2. L’élégance des graphes, la facilité de grouper les données… Vous avez décidé de convertir tous vos graphes en graphes ggplot2 pour ensuite vous rendre compte, après tout vos efforts, que vous étiez incapable d’identifier un point d’intérêt facilement. En effet, la fonction identify (qui permet de cliquer sur un point d’un graphique pour récupérer ses coordonnées) ne fonctionne plus! Comment étiquetter facilement le point outlier alors?

plot

Heureusement, il y a une solution. Elle implique par contre d’aller voir sous la surface de ggplot2 afin d’accéder au système de plus bas niveau sur lequel le package est construit, grid. Le module grid offre des méthodes pour diviser une fenêtre en plusieurs régions graphiques, chacune avec sa propre vues (viewport). Nous pouvons utiliser ces méthodes pour accéder à la vue d’un graphique et effectuer la conversion entre les coordonnées à l’écran et nos données afin d’identifier le point le plus proche.

ggplot

Il existe, en fait, une hiérarchie de vues pour chaque graphe ggplot2. Une fois le graphe créé, nous devons retrouver la vue appropriée parmi toutes les vues associées au fond, au titre, aux axes, à la légende, etc. Dans le cas le plus simple, cette vue se nomme panel.3-4-3-4 et nous pouvons déplacer notre système de coordonnées pour y faire référence comme ceci :


qplot(x, y) + xlim(c(0,10)) + xlim(c(0.1,0.5)) 
downViewport('panel.3-4-3-4') 
pushViewport(dataViewport(x, y, c(0,10), c(0.1, 0.5))) 

Nous pouvons ensuite récupérer les coordonnées de l’écran (en pouces, rien de moins!) en utilisant grid.locator. Ces coordonnées sont relatives au coin inférieur gauche. Ensuite, nous n’avons qu’à trouver le point parmi nos données qui est le plus proche de ces coordonnées. Pour ce faire, nous utilisons les méthodes convertUnit pour transformer nos données vers une échelle en pouces.


pick.n <- as.numeric(pick)
view.x <- as.numeric(convertX( unit(x,'native'), 'in' ))
view.y <- as.numeric(convertY( unit(y,'native'), 'in' ))
w <- which.min((view.x-pick.n[1])^2 + (view.y-pick.n[2])^2)

Une fois ce point identifié, nous pouvons simplement utiliser la méthode annotate pour ajouter une étiquette. Voici la fonction complète :


ggidentify 0.1) {
      print("Closest point is too far")
    } else {  
      popViewport(n=1)
      upViewport(depth)
      print(last_plot() + annotate("text", label=labels[w], x = x[w], y = y[w], 
                                   size = 5, hjust=-0.5, vjust=-0.5))
      depth <- downViewport('panel.3-4-3-4')
      pushViewport(dataViewport(x,y, xscale, yscale))
    }
    pick <- grid.locator('in')
  }
  popViewport(n=1)
  upViewport(depth)
}

Évidemment, cette fonction n'est pas aussi satisfaisante que la fonction identify que nous avons essayé d'imiter. Par exemple, il n'y a aucun historique conservant les points déjà identifiés et étiquettés. Nous pourrions donc nous retrouver avec de multiples étiquettes sur un même point (si on le clique plusieurs fois), rendant le graphique illisible. Aussi, cette méthode doit être employée avant l'appel à d'autre fonctions ggplot2 étant donné que ces dernières peuvent initier un changement d'échelle automatique. Enfin, reconvertir toutes nos données en pouces à chaque clic n'est définitivement pas optimal!

Malgré ces petits défauts, nous avons nos étiquettes!

labeled