Plot legenda di luar area plot di grafis dasar?


185

Seperti judulnya: Bagaimana saya bisa membuat plot legenda di luar area plot ketika menggunakan grafis dasar?

Saya berpikir tentang mengutak-atik layoutdan menghasilkan plot kosong hanya berisi legenda, tapi saya akan tertarik dengan cara hanya menggunakan fasilitas grafik dasar dan misalnya, par(mar = )untuk mendapatkan ruang di sebelah kanan plot untuk legenda.


Berikut sebuah contoh:

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")
legend(1,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

menghasilkan:

teks alternatif

Tetapi seperti yang saya katakan, saya ingin legenda berada di luar area plot (misalnya, di sebelah kanan grafik / plot).


... Anda juga dapat meretas par dengan wadah boneka untuk legenda, mudah dan cukup nyaman dari waktu ke waktu. Pertanyaan serupa di sini .
hhh

3
@hhh Tautan tidak berfungsi lagi. Bisakah Anda memperbaruinya atau mengirim jawaban menggunakan pendekatan ini?
Henrik

Jawaban:


111

Mungkin yang Anda butuhkan adalah par(xpd=TRUE)untuk memungkinkan hal-hal yang dapat ditarik di luar wilayah plot. Jadi jika Anda melakukan plot utama dengan bty='L'Anda akan memiliki ruang di sebelah kanan untuk legenda. Biasanya ini akan terpotong ke wilayah plot, tetapi lakukan par(xpd=TRUE)dan dengan sedikit penyesuaian Anda bisa mendapatkan legenda sejauh mungkin:

 set.seed(1) # just to get the same random numbers
 par(xpd=FALSE) # this is usually the default

 plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2), bty='L')
 # this legend gets clipped:
 legend(2.8,0,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

 # so turn off clipping:
 par(xpd=TRUE)
 legend(2.8,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

33
Perhatikan bahwa Anda dapat meneruskan xpd langsung ke legenda sehingga Anda tidak perlu khawatir tentang menyetel ulang par setelahnya. Lihat juga grconvertX & Y untuk cara menentukan lokasi legenda dengan cara yang tidak bergantung pada batas data yang Anda rencanakan.
Charles

6
karena pertanyaan dan jawaban ini masih sangat populer, par(xpd=NA)bahkan lebih kuat (yaitu, plot ke lebih banyak wilayah).
Henrik

+1. Kita harus menyebutkan bahwa masuk akal untuk memiliki parpanggilan terpisah tepat sebelum legenda. Dalam plot saya, saya menggunakan par(new=T)beberapa kesempatan lain dan hanya ingin menambahkan xpdparam dalam panggilan yang sama, yang menyebabkan masalah.
Matt Bannert

146

Tidak ada yang disebutkan menggunakan insetnilai negatif untuk legend. Berikut adalah contoh, di mana legenda berada di sebelah kanan plot, selaras ke atas (menggunakan kata kunci "topright").

# Random data to plot:
A <- data.frame(x=rnorm(100, 20, 2), y=rnorm(100, 20, 2))
B <- data.frame(x=rnorm(100, 21, 1), y=rnorm(100, 21, 1))

# Add extra space to right of plot area; change clipping to figure
par(mar=c(5.1, 4.1, 4.1, 8.1), xpd=TRUE)

# Plot both groups
plot(y ~ x, A, ylim=range(c(A$y, B$y)), xlim=range(c(A$x, B$x)), pch=1,
               main="Scatter plot of two groups")
points(y ~ x, B, pch=3)

# Add legend to top right, outside plot region
legend("topright", inset=c(-0.2,0), legend=c("A","B"), pch=c(1,3), title="Group")

Nilai pertama inset=c(-0.2,0)mungkin perlu disesuaikan berdasarkan lebar legenda.

legend_right


14
@ Henrik tidak itu tidak akan berfungsi tanpa xpd = BENAR. Perhatikan juga bahwa lebih baik mengatur xpd = TRUE sebagai argumen dari fungsi legend ().
Stéphane Laurent

1
Terkadang xpdharus diatur agar TRUEinset negatif berfungsi. Namun terkadang tidak. Dengan perintah di args.legend=list(x="bottom", horiz=TRUE, inset=-0.2)dalam sebuah barplot(...sepertinya tidak perlu xpd=TRUEtetapi hanya dengan legend(x="bottom", horiz=TRUE, inset=-0.2)itu sepertinya perlu xpd=TRUE. Ada wawasan? Saya hanya bingung menyampaikan argumen saya?
user3386170

28

Solusi lain, selain ondes yang telah disebutkan (menggunakan layoutataupar(xpd=TRUE) ) adalah untuk overlay plot Anda dengan plot transparan di seluruh perangkat dan kemudian tambahkan legenda itu.

Caranya adalah dengan overlay grafik (kosong) di atas area plot yang lengkap dan menambahkan legenda itu. Kita bisa menggunakan par(fig=...)opsi. Pertama kami menginstruksikan R untuk membuat plot baru di seluruh perangkat plot:

par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), mar=c(0, 0, 0, 0), new=TRUE)

Pengaturan omadan mardiperlukan karena kami ingin memiliki bagian dalam plot mencakup seluruh perangkat. new=TRUEdiperlukan untuk mencegah R memulai perangkat baru. Kami kemudian dapat menambahkan plot kosong:

plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n')

Dan kami siap menambahkan legenda:

legend("bottomright", ...)

akan menambahkan legenda ke kanan bawah perangkat. Demikian juga, kita dapat menambahkan legenda ke margin atas atau kanan. Satu-satunya hal yang perlu kita pastikan adalah bahwa margin plot asli cukup besar untuk mengakomodasi legenda tersebut.

Menempatkan semua ini dalam suatu fungsi;

add_legend <- function(...) {
  opar <- par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), 
    mar=c(0, 0, 0, 0), new=TRUE)
  on.exit(par(opar))
  plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n')
  legend(...)
}

Dan sebuah contoh. Pertama buat plot, pastikan kita memiliki cukup ruang di bagian bawah untuk menambahkan legenda:

par(mar = c(5, 4, 1.4, 0.2))
plot(rnorm(50), rnorm(50), col=c("steelblue", "indianred"), pch=20)

Lalu tambahkan legenda

add_legend("topright", legend=c("Foo", "Bar"), pch=20, 
   col=c("steelblue", "indianred"),
   horiz=TRUE, bty='n', cex=0.8)

Yang menghasilkan:

Figur contoh ditampilkan legenda di margin atas


2
Tambahan yang bagus untuk daftar di sini. Ada penjelasan tentang cara membuat ini bekerja dengan banyak plot dalam grafik di sini .
shiri

Jan, apakah ada cara untuk meningkatkan ukuran font dalam legenda, tanpa ada teks yang terpotong? Sebagai contoh, saya memiliki grafik 4 jenis label berbeda, tetapi dengan banyak ruang kosong di antara mereka.
Seorang pria tua di laut.

Saya telah menulis pertanyaan dengan lebih detail stackoverflow.com/questions/42707308/…
Seorang lelaki tua di laut.

16

Maaf karena menghidupkan kembali utas lama, tetapi saya memiliki masalah yang sama hari ini. Cara paling sederhana yang saya temukan adalah sebagai berikut:

# Expand right side of clipping rect to make room for the legend
par(xpd=T, mar=par()$mar+c(0,0,0,6))

# Plot graph normally
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

# Plot legend where you want
legend(3.2,1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

# Restore default clipping rect
par(mar=c(5, 4, 4, 2) + 0.1)

Ditemukan di sini: http://www.harding.edu/fmccown/R/


4
Yang lebih baik adalah oldpar <- par (xpd = T, mar = par () $ mar + c (0,0,0,6)) ... par (oldpar) (Lihat bantuan par)
rakensi

Solusi ini lebih baik karena ruang untuk legenda diperbaiki tidak peduli panjang string legenda
Sergio

15

Saya suka melakukannya seperti ini:

par(oma=c(0, 0, 0, 5))
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch=2, lty=2, type="o")
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA,
       c("group A", "group B"), pch=c(1, 2), lty=c(1,2))

masukkan deskripsi gambar di sini

Satu-satunya penyesuaian yang diperlukan adalah dalam menetapkan margin yang tepat agar cukup lebar untuk mengakomodasi legenda.

Namun, ini juga bisa otomatis:

dev.off() # to reset the graphics pars to defaults
par(mar=c(par('mar')[1:3], 0)) # optional, removes extraneous right inner margin space
plot.new()
l <- legend(0, 0, bty='n', c("group A", "group B"), 
            plot=FALSE, pch=c(1, 2), lty=c(1, 2))
# calculate right margin width in ndc
w <- grconvertX(l$rect$w, to='ndc') - grconvertX(0, to='ndc')
par(omd=c(0, 1-w, 0, 1))
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2, 2))
lines(1:3, rnorm(3), pch=2, lty=2, type="o")
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA,
       c("group A", "group B"), pch=c(1, 2), lty=c(1, 2))

masukkan deskripsi gambar di sini


Menggunakan xpd = T atau xpd = NA tidak mencegah 'main' (judul) saya terpotong ketika ditarik untuk mencoba menggunakan area yang ditambahkan dengan margin kanan lebar.
Phil Goetz

@ PhilGoetz apakah Anda yakin sedang merencanakan main di area plot? Apakah mungkin Anda tidak memiliki cukup garis margin di sana untuk digarap?
jbaums

10

Baru-baru ini saya menemukan fungsi yang sangat mudah dan menarik untuk mencetak legenda di luar area plot di mana Anda inginkan.

Buat margin luar di sisi kanan plot.

par(xpd=T, mar=par()$mar+c(0,0,0,5))

Buat plot

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

Tambahkan legenda dan cukup gunakan fungsi locator (1) seperti di bawah ini. Maka Anda harus mengklik di tempat yang Anda inginkan setelah memuat skrip berikut.

legend(locator(1),c("group A", "group B"), pch = c(1,2), lty = c(1,2))

Cobalah


9

Saya hanya bisa menawarkan contoh solusi tata letak yang sudah ditunjukkan.

layout(matrix(c(1,2), nrow = 1), widths = c(0.7, 0.3))
par(mar = c(5, 4, 4, 2) + 0.1)
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")
par(mar = c(5, 0, 4, 2) + 0.1)
plot(1:3, rnorm(3), pch = 1, lty = 1, ylim=c(-2,2), type = "n", axes = FALSE, ann = FALSE)
legend(1, 1, c("group A", "group B"), pch = c(1,2), lty = c(1,2))

gambar yang jelek: S


9

Menambahkan alternatif sederhana lain yang menurut saya cukup elegan.

Plot Anda:

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

Legenda:

legend("bottomright", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(0,1), xpd=TRUE, horiz=TRUE, bty="n"
       )

Hasil:

berfoto dengan legenda

Di sini hanya baris kedua legenda yang ditambahkan ke contoh Anda. Gantinya:

  • inset=c(0,1)- Memindahkan legenda dengan sebagian kecil dari wilayah plot ke arah (x, y). Dalam hal ini legenda ada di"bottomright" posisi. Itu dipindahkan oleh 0 wilayah plot di arah x (jadi tetap di "kanan") dan oleh 1 wilayah plot di arah y (dari bawah ke atas). Dan kebetulan itu muncul tepat di atas plot.
  • xpd=TRUE - Mari legenda muncul di luar wilayah merencanakan.
  • horiz=TRUE - menginstruksikan untuk menghasilkan legenda horisontal.
  • bty="n" - detail gaya untuk menyingkirkan kotak pembatas legenda.

Hal yang sama berlaku ketika menambahkan legenda ke samping:

par(mar=c(5,4,2,6))
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

legend("topleft", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(1,0), xpd=TRUE, bty="n"
       )

Di sini kita cukup menyesuaikan posisi legenda dan menambahkan ruang margin tambahan ke sisi kanan plot. Hasil:

gambar dengan legenda 2


4

Anda bisa melakukan ini dengan Plotly R API , dengan salah satu kode, atau dari GUI dengan menyeret legenda ke tempat yang Anda inginkan.

Berikut ini sebuah contoh. Grafik dan kode juga ada di sini .

x = c(0,1,2,3,4,5,6,7,8) 
y = c(0,3,6,4,5,2,3,5,4) 
x2 = c(0,1,2,3,4,5,6,7,8) 
y2 = c(0,4,7,8,3,6,3,3,4)

Anda dapat memposisikan legenda di luar grafik dengan menetapkan salah satu dari nilai x dan y ke 100 atau -100.

legendstyle = list("x"=100, "y"=1)
layoutstyle = list(legend=legendstyle)

Berikut adalah opsi lainnya:

  • list("x" = 100, "y" = 0) untuk Bagian Luar Kanan Bawah
  • list("x" = 100, "y"= 1) Luar Kanan Atas
  • list("x" = 100, "y" = .5) Luar Kanan Tengah
  • list("x" = 0, "y" = -100) Di bawah Kiri
  • list("x" = 0.5, "y" = -100) Di bawah Center
  • list("x" = 1, "y" = -100) Di bawah Kanan

Lalu responnya.

response = p$plotly(x,y,x2,y2, kwargs=list(layout=layoutstyle));

Plotly mengembalikan URL dengan grafik Anda saat Anda melakukan panggilan. Anda dapat mengaksesnya lebih cepat dengan menelepon browseURL(response$url)sehingga grafik Anda akan terbuka di browser untuk Anda.

url = response$url
filename = response$filename

Itu memberi kita grafik ini. Anda juga dapat memindahkan legenda dari dalam GUI dan kemudian grafik akan berskala sesuai. Pengungkapan penuh: Saya di tim Plotly.

Legenda di sisi grafik


2

Coba layout()yang saya gunakan untuk ini di masa lalu dengan hanya membuat plot kosong di bawah ini, diskalakan dengan benar sekitar 1/4 atau lebih dan menempatkan bagian legenda secara manual di dalamnya.

Ada beberapa pertanyaan lama di sini tentang legend()yang harus Anda mulai.


Seperti yang sudah dikatakan dalam pertanyaan, ini juga yang saya pikirkan. Tapi itu akan ideal, jika ada cara lain. Entah bagaimana saya kira tidak ada.
Henrik
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.