Intelligente Platzierung von Punktetiketten in R.

102

1) Gibt es eine R-Bibliothek / Funktion, die die Platzierung von INTELLIGENT-Labels im R-Plot implementieren würde? Ich habe einige ausprobiert, aber sie sind alle problematisch - viele Beschriftungen überlappen sich entweder oder andere Punkte (oder andere Objekte in der Handlung, aber ich sehe, dass dies viel schwieriger zu handhaben ist).

2) Wenn nicht, gibt es eine Möglichkeit, den Algorithmus bei der Platzierung des Etiketts für bestimmte problematische Punkte KOMFORTABL zu unterstützen? Die bequemste und effizienteste Lösung gesucht.

Sie können mit meinem reproduzierbaren Beispiel andere Möglichkeiten spielen und testen und sehen, ob Sie bessere Ergebnisse erzielen können als ich:

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

Zum Etikettieren habe ich dann diese Möglichkeiten ausprobiert, niemand ist wirklich gut:

1) dieser ist schrecklich:

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

2) Diese ist gut, wenn Sie nicht alle Punkte beschriften möchten, sondern nur die Ausreißer. Trotzdem werden die Beschriftungen häufig falsch platziert:

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

3) dieser sah vielversprechend aus, aber es gibt das Problem, dass Etiketten zu nahe an den Punkten sind; Ich musste sie mit Leerzeichen auffüllen, aber das hilft nicht viel:

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)

Vielen Dank im Voraus!

EDIT: todo: versuche labcurve {Hmisc} .

TMS
quelle
2
Die Antworten auf R-Fragen scheinen leider gleichmäßig zwischen StackOverflow und CrossValidated aufgeteilt zu sein. In diesem Fall handelt es sich bei der Frage um ein Duplikat von vor 4 Tagen .
Ed Staub
3
Ich bin auf ein ähnliches Problem gestoßen und habe ein Basispaket geschrieben, das die Kraftfeldsimulation verwendet, um die Objektposition anzupassen. Obwohl viele Verbesserungen möglich sind, einschließlich der Integration in ggplot usw., scheint die Aufgabe erledigt zu sein. Das Folgende veranschaulicht die Funktionalität. Wenn jemand auf das Problem install.packages("FField") library(FField) FFieldPtRepDemo()
stößt
Könnte ich Sie bitten, ggrepel zu versuchen ?
Kamil Slowikowski
Lieber @Joran, bitte geben Sie Ihren Kommentar ein. "6) Für ggplot2-Diagramme gibt es eine neue Option namens ggrepel, die vielen Leuten zu gefallen scheint." in einem Kommentar oder einer Antwort. Hier habe ich nur die Liste der Optionen aufgenommen, die ich ausprobiert habe, die aber nicht zufriedenstellend sind . Wenn es etwas ist, das gut funktioniert, sollte es in einer Antwort sein.
TMS

Antworten:

49

Hier sind die Ergebnisse meiner Lösung für dieses Problem:

Geben Sie hier die Bildbeschreibung ein

Ich habe dies von Hand in der Vorschau (sehr einfacher PDF / Bild-Viewer unter OS X) in nur wenigen Minuten gemacht. ( Bearbeiten: Der Workflow war genau das, was Sie erwartet hatten: Ich habe das Diagramm als PDF aus R gespeichert, es in der Vorschau geöffnet und Textfelder mit den gewünschten Beschriftungen (9pt Helvetica) erstellt und sie dann einfach mit der Maus herumgezogen, bis sie aussahen gut. Dann habe ich in ein PNG exportiert, um es auf SO hochzuladen.)

Bevor Sie dem starken Drang erliegen, dies in Vergessenheit zu bringen und bissige Kommentare darüber zu hinterlassen, wie es darum geht, diesen Prozess zu automatisieren, hören Sie mich an!

Die Suche nach algorithmischen Lösungen ist völlig in Ordnung und (IMHO) wirklich interessant. Für mich fallen Punktkennzeichnungssituationen in ungefähr drei Kategorien:

  1. Sie haben eine kleine Anzahl von Punkten, keine, die furchtbar nahe beieinander liegen . In diesem Fall funktioniert eine der Lösungen, die Sie in der Frage aufgeführt haben, wahrscheinlich mit relativ geringen Optimierungen.
  2. Sie haben eine kleine Anzahl von Punkten, von denen einige zu dicht gepackt sind, als dass die typischen algorithmischen Lösungen gute Ergebnisse liefern könnten . In diesem Fall, da Sie nur eine kleine Anzahl von Punkten, so dass sie von Hand Kennzeichnung (entweder mit einem Bildbearbeitungsprogramm oder die Feinabstimmung auf Ihren Anruf text) nicht , dass viel Aufwand.
  3. Sie haben eine ziemlich große Anzahl von Punkten . In diesem Fall sollten Sie sie sowieso nicht beschriften, da es schwierig ist, eine große Anzahl von Etiketten visuell zu verarbeiten.

: Klettern auf Seifenkiste:

Da Leute wie wir die Automatisierung lieben , denke ich, dass wir oft in die Falle tappen, dass fast jeder Aspekt der Erstellung einer guten statistischen Grafik automatisiert werden sollte. Ich bin respektvoll (demütig!) Nicht einverstanden.

Es gibt keine vollkommen allgemeine statistische Darstellungsumgebung, die automatisch das Bild erstellt, das Sie in Ihrem Kopf haben. Dinge wie R, ggplot2, Gitter usw. erledigen den größten Teil der Arbeit; Aber dieses zusätzliche kleine Optimieren, hier eine Linie hinzufügen und dort einen Rand anpassen, ist wahrscheinlich besser für ein anderes Werkzeug geeignet.

: von der Seifenkiste herunterklettern:

Ich würde auch bemerken, dass ich denke, wir könnten alle Streudiagramme mit <10-15 Punkten erstellen, die selbst von Hand kaum sauber zu beschriften sind, und diese werden wahrscheinlich jede automatische Lösung zerstören, die jemand entwickelt.

Abschließend möchte ich noch einmal betonen, dass ich weiß, dass dies nicht die Antwort ist, nach der Sie suchen. Und ich sage nicht , dass algorithmische Versuche nutzlos oder dumm sind. Ich habe diese Frage positiv bewertet und werde gerne interessante algorithmische Lösungen bewerten!

Der Grund, warum ich diese Antwort gepostet habe, ist, dass ich denke, dass diese Frage die kanonische Frage "Punktkennzeichnung in R" für zukünftige Duplikate sein sollte, und ich denke, dass Lösungen mit Handkennzeichnung einen Platz am Tisch verdienen, das ist alles.

Joran
quelle
10
Eine andere manuelle Möglichkeit besteht darin, den Plot als SVG zu speichern und mit Inkscape zu bearbeiten und daraus dann PDF zu erstellen.
Spacedman
Hallo Joran, danke für deine Antwort. OK, ich akzeptiere diese Lösung, obwohl ich denke, dass der Computer dies am besten zuerst tun und dann einen manuellen Eingriff anfordern sollte. Hier suche ich nach der bequemsten und schnellsten Lösung. Könnten Sie bitte Schritt für Schritt beschreiben, wie Sie die Handlung gemacht haben? Was haben Sie in R generiert, exportiert, die Beschriftungen in der Vorschau verschoben usw.?
TMS
1
@TomasT. Oh ich verstehe. In diesem Fall habe ich irgendwie "betrogen". Ich habe ein PDF mit Beschriftungen mit einer der oben genannten Methoden und eine ohne erstellt und das mit Beschriftungen als Leitfaden verwendet.
Joran
1
+1 Dies ist eine großartige Antwort. Eine Erklärung, warum dies im Meta-Lebenslauf erscheint : siehe die Kommentare dort.
Whuber
1
Das Verschieben eines kleinen Satzes von Etiketten von Hand erscheint sinnvoll. Sie können sie jedoch auch zuerst automatisch erstellen und dann verschieben. Auf diese Weise sparen Sie sich viel Arbeit und verringern auch die Wahrscheinlichkeit einer falschen Kennzeichnung ...
naught101
42

ggrepelsieht vielversprechend aus, wenn es auf ggplot2Streudiagramme angewendet wird .

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

Geben Sie hier die Bildbeschreibung ein

Sandy Muspratt
quelle
10

Haben Sie das directlabels- Paket ausprobiert ?

Übrigens können die Argumente pos und offset Vektoren verwenden, damit Sie sie an die richtigen Positionen bringen können, wenn in nur wenigen Plotläufen eine angemessene Anzahl von Punkten vorhanden ist.

John
quelle
Kann das directlabels-Paket mit normalem plot()Plot verwendet werden? Ich habe es nicht erfolgreich versucht ... Danke! PS: @SpacedMan & Ben, ich habe meine Kommentare zum R-Update bereinigt, da sie nicht so interessant sind - Sie können das Gleiche tun.
TMS
6

Ich habe eine Lösung gefunden! Es ist leider nicht ultimativ und ideal, aber es ist das, was jetzt am besten für mich funktioniert. Es ist halb algoritmisch, halb manuell, also spart es Zeit im Vergleich zu einer von Joran entworfenen reinen manuellen Lösung.

Ich habe einen sehr wichtigen Teil der Hilfe übersehen !?identify

Der Algorithmus zum Platzieren von Beschriftungen ist der gleiche wie der von Text verwendete, wenn dort pos angegeben ist. Der Unterschied besteht darin, dass die Position des Zeigers relativ zum identifizierten Punkt pos in ident bestimmt.

Wenn Sie also die identify()Lösung verwenden, wie ich sie in meiner Frage geschrieben habe, können Sie die Position des Etiketts beeinflussen, indem Sie nicht direkt auf diesen Punkt klicken , sondern indem Sie relativ in die gewünschte Richtung neben diesen Punkt klicken !!! Funktioniert einfach super!

Der Nachteil ist, dass es nur 4 Positionen gibt (oben, links, unten, rechts), aber ich würde die anderen 4 (oben links, oben rechts, unten links, unten rechts) mehr schätzen ... Also ich Verwenden Sie diese Option, um Punkte zu kennzeichnen, die mich nicht stören, und den Rest der Punkte, die ich direkt in meiner Powerpoint-Präsentation beschrifte, wie von joran vorgeschlagen :-)

PS: Ich habe die Gitter- / ggplot-Lösung von directlabels noch nicht ausprobiert. Ich bevorzuge immer noch die Verwendung der grundlegenden Plotbibliothek.

TMS
quelle
4

Ich würde vorschlagen, dass Sie sich das wordcloudPaket ansehen . Ich weiß, dass sich dieses Paket nicht genau auf die Punkte konzentriert, sondern auf die Etiketten selbst, und auch der Stil scheint ziemlich fest zu sein. Trotzdem waren die Ergebnisse, die ich mit der Verwendung erzielt habe, ziemlich beeindruckend. Beachten Sie auch, dass die betreffende Paketversion zu dem Zeitpunkt veröffentlicht wurde, als Sie die Frage gestellt haben. Sie ist also noch sehr neu.

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

Maj
quelle
3

Ich habe eine R-Funktion geschrieben, die addTextLabels()in einem Paket aufgerufen wird plotteR. Das Paket kann mit dem folgenden Code direkt in Ihre R-Bibliothek installiert werden:

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

Für das bereitgestellte Beispiel habe ich den folgenden Code verwendet, um die unten verlinkte Beispielfigur zu generieren.

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

Es funktioniert, indem automatisch ein alternativer Ort aus einem feinen Punktraster ausgewählt wird. Die nächstgelegenen Punkte im Raster werden zuerst besucht und ausgewählt, wenn sie sich nicht mit gezeichneten Punkten oder Beschriftungen überschneiden. Werfen Sie einen Blick auf die Quelle - Code , wenn Sie interessiert sind.

Beispiel Abbildung

Joseph Crispell
quelle
2

Keine Antwort, aber zu lang für einen Kommentar. Ein sehr einfacher Ansatz, der in einfachen Fällen zwischen der Nachbearbeitung von Joran und den komplexeren Algorithmen, die vorgestellt wurden in-place, funktionieren kann, besteht darin, einfache Transformationen in den Datenrahmen vorzunehmen.

Ich illustriere dies mit, ggplot2weil ich mit dieser Syntax besser vertraut bin als mit Basis-R-Plots.

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)

Wie Sie sehen können, ist das Ergebnis in diesem Fall nicht ideal, aber es kann für einige Zwecke gut genug sein. Und es ist ziemlich mühelos, normalerweise reicht so etwaswithin(df, y <- y+.01)

Geben Sie hier die Bildbeschreibung ein

PatrickT
quelle
2
Anstatt die dfVerwendung zu ändern within, mache ich dies oft, indem ich die Ästhetik anpasse: geom_text(aes(x = x - .01, y = y + .01), hjust = 0, vjust = 0)Scheint sauberer.
Gregor Thomas