Posizionamento intelligente dell'etichetta del punto in R


102

1) Esiste una libreria / funzione R che implementa il posizionamento INTELLIGENTE dell'etichetta nel grafico R? Ne ho provate alcune ma sono tutte problematiche: molte etichette si sovrappongono tra loro o su altri punti (o altri oggetti nella trama, ma vedo che questo è molto più difficile da gestire).

2) In caso negativo, c'è un modo per aiutare COMODAMENTE l'algoritmo con il posizionamento dell'etichetta per punti problematici particolari? Si cerca la soluzione più comoda ed efficiente.

Puoi giocare e testare altre possibilità con il mio esempio riproducibile e vedere se sei in grado di ottenere risultati migliori di quelli che ho io:

# 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")

Per l'etichettatura ho quindi provato queste possibilità, nessuno è veramente bravo:

1) questo è terribile:

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

2) questo è buono se non vuoi posizionare etichette per tutti i punti, ma solo per i valori anomali, ma comunque, le etichette sono spesso posizionate in modo sbagliato:

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

3) questo sembrava promettente ma c'è il problema che le etichette siano troppo vicine ai punti; Ho dovuto riempirli di spazi ma questo non aiuta molto:

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)

Grazie in anticipo!

EDIT: todo: prova labcurve {Hmisc} .


2
Le risposte alle domande R sembrano, sfortunatamente, essere equamente suddivise tra StackOverflow e CrossValidated. In questo caso, la domanda è un duplicato di quella di 4 giorni fa laggiù .
Ed Staub

3
Mi sono imbattuto in un problema simile e ho scritto un pacchetto di base che utilizza la simulazione del campo di forza per regolare la posizione degli oggetti. Sebbene siano possibili molti miglioramenti, inclusa l'integrazione con ggplot, ecc., Sembra che il compito venga portato a termine. Di seguito viene illustrata la funzionalità. Se qualcuno si imbatte nel problema e cerca una risposta, si spera che questo possa essere di aiuto:install.packages("FField") library(FField) FFieldPtRepDemo()
gregk

Potrei chiederti di provare ggrepel ?
Kamil Slowikowski

cara @Joran, per favore metti il ​​tuo commento "6) Per i grafici ggplot2, c'è un'opzione nuova chiamata ggrepel che molte persone sembrano apprezzare." in un commento o una risposta. Qui ho incluso solo l'elenco delle opzioni che ho provato ma non sono soddisfacenti . Se è qualcosa che funziona bene, dovrebbe essere in una risposta.
TMS

Risposte:


49

Innanzitutto, ecco i risultati della mia soluzione a questo problema:

inserisci qui la descrizione dell'immagine

L'ho fatto a mano in Anteprima (visualizzatore di PDF / immagini molto semplice su OS X) in pochi minuti. ( Modifica: il flusso di lavoro era esattamente quello che ti aspetteresti: ho salvato la trama come PDF da R, l'ho aperta in Anteprima e ho creato caselle di testo con le etichette desiderate (9pt Helvetica) e poi le ho trascinate con il mouse finché non sembravano bene. Quindi ho esportato in un PNG per il caricamento in SO.)

Ora, prima di soccombere al forte impulso di votare questo fino all'oblio e lasciare commenti sarcastici su come il punto è automatizzare questo processo, ascoltami!

Cercare soluzioni algoritmiche va benissimo e (IMHO) davvero interessante. Ma, per me, le situazioni di etichettatura dei punti rientrano in circa tre categorie:

  1. Hai un piccolo numero di punti, nessuno molto ravvicinato . In questo caso, è probabile che una delle soluzioni che hai elencato nella domanda funzioni con un ritocco minimo.
  2. Hai un piccolo numero di punti, alcuni dei quali sono troppo ravvicinati perché le soluzioni algoritmiche tipiche diano buoni risultati . In questo caso, dal momento che hai solo un piccolo numero di punti, etichettandoli a mano (o con un editor di immagini o di messa a punto la chiamata a text) non è che molto sforzo.
  3. Hai un numero abbastanza elevato di punti . In questo caso, non dovresti comunque etichettarle, poiché è difficile elaborare visivamente un gran numero di etichette.

: salire sulla soapbox:

Poiché le persone come noi amano l' automazione, penso che spesso cadiamo nella trappola di pensare che quasi ogni aspetto della produzione di un buon grafico statistico debba essere automatizzato. Rispettosamente (umilmente!) Non sono d'accordo.

Non esiste un ambiente di plottaggio statistico perfettamente generale che crei automagicamente l'immagine che hai nella tua testa. Cose come R, ggplot2, lattice ecc. Fanno la maggior parte del lavoro; ma quel pizzico in più di aggiustamento, l'aggiunta di una linea qui, la regolazione di un margine lì, è probabilmente più adatto a uno strumento diverso.

: scendendo dalla soapbox:

Vorrei anche notare che penso che potremmo tutti trovare grafici a dispersione con <10-15 punti che sarà quasi impossibile etichettare in modo pulito, anche a mano, e questi probabilmente interromperanno qualsiasi soluzione automatica che qualcuno troverà.

Infine, voglio ribadire che so che questa non è la risposta che stai cercando. E sto non dicendo che i tentativi algoritmici sono inutili o stupido. Ho votato positivamente questa domanda e sarò felice di votare soluzioni algoritmiche interessanti!

Il motivo per cui ho pubblicato questa risposta è che penso che questa domanda dovrebbe essere la canonica domanda "etichettatura punto in R" per futuri duplicati, e penso che le soluzioni che coinvolgono l'etichettatura manuale meritino un posto al tavolo, tutto qui.


10
Un altro modo manuale è salvare la trama come SVG e modificarla usando Inkscape, quindi produrre PDF da quello.
Spacedman

Ciao joran, grazie per la tua risposta. OK, accetto questa soluzione, anche se penso che il computer dovrebbe farlo meglio prima E POI richiedere un intervento manuale. Qui sto cercando la soluzione più comoda e veloce. Potresti descrivere passo dopo passo come hai realizzato la trama? Cosa hai generato in R, esportato, spostato le etichette in Anteprima, ecc.?
TMS

1
@TomasT. Oh, capisco. In quel caso ho "barato", più o meno. Ho generato un pdf con le etichette usando uno dei tuoi metodi sopra e uno senza e ho usato quello con le etichette come guida.
joran

1
+1 Questa è un'ottima risposta. Qualche spiegazione del perché appare sul meta-CV : vedi i commenti lì.
whuber

1
Spostare a mano un piccolo set di etichette sembra sensato, ma puoi anche crearle prima automaticamente e poi spostarle. In questo modo ti risparmi un sacco di lavoro e
riduci

42

ggrepelsembra promettente se applicato a ggplot2grafici a dispersione.

# 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)

inserisci qui la descrizione dell'immagine


10

Hai provato il pacchetto directlabels ?

E, a proposito, gli argomenti pos e offset possono prendere vettori per consentirti di portarli nelle posizioni giuste quando c'è un numero ragionevole di punti in poche sequenze di grafico.


Il pacchetto directlabels può essere utilizzato con la plot()trama normale ? Non ho avuto successo nel provare quindi ... Grazie! PS: @SpacedMan e Ben, ho ripulito i miei commenti sull'aggiornamento R, poiché non sono molto interessanti - puoi fare lo stesso.
TMS

6

Ho trovato una soluzione! Sfortunatamente non è definitivo e ideale, ma è quello che funziona meglio per me ora. È per metà algoritmico e per metà manuale, quindi consente di risparmiare tempo rispetto alla pura soluzione manuale delineata da joran.

Ho trascurato una parte molto importante ?identifydell'aiuto!

L'algoritmo utilizzato per posizionare le etichette è lo stesso utilizzato dal testo se è specificato pos, con la differenza che la posizione del puntatore rispetto al punto identificato determina pos in identificazione.

Quindi se usi la identify()soluzione come ho scritto nella mia domanda, allora puoi influenzare la posizione dell'etichetta non cliccando direttamente su quel punto, ma cliccando accanto a quel punto relativamente nella direzione desiderata !!! Funziona alla grande!

Lo svantaggio è che ci sono solo 4 posizioni (in alto, a sinistra, in basso, a destra), ma apprezzerei di più le altre 4 (in alto a sinistra, in alto a destra, in basso a sinistra, in basso a destra) ... Quindi io usalo per etichettare i punti in cui non mi dà fastidio e il resto dei punti etichetto direttamente nella mia presentazione Powerpoint, come ha proposto joran :-)

PS: non ho ancora provato la soluzione directlabels lattice / ggplot, preferisco comunque usare la libreria di base della trama.


4

Ti suggerisco di dare un'occhiata alla wordcloudconfezione. So che questo pacchetto non si concentra esattamente sui punti ma sulle etichette stesse, e anche lo stile sembra essere piuttosto fisso. Tuttavia, i risultati che ho ottenuto dall'uso sono stati piuttosto sorprendenti. Tieni inoltre presente che la versione del pacchetto in questione è stata rilasciata all'incirca nel momento in cui hai posto la domanda, quindi è ancora molto nuova.

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


3

Ho scritto una funzione R chiamata addTextLabels()all'interno di un pacchetto plotteR. Il pacchetto può essere installato direttamente nella libreria R utilizzando il codice seguente:

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

Per l'esempio fornito, ho utilizzato il codice seguente per generare la figura di esempio collegata di seguito.

# 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")

Funziona selezionando automaticamente una posizione alternativa da una sottile griglia di punti. I punti più vicini sulla griglia vengono visitati per primi e selezionati se non si sovrappongono a punti o etichette tracciati. Dai un'occhiata al codice sorgente , se sei interessato.

Figura di esempio


2

Non una risposta, ma troppo lunga per un commento. Un approccio molto semplice che può funzionare su casi semplici, da qualche parte tra la post-elaborazione di joran e gli algoritmi più sofisticati che sono stati presentati è quello di apportare in-placesemplici trasformazioni al dataframe.

Lo illustro ggplot2perché ho più familiarità con quella sintassi rispetto ai grafici R di base.

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)

Come puoi vedere, in questo caso il risultato non è ideale, ma può essere abbastanza buono per alcuni scopi. Ed è abbastanza semplice, in genere qualcosa del genere è sufficientewithin(df, y <- y+.01)

inserisci qui la descrizione dell'immagine


2
Piuttosto che modificare l' dfutilizzo within, lo faccio spesso aggiustando l'estetica: geom_text(aes(x = x - .01, y = y + .01), hjust = 0, vjust = 0)sembra più pulito.
Gregor Thomas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.