【问题标题】:npc coordinates of geom_point in ggplot2ggplot2中geom_point的npc坐标
【发布时间】:2020-03-22 18:35:59
【问题描述】:

如何在 ggplot 中获取 geom_pointxy 坐标,其中参考frame 是整个绘制的图像吗?

我可以使用一些 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 的位置作为 plot widthplot height 的函数给出。

【问题讨论】:

  • 为什么投了 2 票?
  • 是的,如果您有任何疑虑或建议,请发表评论。
  • 请考虑绘图本身没有固定尺寸 - 绝对点位置不仅取决于打印设备的大小,还取决于轴的比例。因此很好奇你需要它来做什么
  • 关于否决票,请注意,我不需要证明我的问题是对 SE 的有效问题。为什么我想知道?因为我愿意。
  • 这个也是。但从未得到真正的答案stackoverflow.com/questions/48710478/…

标签: r ggplot2 grob


【解决方案1】:

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

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

另一个困难是确保您在面板 grob 中识别出正确的 grobs,而且很难看出如何轻松概括这一点。在您的示例中使用列表子集函数[[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 package (v0.3.0) 于 2020 年 3 月 25 日创建

【讨论】:

  • 这个sum(to_mm(gt$heights[seq(panel_pos$t - 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。事实上,ggplotGrob 产生了一个 gTable 或 grob 表
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多