Vẽ một huyền thoại bên ngoài khu vực vẽ trong đồ họa cơ sở?


185

Như tiêu đề nói: Làm thế nào tôi có thể vẽ một huyền thoại bên ngoài khu vực âm mưu khi sử dụng đồ họa cơ sở?

Tôi đã nghĩ về việc loay hoay với layoutvà tạo ra một âm mưu trống rỗng chỉ chứa huyền thoại, nhưng tôi sẽ quan tâm đến cách sử dụng chỉ các phương tiện đồ thị cơ sở và ví dụ, par(mar = )để có được một khoảng trống ở bên phải cốt truyện cho huyền thoại.


Dưới đây là một ví dụ:

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

sản xuất:

văn bản thay thế

Nhưng như đã nói, tôi muốn huyền thoại ở bên ngoài khu vực vẽ đồ thị (ví dụ, ở bên phải của biểu đồ / cốt truyện.


... Bạn cũng có thể hack ngang với thùng chứa giả cho huyền thoại, dễ dàng và khá thuận tiện theo thời gian. Câu hỏi tương tự ở đây .
hhh

2
@hhh Liên kết không hoạt động nữa. Bạn có thể cập nhật nó hoặc đăng một câu trả lời bằng cách sử dụng phương pháp này?
Henrik

Câu trả lời:


111

Có lẽ những gì bạn cần là par(xpd=TRUE)cho phép mọi thứ được vẽ bên ngoài khu vực cốt truyện. Vì vậy, nếu bạn làm cốt truyện chính vớibty='L' bạn sẽ có một khoảng trống ở bên phải cho một huyền thoại. Thông thường, điều này sẽ được cắt vào khu vực cốt truyện, nhưng thực hiện par(xpd=TRUE)và với một chút điều chỉnh, bạn có thể có được một huyền thoại càng xa càng tốt:

 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
Lưu ý rằng bạn có thể truyền xpd trực tiếp vào truyền thuyết, do đó bạn không cần phải lo lắng về việc đặt lại mệnh giá sau đó. Đồng thời xem grconvertX & Y để biết cách chỉ định vị trí của chú giải theo cách không phụ thuộc vào giới hạn của dữ liệu bạn đang vẽ.
Charles

6
vì câu hỏi và câu trả lời này vẫn còn rất phổ biến, par(xpd=NA)thậm chí còn mạnh mẽ hơn (nghĩa là âm mưu đến nhiều khu vực hơn).
Henrik

+1. Chúng ta nên đề cập rằng nó có ý nghĩa để có một parcuộc gọi riêng ngay trước truyền thuyết. Trong cốt truyện của tôi, tôi đã sử dụng par(new=T)trong một số dịp khác và chỉ muốn thêm xpdtham số trong cùng một cuộc gọi, điều này gây ra rắc rối.
Matt Bannert

146

Không ai đã đề cập đến việc sử dụng các insetgiá trị âm cho legend. Dưới đây là một ví dụ, trong đó chú giải nằm ở bên phải cốt truyện, được căn chỉnh lên trên cùng (sử dụng từ khóa "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")

Giá trị đầu tiên inset=c(-0.2,0)có thể cần điều chỉnh dựa trên chiều rộng của chú giải.

huyền thoại


14
@Henrik không, nó không hoạt động nếu không có xpd = TRUE. Cũng lưu ý rằng tốt hơn là đặt xpd = TRUE làm đối số của hàm Legend ().
Stéphane Laurent

1
Đôi khi xpdphải được đặt thành để TRUEphần tử âm hoạt động. Nhưng đôi khi không. Với lệnh args.legend=list(x="bottom", horiz=TRUE, inset=-0.2)bên trong barplot(...nó dường như không cần xpd=TRUEnhưng với legend(x="bottom", horiz=TRUE, inset=-0.2)nó dường như không cần xpd=TRUE. Bất kỳ hiểu biết? Tôi chỉ bối rối trong việc thông qua lý lẽ của tôi?
dùng3386170

28

Một giải pháp khác, bên cạnh các điều kiện đã được đề cập (sử dụng layouthoặcpar(xpd=TRUE) ) là phủ lớp âm mưu của bạn với một âm mưu trong suốt trên toàn bộ thiết bị và sau đó thêm chú giải vào đó.

Mẹo nhỏ là phủ một biểu đồ (trống) trên vùng vẽ hoàn chỉnh và thêm chú thích vào đó. Chúng ta có thể sử dụng par(fig=...)tùy chọn. Đầu tiên chúng tôi hướng dẫn R tạo một âm mưu mới trên toàn bộ thiết bị vẽ:

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

Cài đặt omamarlà cần thiết vì chúng tôi muốn có phần bên trong của ô bao trùm toàn bộ thiết bị. new=TRUElà cần thiết để ngăn R khởi động một thiết bị mới. Sau đó chúng ta có thể thêm vào ô trống:

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

Và chúng tôi đã sẵn sàng để thêm huyền thoại:

legend("bottomright", ...)

sẽ thêm một chú thích ở phía dưới bên phải của thiết bị. Tương tự như vậy, chúng ta có thể thêm chú thích vào lề trên hoặc bên phải. Điều duy nhất chúng tôi cần đảm bảo là lề của cốt truyện gốc đủ lớn để chứa đựng huyền thoại.

Đưa tất cả điều này vào một chức năng;

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(...)
}

Và một ví dụ. Đầu tiên tạo cốt truyện để đảm bảo chúng ta có đủ không gian ở phía dưới để thêm chú thích:

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

Sau đó thêm huyền thoại

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

Kết quả là:

Hình ví dụ hiển thị chú thích ở lề trên


2
Bổ sung tuyệt vời vào danh sách ở đây. Có một lời giải thích về cách làm cho công việc này hoạt động với nhiều ô trong đồ họa ở đây .
shiri

Jan, có cách nào để tăng kích thước phông chữ trong truyền thuyết, mà không có một số văn bản được cắt bớt? Ví dụ, tôi có một đồ họa gồm 4 loại nhãn khác nhau, nhưng có rất nhiều khoảng trống giữa chúng.
Một ông già ở biển.

Tôi đã viết một câu hỏi với nhiều chi tiết hơn stackoverflow.com/questions/42707308/ trộm
Một ông già ở biển.

16

Xin lỗi vì đã hồi sinh một chủ đề cũ, nhưng tôi đã gặp vấn đề tương tự ngày hôm nay. Cách đơn giản nhất mà tôi đã tìm thấy là như sau:

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

Tìm thấy ở đây: http://www.hending.edu/fmccown/R/


4
Thậm chí tốt hơn là oldpar <- par (xpd = T, mar = par () $ mar + c (0,0,0,6)) ... par (oldpar) (Xem trợ giúp của par)
rakensi

Giải pháp này tốt hơn bởi vì không gian cho huyền thoại được cố định không quan trọng độ dài của chuỗi huyền thoại
Sergio

15

Tôi thích làm như thế này:

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

nhập mô tả hình ảnh ở đây

Điều chỉnh duy nhất cần thiết là trong việc đặt lề phải đủ rộng để phù hợp với chú giải.

Tuy nhiên, điều này cũng có thể được tự động:

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

nhập mô tả hình ảnh ở đây


Sử dụng xpd = T hoặc xpd = NA không ngăn 'chính' (tiêu đề) của tôi bị cắt bớt khi nó được kéo dài để cố gắng sử dụng khu vực được thêm vào với lề phải rộng.
Phil Goetz

@PhilGoetz bạn có chắc là bạn đang vẽ sơ đồ chính trong khu vực cốt truyện không? Có thể là bạn không có đủ các dòng lề ở đó để vẽ?
jbaums

10

Gần đây tôi tìm thấy chức năng rất dễ dàng và thú vị để in chú thích bên ngoài khu vực cốt truyện mà bạn muốn.

Tạo lề ngoài ở phía bên phải của cốt truyện.

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

Tạo một cốt truyện

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

Thêm chú thích và chỉ sử dụng chức năng định vị (1) như dưới đây. Sau đó, bạn chỉ cần nhấp vào nơi bạn muốn sau khi tải tập lệnh sau.

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

Thử nó


9

Tôi chỉ có thể cung cấp một ví dụ về giải pháp bố trí đã được chỉ ra.

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

một bức tranh xấu xí: S


9

Thêm một thay thế đơn giản mà khá thanh lịch theo ý kiến ​​của tôi.

Âm mưu của bạn:

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

Huyền thoại:

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

Kết quả:

hình ảnh với huyền thoại

Ở đây chỉ có dòng thứ hai của truyền thuyết được thêm vào ví dụ của bạn. Lần lượt:

  • inset=c(0,1)- di chuyển chú giải theo một phần của vùng vẽ theo hướng (x, y). Trong trường hợp này, huyền thoại là"bottomright" vị trí. Nó được di chuyển bởi 0 vùng vẽ theo hướng x (vì vậy giữ ở "bên phải") và bởi 1 vùng vẽ theo hướng y (từ dưới lên trên). Và nó xảy ra rằng nó xuất hiện ngay trên cốt truyện.
  • xpd=TRUE - hãy để huyền thoại xuất hiện bên ngoài khu vực âm mưu.
  • horiz=TRUE - hướng dẫn để tạo ra một huyền thoại ngang.
  • bty="n" - một chi tiết phong cách để thoát khỏi hộp giới hạn huyền thoại.

Áp dụng tương tự khi thêm chú thích sang một bên:

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

Ở đây chúng tôi chỉ cần điều chỉnh các vị trí chú thích và thêm không gian lề bổ sung vào bên phải của cốt truyện. Kết quả:

hình ảnh với huyền thoại 2


4

Bạn có thể làm điều này với API Plotly R , bằng mã hoặc từ GUI bằng cách kéo chú thích vào nơi bạn muốn.

Đây là một ví dụ. Biểu đồ và mã cũng ở đây .

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)

Bạn có thể định vị chú giải bên ngoài biểu đồ bằng cách gán một trong các giá trị x và y cho 100 hoặc -100.

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

Dưới đây là các tùy chọn khác:

  • list("x" = 100, "y" = 0) cho bên ngoài dưới cùng bên phải
  • list("x" = 100, "y"= 1) Bên phải trên cùng
  • list("x" = 100, "y" = .5) Bên phải trung
  • list("x" = 0, "y" = -100) Dưới bên trái
  • list("x" = 0.5, "y" = -100) Theo trung tâm
  • list("x" = 1, "y" = -100) Dưới quyền

Sau đó là phản ứng.

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

Plotly trả lại một URL với biểu đồ của bạn khi bạn thực hiện một cuộc gọi. Bạn có thể truy cập nhanh hơn bằng cách gọi browseURL(response$url)để nó sẽ mở biểu đồ của bạn trong trình duyệt cho bạn.

url = response$url
filename = response$filename

Điều đó cho chúng ta biểu đồ này. Bạn cũng có thể di chuyển chú giải từ trong GUI và sau đó biểu đồ sẽ chia tỷ lệ tương ứng. Tiết lộ đầy đủ: Tôi thuộc nhóm Plotly.

Chú thích bên đồ thị


2

Hãy thử layout()cái mà tôi đã sử dụng cho điều này trong quá khứ bằng cách chỉ cần tạo một ô trống bên dưới, được chia tỷ lệ chính xác ở khoảng 1/4 hoặc hơn và đặt các phần chú thích theo cách thủ công trong đó.

Có một số câu hỏi cũ hơn ở đây về việc legend()bạn nên bắt đầu.


Như đã nói trong câu hỏi, đây cũng là những gì tôi nghĩ về. Nhưng nó sẽ là lý tưởng, nếu có một cách khác. Bằng cách nào đó tôi cho rằng không có.
Henrik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.