tọa độ npc của geom_point trong ggplot2


10

Làm cách nào tôi có thể lấy tọa độ x , y của geom_point trong ggplot , trong đó khung tham chiếu là toàn bộ hình ảnh được vẽ?

Tôi có thể tạo một ggplot với một số geom_point bằng cách sử dụng:

library(ggplot2)

my.plot <- ggplot(data.frame(x = c(0, 0.456, 1), y = c(0, 0.123, 1))) +
             geom_point(aes(x, y), color = "red")

Điều này mang lại:

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

Bằng cách chuyển đổi nó thành một grob , tôi có thể trích xuất một số thông tin bổ sung về ggplot này , như tọa độ đối với bảng điều khiển cốt truyện, được đánh dấu bằng mũi tên màu tím. Tuy nhiên, điều này bỏ qua không gian được đưa lên bởi các trục.

my.grob <- ggplotGrob(my.plot)
my.grob$grobs[[6]]$children[[3]]$x
# [1] 0.0454545454545455native 0.46native 0.954545454545454native 
my.grob$grobs[[6]]$children[[3]]$y
# [1] 0.0454545454545455native 0.157272727272727native 0.954545454545454native

Làm cách nào tôi có thể nhận được các giá trị của tọa độ x , y khi tôi bắt đầu đo từ góc dưới bên trái của toàn bộ hình ảnh, được đánh dấu bằng mũi tên màu lục?

Nếu có thể, tôi muốn giải pháp tính đến chủ đề của ggplot . Thêm một chủ đề như + theme_void()ảnh hưởng đến các trục và cũng thay đổi vị trí của các điểm đối với toàn bộ hình ảnh được vẽ.

Cập nhật : Tôi nhận ra rằng kích thước phông chữ của các trục thay đổi tùy thuộc vào chiều rộng và chiều cao của ô, ảnh hưởng đến kích thước tương đối của bảng vẽ . Vì vậy, sẽ không tầm thường khi cung cấp vị trí theo đơn vị npc mà không xác định chiều rộng chiều cao lô . Nếu có thể, đưa ra vị trí của geom_point là một hàm của chiều rộng chiều cao lô .


5
Tại sao 2 downvote?
markus

2
Vâng, xin vui lòng bình luận nếu bạn có mối quan tâm hoặc đề nghị.
LBogaardt

1
Hãy xem xét rằng bản thân cốt truyện không có kích thước cố định - vị trí điểm tuyệt đối không chỉ phụ thuộc vào kích thước của thiết bị mà bạn in mà còn phụ thuộc vào tỷ lệ trục của bạn. Do đó, khá tò mò về những gì bạn cần nó cho
Tjebo

1
Về các downvote, lưu ý rằng tôi không cần phải biện minh cho câu hỏi của mình để nó là một câu hỏi hợp lệ trên SE. Tại sao tôi muốn biết? Bởi vì tôi làm.
LBogaardt

1
cái này cũng vậy nhưng không bao giờ có câu trả lời thực sự stackoverflow.com/questions/48710478/ từ
Tjebo

Câu trả lời:


5

Khi bạn thay đổi kích thước một ggplot, vị trí của các thành phần trong bảng điều khiển không ở các vị trí cố định trong không gian npc. Điều này là do một số thành phần của âm mưu có kích thước cố định và một số trong số chúng (ví dụ: bảng điều khiển) thay đổi kích thước theo kích thước của thiết bị.

Điều này có nghĩa là bất kỳ giải pháp nào cũng phải tính đến kích thước thiết bị và nếu bạn muốn thay đổi kích thước lô, bạn sẽ phải chạy lại phép tính. Phải nói rằng, đối với hầu hết các ứng dụng (bao gồm cả ứng dụng của bạn, bởi âm thanh của sự vật), đây không phải là vấn đề.

Một khó khăn khác là đảm bảo rằng bạn đang xác định các rãnh chính xác trong bảng điều khiển, và rất khó để xem làm thế nào điều này có thể dễ dàng được khái quát hóa. Sử dụng các hàm tập hợp danh sách [[6]][[3]]trong ví dụ của bạn không thể khái quát hóa cho các ô khác.

Dù sao, giải pháp này hoạt động bằng cách đo kích thước và vị trí của bảng điều khiển trong gtable và chuyển đổi tất cả các kích thước thành milimet trước khi chia cho kích thước lô theo milimet để chuyển sang không gian npc. Tôi đã cố gắng làm cho nó tổng quát hơn một chút bằng cách trích xuất bảng và các điểm theo tên chứ không phải chỉ số.

library(ggplot2)
library(grid)
require(gtable)

get_x_y_values <- function(gg_plot)
{
  img_dim      <- grDevices::dev.size("cm") * 10
  gt           <- ggplot2::ggplotGrob(gg_plot)
  to_mm        <- function(x) grid::convertUnit(x, "mm", valueOnly = TRUE)
  n_panel      <- which(gt$layout$name == "panel")
  panel_pos    <- gt$layout[n_panel, ]
  panel_kids   <- gtable::gtable_filter(gt, "panel")$grobs[[1]]$children
  point_grobs  <- panel_kids[[grep("point", names(panel_kids))]]
  from_top     <- sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))
  from_left    <- sum(to_mm(gt$widths[seq(panel_pos$l - 1)]))
  from_right   <- sum(to_mm(gt$widths[-seq(panel_pos$l)]))
  from_bottom  <- sum(to_mm(gt$heights[-seq(panel_pos$t)]))
  panel_height <- img_dim[2] - from_top - from_bottom
  panel_width  <- img_dim[1] - from_left - from_right
  xvals        <- as.numeric(point_grobs$x)
  yvals        <- as.numeric(point_grobs$y)
  yvals        <- yvals * panel_height + from_bottom
  xvals        <- xvals * panel_width + from_left
  data.frame(x = xvals/img_dim[1], y = yvals/img_dim[2])
}

Bây giờ chúng tôi có thể kiểm tra nó với ví dụ của bạn:

my.plot <- ggplot(data.frame(x = c(0, 0.456, 1), y = c(0, 0.123, 1))) +
             geom_point(aes(x, y), color = "red")

my.points <- get_x_y_values(my.plot)
my.points
#>           x         y
#> 1 0.1252647 0.1333251
#> 2 0.5004282 0.2330669
#> 3 0.9479917 0.9442339

Và chúng tôi có thể xác nhận các giá trị này là chính xác bằng cách vẽ một số điểm trên các điểm đỏ của bạn, sử dụng các giá trị của chúng tôi dưới dạng tọa độ npc:

my.plot
grid::grid.draw(pointsGrob(x = my.points$x, y = my.points$y, default.units = "npc"))

Được tạo vào ngày 2020-03-25 bởi gói reprex (v0.3.0)


1
Phần này sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))là lạ nhất. Bạn có thể giải thích những gì bạn đang tổng kết ở đây?
LBogaardt

1
@LBogaardt panel_pos$tđưa ra hàng của lưới trong đó bảng (linh hoạt) nằm, vì vậy seq(panel_pos$t -1)tất cả các số hàng ở trên này, và do đó sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))là tổng chiều cao của các hàng này.
Allan Cameron

@LBogaardt Tôi đã cố gắng cân bằng giữa sự ngắn gọn và rõ ràng, nhưng có lẽ tôi đã không hoàn toàn hiểu điều này ...
Allan Cameron

À, vậy ggplot giống như một bảng, với một cột cho nhãn y, một cột cho đánh số trục y, v.v. Tương tự như vậy đối với các hàng, mỗi cột có chiều rộng / chiều cao. Bảng điều khiển là một ô trong bảng này? Hiểu rồi. Cảm ơn Allan.
LBogaardt

1
Chính xác, @LBogaardt. Trên thực tế, ggplotGrob tạo ra một bảng gTable hoặc bảng grob
Allan Cameron
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.