Penempatan label poin cerdas di R

102

1) Apakah ada library / fungsi R yang akan menerapkan penempatan label CERDAS pada plot R? Saya mencoba beberapa tetapi semuanya bermasalah - banyak label yang tumpang tindih satu sama lain atau titik lain (atau objek lain dalam plot, tetapi saya melihat bahwa ini jauh lebih sulit untuk ditangani).

2) Jika tidak, adakah cara untuk dengan NYAMAN membantu algoritme dengan penempatan label untuk poin bermasalah tertentu? Solusi paling nyaman dan efisien yang diinginkan.

Anda dapat bermain dan menguji kemungkinan lain dengan contoh saya yang dapat direproduksi dan melihat apakah Anda dapat mencapai hasil yang lebih baik daripada yang saya miliki:

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

Untuk pelabelan, saya kemudian mencoba kemungkinan ini, tidak ada yang benar-benar bagus:

1) yang ini mengerikan:

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

2) yang ini bagus jika Anda tidak ingin menempatkan label untuk semua titik, tetapi hanya untuk pencilan, tetapi tetap saja, label sering salah ditempatkan:

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

3) yang satu ini tampak menjanjikan tetapi ada masalah label yang terlalu dekat dengan poin; Saya harus memberi mereka spasi tetapi ini tidak banyak membantu:

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)

Terima kasih sebelumnya!

EDIT: todo: coba labcurve {Hmisc} .

TMS
sumber
2
Sayangnya, jawaban atas pertanyaan R tampaknya terbagi rata antara StackOverflow dan CrossValidated. Dalam hal ini, pertanyaannya adalah duplikat dari pertanyaan dari 4 hari yang lalu di sana .
Ed Staub
3
Saya mengalami masalah serupa dan menulis paket dasar yang menggunakan simulasi medan gaya untuk menyesuaikan lokasi objek. Meskipun banyak peningkatan yang mungkin dilakukan, termasuk integrasi dengan ggplot, dll., Tampaknya tugas tersebut dapat diselesaikan. Berikut ini ilustrasi fungsinya. Jika seseorang mengalami masalah dan mencari jawabannya, mudah-mudahan ini bisa membantu:install.packages("FField") library(FField) FFieldPtRepDemo()
gregk
Bolehkah saya meminta Anda untuk mencoba ggrepel ?
Kamil Slowikowski
@Joran sayang, tolong beri komentar "6) Untuk grafik ggplot2, ada opsi baru yang disebut ggrepel yang sepertinya disukai banyak orang." dalam komentar atau jawaban. Di sini saya hanya menyertakan daftar opsi yang saya coba tetapi tidak memuaskan . Jika itu adalah sesuatu yang bekerja dengan baik maka itu harus menjadi jawaban.
TMS

Jawaban:

49

Pertama, inilah hasil solusi saya untuk masalah ini:

masukkan deskripsi gambar di sini

Saya melakukan ini dengan tangan di Pratinjau (penampil PDF / gambar yang sangat dasar di OS X) hanya dalam beberapa menit. ( Sunting: Alur kerja persis seperti yang Anda harapkan: Saya menyimpan plot sebagai PDF dari R, membukanya di Pratinjau dan membuat kotak teks dengan label yang diinginkan (Helvetica 9pt) dan kemudian menyeretnya dengan mouse saya sampai mereka terlihat bagus. Kemudian saya mengekspor ke PNG untuk diunggah ke SO.)

Sekarang, sebelum Anda menyerah pada dorongan kuat untuk tidak memberikan suara ini sehingga terlupakan dan meninggalkan komentar tajam tentang bagaimana intinya adalah mengotomatiskan proses ini, dengarkan saya!

Mencari solusi algoritmik baik-baik saja, dan (IMHO) sangat menarik. Namun, bagi saya, situasi pelabelan titik secara kasar terbagi menjadi tiga kategori:

  1. Anda memiliki sejumlah kecil poin, tidak ada yang terlalu berdekatan . Dalam hal ini, salah satu solusi yang Anda cantumkan dalam pertanyaan kemungkinan akan berfungsi dengan penyesuaian yang cukup minimal.
  2. Anda memiliki sejumlah kecil poin, beberapa di antaranya terlalu padat untuk solusi algoritmik tipikal untuk memberikan hasil yang baik . Dalam hal ini, karena Anda hanya memiliki sejumlah kecil poin, label mereka dengan tangan (baik dengan editor gambar atau fine-tuning panggilan Anda untuk text) tidak bahwa banyak usaha.
  3. Anda memiliki jumlah poin yang cukup besar . Dalam hal ini, Anda sebaiknya tidak memberi label pada mereka, karena sulit untuk memproses label dalam jumlah besar secara visual.

: naik ke kotak sabun:

Karena orang-orang seperti kita menyukai otomatisasi, saya pikir kita sering jatuh ke dalam perangkap pemikiran bahwa hampir setiap aspek menghasilkan grafik statistik yang baik harus diotomatiskan. Saya dengan hormat (dengan rendah hati!) Tidak setuju.

Tidak ada lingkungan plotting statistik umum yang sempurna yang secara otomatis menciptakan gambaran yang Anda miliki di kepala Anda. Hal-hal seperti R, ggplot2, lattice, dll. Melakukan sebagian besar pekerjaan; tetapi sedikit penyesuaian ekstra itu, menambahkan garis di sini, menyesuaikan margin di sana, mungkin lebih cocok untuk alat yang berbeda.

: turun dari kotak sabun:

Saya juga akan mencatat bahwa saya pikir kita semua bisa menghasilkan sebar dengan <10-15 poin yang hampir tidak mungkin untuk diberi label dengan rapi, bahkan dengan tangan, dan ini kemungkinan akan merusak solusi otomatis yang dibuat seseorang.

Akhirnya, saya ingin menegaskan kembali bahwa saya tahu ini bukan jawaban yang Anda cari. Dan saya tidak mengatakan bahwa upaya algoritmik tidak berguna atau bodoh. Saya memilih pertanyaan ini, dan dengan senang hati akan memberikan suara positif untuk solusi algoritmik yang menarik!

Alasan saya memposting jawaban ini adalah bahwa saya pikir pertanyaan ini seharusnya menjadi pertanyaan kanonik "pelabelan titik dalam R" untuk duplikat di masa mendatang, dan saya pikir solusi yang melibatkan pelabelan tangan layak mendapat tempat di meja, itu saja.

joran
sumber
10
Cara manual lainnya adalah dengan menyimpan plot sebagai SVG dan mengeditnya menggunakan Inkscape, lalu menghasilkan PDF dari situ.
Spacedman
Hai joran, terima kasih atas jawabannya. Oke, saya menerima solusi ini, meskipun menurut saya komputer harus melakukan yang terbaik terlebih dahulu DAN KEMUDIAN meminta intervensi manual. Di sini saya mencari solusi paling nyaman dan cepat. Bisakah Anda menjelaskan bagaimana Anda membuat plot, selangkah demi selangkah? Apa yang Anda hasilkan di R, ekspor, pindahkan label di Pratinjau, dll.?
TMS
1
@TomasT. Oh begitu. Kalau begitu aku "curang", semacam. Saya membuat satu pdf dengan label menggunakan salah satu metode Anda di atas dan satu tanpa dan menggunakan yang berlabel sebagai panduan.
joran
1
+1 Ini jawaban yang bagus. Beberapa penjelasan mengapa muncul di meta-CV : lihat komentar di sana.
whuber
1
Memindahkan sekumpulan kecil label dengan tangan tampaknya masuk akal, tetapi Anda juga dapat membuatnya secara otomatis terlebih dahulu , lalu memindahkannya. Dengan begitu Anda menghemat banyak pekerjaan, dan juga mengurangi kemungkinan salah pelabelan ...
n nothing101
42

ggrepelterlihat menjanjikan saat diterapkan ke ggplot2sebar.

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

masukkan deskripsi gambar di sini

Sandy Muspratt
sumber
10

Sudahkah Anda mencoba paket directlabels ?

Dan, BTW, argumen pos dan offset dapat menggunakan vektor untuk memungkinkan Anda menempatkannya di posisi yang tepat saat ada sejumlah titik yang wajar hanya dalam beberapa alur plot.

John
sumber
Bisakah paket directlabels digunakan dengan plot()plot normal ? Saya tidak berhasil mencoba jadi ... Terima kasih! PS: @SpacedMan & Ben, saya membersihkan komentar saya tentang pembaruan R, karena mereka tidak terlalu menarik - Anda dapat melakukan hal yang sama.
TMS
6

Saya menemukan solusi! Sayangnya, ini bukan yang utama dan ideal, tetapi yang terbaik untuk saya sekarang. Ini setengah algoritmik, setengah manual, jadi menghemat waktu dibandingkan dengan solusi manual murni yang dibuat oleh joran.

Saya mengabaikan bagian yang sangat penting dari ?identifybantuan!

Algoritma yang digunakan untuk menempatkan label sama dengan yang digunakan oleh teks jika pos ditentukan di sana, perbedaannya adalah bahwa posisi penunjuk relatif titik yang diidentifikasi menentukan pos dalam identifikasi.

Jadi, jika Anda menggunakan identify()solusi seperti yang saya tulis di pertanyaan saya, maka Anda dapat memengaruhi posisi label dengan tidak mengklik langsung pada titik itu, tetapi dengan mengklik di sebelah titik tersebut secara relatif ke arah yang diinginkan !!! Bekerja dengan sangat baik!

Kelemahannya adalah hanya ada 4 posisi (atas, kiri, bawah, kanan), tetapi saya lebih menghargai 4 lainnya (kiri atas, kanan atas, kiri bawah, kanan bawah) ... Jadi saya gunakan ini untuk menandai titik-titik yang tidak mengganggu saya dan titik-titik lainnya yang saya beri label langsung dalam presentasi Powerpoint saya, seperti yang diusulkan joran :-)

PS: Saya belum mencoba solusi directlabels lattice / ggplot, saya masih lebih suka menggunakan pustaka plot dasar.

TMS
sumber
4

Saya sarankan Anda melihat wordcloudpaketnya. Saya tahu paket ini tidak hanya berfokus pada poin tetapi pada label itu sendiri, dan juga gayanya tampaknya agak diperbaiki. Tapi tetap saja, hasil yang saya dapat dari menggunakannya cukup menakjubkan. Perhatikan juga bahwa versi paket yang dimaksud dirilis pada saat Anda mengajukan pertanyaan, jadi ini masih sangat baru.

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

maj
sumber
3

Saya telah menulis fungsi R yang dipanggil addTextLabels()dalam sebuah paket plotteR. Paket dapat langsung diinstal ke pustaka R Anda menggunakan kode berikut:

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

Untuk contoh yang diberikan, saya menggunakan kode berikut untuk menghasilkan gambar contoh yang ditautkan di bawah ini.

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

Ia bekerja dengan secara otomatis memilih lokasi alternatif dari titik-titik grid yang bagus. Titik terdekat pada kisi dikunjungi terlebih dahulu dan dipilih jika tidak tumpang tindih dengan titik atau label yang diplot. Lihatlah kode sumbernya , jika Anda tertarik.

Contoh Gambar

Joseph Crispell
sumber
2

Bukan jawaban, tapi terlalu panjang untuk berkomentar. Pendekatan yang sangat sederhana yang dapat bekerja pada kasus-kasus sederhana, di antara pasca-pemrosesan joran dan algoritma yang lebih canggih yang telah disajikan adalah membuat in-placetransformasi sederhana ke kerangka data.

Saya mengilustrasikan ini dengan ggplot2karena saya lebih akrab dengan sintaks itu daripada plot dasar 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)

Seperti yang Anda lihat, dalam hal ini hasilnya tidak ideal, tetapi mungkin cukup baik untuk beberapa tujuan. Dan itu cukup mudah, biasanya sesuatu seperti ini sudah cukupwithin(df, y <- y+.01)

masukkan deskripsi gambar di sini

PatrickT
sumber
2
Daripada memodifikasi dfpenggunaan within, saya sering melakukan ini dengan menyesuaikan estetika: geom_text(aes(x = x - .01, y = y + .01), hjust = 0, vjust = 0)terkesan lebih bersih.
Gregor Thomas