当你调整ggplot的大小时,面板内元素的位置不是在npc空间中固定的位置。这是因为绘图的一些组件具有固定的大小,而其中一些组件(例如面板)根据设备的大小而改变尺寸。
这意味着任何解决方案都必须考虑设备的大小,并且如果您想调整绘图的大小,您需要重新运行计算。话虽如此,对于大多数应用程序(包括您的应用程序),这并不是一个问题。
另一个困难是确保您正确地识别面板grob中的正确grob,而且很难看出这个问题如何容易地被泛化。在您的示例中使用列表子集函数
[[6]]
和
[[3]]
并不能推广到其他绘图。
无论如何,这个解决方案通过测量gtable中的面板大小和位置,并将所有尺寸转换为毫米,然后再除以毫米单位的绘图尺寸来转换为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
我们可以通过在您的红点上绘制一些点图形,使用我们的值作为npc坐标来确认这些值是正确的。
my.plot
grid::grid.draw(pointsGrob(x = my.points$x, y = my.points$y, default.units = "npc"))
![enter image description here](https://istack.dev59.com/E9qgG.webp)
2020-03-25由reprex package (v0.3.0)创建