พิกัด npc ของ geom_point ใน ggplot2


10

ฉันจะรับพิกัดx , yของgeom_pointในggplotโดยที่กรอบอ้างอิงเป็นภาพที่ถูกพล็อตทั้งหมดได้อย่างไร

ฉันสามารถสร้างggplotด้วยgeom_pointบางอย่างโดยใช้:

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

สิ่งนี้ให้:

ป้อนคำอธิบายรูปภาพที่นี่

โดยการแปลงเป็นgrobฉันสามารถดึงข้อมูลเพิ่มเติมบางอย่างเกี่ยวกับggplotนี้เช่นพิกัดที่เกี่ยวกับแผงพล็อตซึ่งมีลูกศรสีม่วงทำเครื่องหมายไว้ อย่างไรก็ตามสิ่งนี้จะไม่สนใจพื้นที่ที่แกนนำมาใช้

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

ฉันจะรับค่าพิกัดx , y ได้อย่างไรเมื่อฉันเริ่มวัดจากมุมล่างซ้ายของภาพทั้งหมดทำเครื่องหมายโดยลูกศรสีเขียว

ถ้าเป็นไปได้ผมอยากวิธีการคำนึงถึงรูปแบบของggplot การเพิ่มธีมเช่น+ theme_void()มีผลกับแกนและเลื่อนตำแหน่งของจุดด้วยความเคารพต่อภาพที่ถูกพล็อตทั้งหมด

ปรับปรุง : ฉันตระหนักว่าขนาดตัวอักษรของแกนมีการเปลี่ยนแปลงขึ้นอยู่กับความกว้างและความสูงของพล็อตที่มีผลต่อขนาดญาติของแผงพล็อต ดังนั้นมันจะไม่เป็นที่น่ารำคาญที่จะให้สถานที่ในNPCหน่วยโดยไม่ต้องกำหนดความกว้างของพล็อตและความสูงของพล็อต ถ้าเป็นไปได้ให้สถานที่ตั้งของgeom_pointsเป็นหน้าที่ของที่ความกว้างของพล็อตและความสูงของพล็อต


5
ทำไมต้องลง 2 คะแนน
markus

2
ใช่โปรดแสดงความคิดเห็นหากคุณมีข้อกังวลหรือข้อเสนอแนะ
LBogaardt

1
พิจารณาว่าพล็อตตัวเองไม่มีมิติที่คงที่ - ตำแหน่งจุดสัมบูรณ์ไม่เพียงขึ้นอยู่กับขนาดของอุปกรณ์ที่คุณพิมพ์ แต่ยังรวมถึงอัตราส่วนของแกนของคุณด้วย ดังนั้นค่อนข้างอยากรู้อยากเห็นสิ่งที่คุณต้องการสำหรับ
Tjebo

1
เกี่ยวกับ downvotes โปรดทราบว่าฉันไม่จำเป็นต้องพิสูจน์คำถามของฉันเพื่อให้เป็นคำถามที่ถูกต้องใน SE ทำไมฉันถึงอยากรู้? เพราะฉันทำ.
LBogaardt

1
อันนี้เหมือนกัน แต่ไม่เคยได้รับคำตอบที่แท้จริงstackoverflow.com/questions/48710478/ …
Tjebo

คำตอบ:


5

เมื่อคุณปรับขนาด ggplot ตำแหน่งขององค์ประกอบภายในแผงควบคุมจะไม่อยู่ในตำแหน่งคงที่ในพื้นที่ npc นี่เป็นเพราะส่วนประกอบบางส่วนของพล็อตมีขนาดคงที่และบางส่วน (ตัวอย่างเช่นพาเนล) เปลี่ยนขนาดตามขนาดของอุปกรณ์

ซึ่งหมายความว่าวิธีแก้ไขปัญหาใด ๆ จะต้องคำนึงถึงขนาดของอุปกรณ์และหากคุณต้องการปรับขนาดพล็อตคุณจะต้องเรียกใช้การคำนวณอีกครั้ง ต้องบอกว่าสำหรับการใช้งานส่วนใหญ่ (รวมถึงของคุณด้วยเสียงของสิ่งต่าง ๆ ) นี่ไม่ใช่ปัญหา

ปัญหาอีกประการหนึ่งคือการทำให้แน่ใจว่าคุณระบุ grobs ที่ถูกต้องภายในแผง grob และมันยากที่จะเห็นว่าสิ่งนี้สามารถทำให้เป็นเรื่องทั่วไปได้อย่างง่ายดาย การใช้ฟังก์ชั่นชุดย่อยของรายการ[[6]]และ[[3]]ในตัวอย่างของคุณนั้นไม่สามารถแปลงเป็นแปลงอื่น ๆ ได้

อย่างไรก็ตามโซลูชันนี้ทำงานโดยการวัดขนาดและตำแหน่งของแผงภายใน gtable และแปลงทุกขนาดเป็น milimetres ก่อนหารด้วยขนาดของ plot ใน milimetres เพื่อแปลงเป็นพื้นที่ npc ฉันพยายามทำให้มันเป็นเรื่องทั่วไปมากขึ้นโดยการแยกพาเนลและคะแนนตามชื่อแทนที่จะเป็นดัชนีตัวเลข

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

ตอนนี้เราสามารถทดสอบกับตัวอย่างของคุณ:

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

และเราสามารถยืนยันค่าเหล่านี้ถูกต้องโดยการพล็อตจุดบางจุดบนจุดสีแดงของคุณโดยใช้ค่าของเราเป็นพิกัด npc:

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

สร้างเมื่อ 2020-03-25 โดยแพ็คเกจ reprex (v0.3.0)


1
sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))ส่วนนี้เป็นสิ่งที่แปลกประหลาด คุณช่วยอธิบายสิ่งที่คุณสรุปได้ที่นี่ได้ไหม
LBogaardt

1
@LBogaardt panel_pos$tให้แถวของกริดที่แผง (ที่ยืดหยุ่น) ตั้งอยู่ดังนั้นseq(panel_pos$t -1)คือหมายเลขแถวทั้งหมดที่อยู่เหนือสิ่งนี้ดังนั้นจึงsum(to_mm(gt$heights[seq(panel_pos$t - 1)]))เป็นผลรวมของความสูงของแถวเหล่านี้
Allan Cameron

@Bogaardt ฉันพยายามที่จะรักษาความสมดุลระหว่างความกะทัดรัดและความคมชัด แต่บางทีฉันอาจจะไม่ได้รับสิทธินี้ ...
Allan Cameron

อาดังนั้น ggplot ก็เหมือนกับตารางโดยมีหนึ่งคอลัมน์สำหรับ y-label, หนึ่งอันสำหรับการกำหนดแกน y เป็นต้นในทำนองเดียวกันสำหรับแถวแต่ละแถวมีความกว้าง / ความสูง แผงเป็นเซลล์เดียวในตารางนี้? เข้าใจแล้ว ขอบคุณอัลลัน
LBogaardt

1
@LBogaardt อย่างแน่นอน ในความเป็นจริง ggplotGrob สร้างตาราง gTable หรือ grob
Allan Cameron
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.