web-dev-qa-db-fra.com

Positionnement intelligent des étiquettes de points dans R

1) Existe-t-il une bibliothèque/fonction R qui implémenterait le placement d'étiquettes INTELLIGENT dans le tracé R? J'en ai essayé quelques-unes mais elles sont toutes problématiques - beaucoup d'étiquettes se chevauchent l'une l'autre ou d'autres points (ou d'autres objets dans l'intrigue, mais je vois que c'est beaucoup plus difficile à gérer).

2) Si non, y a-t-il un moyen d'aider COMFORTABEMENT l'algorithme à placer les étiquettes pour des points problématiques particuliers? La solution la plus confortable et efficace recherchée.

Vous pouvez jouer et tester d'autres possibilités avec mon exemple reproductible et voir si vous pouvez obtenir de meilleurs résultats que ceux que j'ai:

# data
x = c(0.8846, 1.1554, 0.9317, 0.9703, 0.9053, 0.9454, 1.0146, 0.9012, 
0.9055, 1.3307)
y = c(0.9828, 1.0329, 0.931, 1.3794, 0.9273, 0.9605, 1.0259, 0.9542, 
0.9717, 0.9357)
ShortSci = c("MotAlb", "PruMod", "EriRub", "LusMeg", "PhoOch", "PhoPho", 
"SaxRub", "TurMer", "TurPil", "TurPhi")

# basic plot
plot(x, y, asp=1)
abline(h = 1, col = "green")
abline(v = 1, col = "green")

Pour l'étiquetage, j'ai ensuite essayé ces possibilités, personne n'est vraiment bon:

1) celui-ci est terrible:

text(x, y, labels = ShortSci, cex= 0.7, offset = 10)

2) Celui-ci est utile si vous ne souhaitez pas placer d'étiquettes pour tous les points, mais uniquement pour les valeurs aberrantes, mais les étiquettes sont souvent mal placées:

identify(x, y, labels = ShortSci, cex = 0.7)

3) celle-ci semblait prometteuse, mais il y a le problème des étiquettes trop proches des points; Je devais les garnir d'espaces mais cela n'aide pas beaucoup:

require(maptools)
pointLabel(x, y, labels = paste("  ", ShortSci, "  ", sep=""), cex=0.7)

4)

require(plotrix)
thigmophobe.labels(x, y, labels = ShortSci, cex=0.7, offset=0.5)

5)

require(calibrate)
textxy(x, y, labs=ShortSci, cx=0.7)

Merci d'avance!

EDIT: todo: try labcurve {Hmisc} .

100
TMS

J'ai trouvé une solution! Malheureusement, ce n’est pas ultime et idéal, mais c’est celui qui me convient le mieux à présent. Il est à moitié algoritmique, à moitié manuel, ce qui fait gagner du temps par rapport à la solution manuelle pure dessinée par joran.

J'ai négligé très partie importante de l'aide ?identify!

L'algorithme utilisé pour placer les étiquettes est le même que celui utilisé par text si pos est spécifié ici, la différence étant que la position du pointeur par rapport au point identifié détermine pos in identifier.

Donc, si vous utilisez la solution identify() comme je l’ai écrit dans ma question, alors vous pouvez affecter la position du libellé en ne cliquant pas directement sur ce point, mais en en cliquant à côté de ce point relativement dans la direction souhaitée !!! Fonctionne simplement très bien!

L'inconvénient est qu'il n'y a que 4 positions (haut, gauche, bas, droite), mais j'apprécierais davantage les 4 autres (haut-gauche, haut-droite, bas-gauche, bas-droite) ... utilisez ceci pour marquer les points où cela ne me dérange pas et le reste des points que je marque directement dans ma présentation PowerPoint, comme proposé par joran :-)

P.S .: Je n'ai pas encore essayé la solution directlabels lattice/ggplot, je préfère quand même utiliser la bibliothèque de base Plot.

5
TMS

Tout d'abord, voici les résultats de ma solution à ce problème:

enter image description here

Je l'ai fait à la main dans Aperçu (visionneuse très simple de PDF/images sous OS X) en quelques minutes seulement. (Edit: Le workflow correspondait exactement à ce que vous attendiez: j'ai enregistré le tracé en tant que PDF de R, l'a ouvert dans Aperçu et créé des zones de texte avec les libellés souhaités. (9pt Helvetica), puis je les ai simplement déplacés avec la souris jusqu'à ce qu'ils soient beaux. Ensuite, j'ai exporté au format PNG pour le télécharger sur SO.)

Maintenant, avant de céder à la forte envie de voter pour ceci dans l'oubli et de laisser des commentaires sournois sur la nécessité d'automatiser ce processus, écoutez-moi!

Rechercher des solutions algorithmiques est tout à fait correct, et (IMHO) vraiment intéressant. Mais, pour moi, les situations d’étiquetage ponctuel se répartissent en trois catégories:

  1. Vous avez un petit nombre de points, aucun ne sont terriblement proches les uns des autres. Dans ce cas, l’une des solutions que vous avez énumérées dans la question est susceptible de fonctionner avec des ajustements assez minimes.
  2. Vous avez un petit nombre de points, dont certains sont trop compacts pour que les solutions algorithmiques typiques donnent de bons résultats. Dans ce cas, puisque vous ne possédez qu'un petit nombre de points, les étiqueter à la main (avec un éditeur d'image ou en ajustant votre appel à text) n'est pas ça beaucoup effort.
  3. Vous avez un assez grand nombre de points. Dans ce cas, vous ne devriez vraiment pas les étiqueter, car il est difficile de traiter visuellement un grand nombre d'étiquettes.

: grimper sur la tribune:

Puisque des gens comme nous amour automatisation, je pense que nous tombons souvent dans le piège consistant à penser que presque tous les aspects de la production d’un bon graphique statistique doivent être automatisés. Je suis respectueusement (humblement!) En désaccord.

Il n’existe aucun environnement de tracé statistique parfaitement général qui crée automatiquement l’image que vous avez dans la tête. Des choses comme R, ggplot2, réseau etc. font la plupart du travail; mais ce petit peu d'ajustement, l'ajout d'une ligne ici, l'ajustement d'une marge ici, est probablement mieux adapté à un outil différent.

: descendant de la caisse à savon:

Je voudrais également noter que je pense que nous pourrions tous créer des diagrammes de dispersion avec <10-15 points qui seront presque impossibles à étiqueter proprement, même à la main, et qui casseront probablement toute solution automatique proposée par quelqu'un.

Enfin, je tiens à répéter que je savoir Ce n’est pas la réponse que vous cherchez. Et je pas dit que les tentatives algorithmiques sont inutiles ou stupides. J'ai voté contre cette question, et je voterai avec enthousiasme pour les solutions algorithmiques intéressantes!

La raison pour laquelle j'ai posté cette réponse est que je pense que cette question devrait être la question canonique "d'étiquetage ponctuel en R" pour les doublons à venir, et je pense que les solutions impliquant l'étiquetage à la main méritent une place à la table, c'est tout.

47
joran

ggrepel semble prometteur lorsqu'il est appliqué à ggplot2 nuages ​​de points.

# data
x = c(0.8846, 1.1554, 0.9317, 0.9703, 0.9053, 0.9454, 1.0146, 0.9012, 
0.9055, 1.3307)
y = c(0.9828, 1.0329, 0.931, 1.3794, 0.9273, 0.9605, 1.0259, 0.9542, 
0.9717, 0.9357)
ShortSci = c("MotAlb", "PruMod", "EriRub", "LusMeg", "PhoOch", "PhoPho", 
"SaxRub", "TurMer", "TurPil", "TurPhi")


df <- data.frame(x = x, y = y, z = ShortSci)
library(ggplot2)
library(ggrepel)

ggplot(data = df, aes(x = x, y = y)) + theme_bw() + 

    geom_text_repel(aes(label = z), 
       box.padding = unit(0.45, "lines")) +

    geom_point(colour = "green", size = 3)

enter image description here

39
Sandy Muspratt

Avez-vous essayé le package directlabels ?

Et, BTW, les arguments pos et offset peuvent prendre des vecteurs pour vous permettre de les placer dans les bonnes positions quand il y a un nombre raisonnable de points dans quelques exécutions de parcelles.

10
John

Je vous suggère de jeter un coup d'œil au paquetage wordcloud. Je sais que ce paquet ne se concentre pas exactement sur les points mais sur les étiquettes elles-mêmes, et le style semble être plutôt figé. Mais malgré tout, les résultats obtenus en l’utilisant étaient assez étonnants. Notez également que la version du paquet en question a été publiée au moment où vous avez posé la question. Elle est donc très récente.

http://blog.fellstat.com/?cat=11

4
maj

J'ai écrit une fonction R appelée addTextLabels() dans un paquetage plotteR. Le paquet peut être directement installé dans votre bibliothèque R en utilisant le code suivant:

install.packages("devtools")
library("devtools")
install_github("JosephCrispell/basicPlotteR")

Pour l'exemple fourni, j'ai utilisé le code suivant pour générer la figure d'exemple liée ci-dessous.

# Load the plotteR library
library(plotteR)

# Create vectors storing the X and Y coordinates
x = c(0.8846, 1.1554, 0.9317, 0.9703, 0.9053, 0.9454, 1.0146, 0.9012, 
      0.9055, 1.3307)
y = c(0.9828, 1.0329, 0.931, 1.3794, 0.9273, 0.9605, 1.0259, 0.9542, 
      0.9717, 0.9357)

# Store the labels to be plotted in a vector
ShortSci = c("MotAlb", "PruMod", "EriRub", "LusMeg", "PhoOch", "PhoPho", 
             "SaxRub", "TurMer", "TurPil", "TurPhi")

# Plot the X and Y coordinates without labels
plot(x, y, asp=1)
abline(h = 1, col = "green")
abline(v = 1, col = "green")

# Add non-overlapping text labels
addTextLabels(x, y, ShortSci, cex=0.9, col.background=rgb(0,0,0, 0.75), 
              col.label="white")

Cela fonctionne en sélectionnant automatiquement un emplacement alternatif à partir d'une grille fine de points. Les points les plus proches de la grille sont d'abord visités et sélectionnés s'ils ne se chevauchent pas avec des points tracés ou des étiquettes. Regardez la source code , si cela vous intéresse.

Example Figure

3
Joseph Crispell

Pas une réponse, mais trop longue pour un commentaire. Une approche très simple qui peut fonctionner sur des cas simples, quelque part entre le post-traitement de joran et les algorithmes plus sophistiqués qui ont été présentés consiste à effectuer in-place De simples transformations dans le cadre de données.

J'illustre ceci avec ggplot2 Parce que je suis plus familier avec cette syntaxe que les graphes de base R.

df <- data.frame(x = x, y = y, z = ShortSci)
library("ggplot2")
ggplot(data = df, aes(x = x, y = y, label = z)) + theme_bw() + 
    geom_point(shape = 1, colour = "green", size = 5) + 
    geom_text(data = within(df, c(y <- y+.01, x <- x-.01)), hjust = 0, vjust = 0)

Comme vous pouvez le constater, dans ce cas, le résultat n'est pas idéal, mais il peut suffire à certaines fins. Et c'est assez facile, typiquement quelque chose comme ça suffit within(df, y <- y+.01)

enter image description here

2
PatrickT