ggplot2中geom_point的NPC坐标


10

如何获取ggplotgeom_pointxy坐标,其中参考帧是整个绘制的图像?

我可以使用一些geom_point创建一个ggplot

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

从整个图像的左下角开始测量时,如何获得xy坐标的值,并用绿色箭头标记?

如果有可能,我想解决顾及主题的的ggplot。添加主题+ theme_void()影响轴和也相对于整个绘图图像偏移的点的位置。

更新:我意识到轴的字体大小会根据绘图的宽度和高度而变化,从而影响绘图面板的相对大小。因此如果不定义绘图宽度绘图高度,npc为单位提供位置并不是一件容易的事。如果可能,根据绘图宽度绘图高度给出geom_points的位置。


5
为什么要2次投票?
马库斯

2
是的,如果您有任何疑问或建议,请发表评论。
LBogaardt

1
考虑到绘图本身没有固定的尺寸-绝对点位置不仅取决于要打印的设备的尺寸,还取决于轴的比率。因此,很好奇您的需求
Tjebo

1
关于降票,请注意,我不需要证明我的问题是对SE的有效问题。我为什么想知道?因为我愿意。
LBogaardt

1
这也是。但一直没有得到真正的答案stackoverflow.com/questions/48710478/...
Tjebo

Answers:


5

调整ggplot的大小时,面板中元素的位置不在npc空间中的固定位置。这是因为绘图中的某些组件具有固定的大小,而其中某些组件(例如面板)会根据设备的大小而更改尺寸。

这意味着任何解决方案都必须考虑设备尺寸,如果要调整图的大小,则必须再次运行计算。话虽如此,对于大多数应用程序(包括您的应用程序而言),这不是问题。

另一个困难是要确保在面板组中识别出正确的组,并且很难看到如何轻松地将其概括。使用列表子功能[[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
#>           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"))

reprex包(v0.3.0)创建于2020-03-25


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)]))是这些行的高度之和。
艾伦·卡梅伦

@LBogaardt我试图在简洁和清晰度之间取得平衡,但是也许我还没有做到这一点……
艾伦·卡梅伦

嗯,所以ggplot就像一张表,其中一列用于y标签,一列用于y轴编号等。对于行,同样具有宽度/高度。面板是此表中的一个单元格吗?得到它了。谢谢艾伦。
LBogaardt

1
确实是@LBogaardt。实际上,ggplotGrob会生成gTable或grob表
Allan Cameron
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.