如何获得包括超出范围的对象的图的尺寸 [英] How to get dimensions of a plot including out of bounds objects

查看:63
本文介绍了如何获得包括超出范围的对象的图的尺寸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以这样计算图的高度:

I can calculate the height of a plot like this:

library(ggplot2)
library(egg)
library(gridExtra)

g <- ggplot(iris, aes(x = Species, y = Petal.Length)) +
  stat_summary(geom = 'bar', fun.y = mean) +
  geom_point() +
  scale_y_continuous(limits = c(0,8), expand = c(0,0), oob = function(x, ...) x)

gt <- egg::set_panel_size(g)
gt$layout$clip[gt$layout$name=="panel"] <- "off"
gridExtra::grid.arrange(gt)

sum(as.numeric(grid::convertUnit(gt$heights, "mm")))

但是,如果我有一些超出范围的geom对象,它将返回相同的高度:

But if I have some geom object that is out of bounds, it returns the same height:

g <- ggplot(iris, aes(x = Species, y = Petal.Length)) +
  stat_summary(geom = 'bar', fun.y = mean) +
  geom_point() +
  scale_y_continuous(limits = c(0,8), expand = c(0,0), oob = function(x, ...) x) +
  geom_text(label = 'obText', aes(x = 2, y = 8.5))

gt <- egg::set_panel_size(g)
gt$layout$clip[gt$layout$name=="panel"] <- "off"
gridExtra::grid.arrange(gt)

sum(as.numeric(grid::convertUnit(gt$heights, "mm")))

即使现在有一些文字位于53.35411毫米以上的位置.

even though there is now text that is positioned higher than the 53.35411mm.

有没有办法获取包括超出范围的文字的图的高度?

Is there a way to get the height of the plot including this out of bounds text?

推荐答案

我不确定您的用例是什么,但是是的,有可能.

I'm not sure what's your use case, but yes, it's possible.

问题的症结在于,不是捕获文本(或任何其他geom图层)的高度,但捕获的高度参数是 gt $ heights 嵌套层次结构中的各个杂项(表示为.$ x $ height ).

The crux of the matter is that the height of the text (or any other geom layer) is not captured in gt$heights, but in the height parameters of the respective grobs (expressed as .$x or $height) further down the nested hierarchy.

# same code as yours, except that I positioned the label ever further up, to increase the contrast
g <- ggplot(iris, aes(x = Species, y = Petal.Length)) +
  stat_summary(geom = 'bar', fun.y = mean) +
  geom_point() +
  scale_y_continuous(limits = c(0,8), expand = c(0,0), oob = function(x, ...) x) +
  geom_text(label = 'obText', aes(x = 2, y = 18.5))    

gt <- egg::set_panel_size(g)

看看 gt $ heights .我们可以验证所有高度值均保持不变,而不管面板的剪辑是否已关闭:

Take a look at gt$heights. We can verify that all the height values remain unchanged, regardless whether the panel's clipping has been turned off:

> gt$heights
 [1] 5.5pt                    0cm                      0cm                     
 [4] 0cm                      0cm                      0cm                     
 [7] 4cm                      sum(2.75pt, 1grobheight) 1grobheight             
[10] 0cm                      0pt                      5.5pt    

gt$layout$clip[gt$layout$name=="panel"] <- "off"

> gt$heights
 [1] 5.5pt                    0cm                      0cm                     
 [4] 0cm                      0cm                      0cm                     
 [7] 4cm                      sum(2.75pt, 1grobheight) 1grobheight             
[10] 0cm                      0pt                      5.5pt   

在上述所有值中,您应该关心的是 [7] 4cm ,因为这是面板的高度.我们知道,由于基于 gt 的布局,面板位于第7行&第五列,可以通过检查 gt 本身的控制台打印输出或通过gtable包中的 gtable_show_layout()来验证:

Among all the values above, the one you should care about is [7] 4cm, because that's the height of the panel. We know that because based on gt's layout, the panel is in the 7th row & 5th column, which can be verified by examining the console printout of gt itself, or through gtable_show_layout() from the gtable package:

> gt
TableGrob (12 x 9) "layout": 18 grobs
    z         cells       name                                           grob
1   0 ( 1-12, 1- 9) background               rect[plot.background..rect.3020]
2   5 ( 6- 6, 4- 4)     spacer                                 zeroGrob[NULL]
3   7 ( 7- 7, 4- 4)     axis-l           absoluteGrob[GRID.absoluteGrob.3008]
4   3 ( 8- 8, 4- 4)     spacer                                 zeroGrob[NULL]
5   6 ( 6- 6, 5- 5)     axis-t                                 zeroGrob[NULL]
6   1 ( 7- 7, 5- 5)      panel                      gTree[panel-1.gTree.2994]
7   9 ( 8- 8, 5- 5)     axis-b           absoluteGrob[GRID.absoluteGrob.3001]
8   4 ( 6- 6, 6- 6)     spacer                                 zeroGrob[NULL]
9   8 ( 7- 7, 6- 6)     axis-r                                 zeroGrob[NULL]
10  2 ( 8- 8, 6- 6)     spacer                                 zeroGrob[NULL]
11 10 ( 5- 5, 5- 5)     xlab-t                                 zeroGrob[NULL]
12 11 ( 9- 9, 5- 5)     xlab-b titleGrob[axis.title.x.bottom..titleGrob.3011]
13 12 ( 7- 7, 3- 3)     ylab-l   titleGrob[axis.title.y.left..titleGrob.3014]
14 13 ( 7- 7, 7- 7)     ylab-r                                 zeroGrob[NULL]
15 14 ( 4- 4, 5- 5)   subtitle         zeroGrob[plot.subtitle..zeroGrob.3016]
16 15 ( 3- 3, 5- 5)      title            zeroGrob[plot.title..zeroGrob.3015]
17 16 (10-10, 5- 5)    caption          zeroGrob[plot.caption..zeroGrob.3018]
18 17 ( 2- 2, 2- 2)        tag              zeroGrob[plot.tag..zeroGrob.3017]

> gtable::gtable_show_layout(gt)

要获取各个geom图层的高度,我们可以更深入地研究面板对象的子对象:

To get the height of individual geom layers, we can dig deeper to look at the children grobs of the panel grob:

> gt$grobs[[which(gt$layout$name == "panel")]]$children
(gTree[grill.gTree.2992], zeroGrob[NULL], rect[geom_rect.rect.2978], 
points[geom_point.points.2980], text[GRID.text.2981], zeroGrob[NULL], 
zeroGrob[panel.border..zeroGrob.2982]) 

在这种情况下,我们知道(因为该示例是通过这种方式创建的),令人讨厌的geom是文本层,因此我们可以直接转到第5个子对象,并查看其中的高度:

In this case, we know (since the example's created that way) that the offending geom is the text layer, so we can go straight to the 5th children grob and look at the height(s) there:

> gt$grobs[[which(gt$layout$name == "panel")]]$children[[5]]$y
[1] 2.3125native 2.3125native 2.3125native 2.3125native 2.3125native 2.3125native
[7] 2.3125native 2.3125native 2.3125native 2.3125native 2.3125native 2.3125native
...

从网格包中引用?unit 帮助文件,本机"坐标系意味着测量值相对于视口的xscale&yscale.因此, 2.3125native 可以解释为2.3125 x面板高度(4厘米)= 9.25厘米.

Referencing the ?unit help file from the grid package, the "native" coordinate system means that the measurements are relative to the viewport's xscale & yscale. Hence 2.3125native can be interpreted as 2.3125 x panel height (4cm) = 9.25cm.

更一般而言,要获取两个方向的高度限制:

More generally, to get the height limits in both directions:

# rect grobs such as those created by geom_bar() have "height" / "width" measurements,
# while point & text grobs have "y" / "x" measurements, & we look for both
max.grob.heights <- sapply(gt$grob[[which(gt$layout$name == "panel")]]$children,
                       function(x) ifelse(!is.null(x$height) & "unit" %in% class(x$height),
                                          max(as.numeric(x$height)),
                                          ifelse(!is.null(x$y) & "unit" %in% class(x$y),
                                                 max(as.numeric(x$y)),
                                                 0)))
max.grob.heights = max(max.grob.heights)

min.grob.heights <- sapply(gt$grob[[which(gt$layout$name == "panel")]]$children,
                           function(x) ifelse(!is.null(x$height) & "unit" %in% class(x$height),
                                              min(as.numeric(x$height)),
                                              ifelse(!is.null(x$y) & "unit" %in% class(x$y),
                                                     min(as.numeric(x$y)),
                                                     0)))
min.grob.heights = min(min.grob.heights)

# identify panel row & calculate panel height
panel.row <- gt$layout[gt$layout$name == "panel", "t"] # = 7
panel.height <- as.numeric(grid::convertUnit(gt$heights[panel.row],"mm"))

如果只希望包括所有geom图层的面板组件的高度(并且不在乎它们与整体grob对象的组合高度的关系),则可以将max/min grob高度用作乘积的乘积.面板高度:

If you just want the height of the panel component including all geom layers (& don't care how they relate to the overall grob object's combined height), you can use the max / min grob heights as a multiplier for the panel height:

panel.multiplier <- max(1, max.grob.heights) + abs(min.grob.heights)
result <- panel.multiplier * panel.height

如果要计算绘图的整体高度,则必须分别比较顶部/底部边界对象的高度:如果它们在绘图范围之内,请使用原始高度;如果超过该高度,请改用其高度.

If you want the calculate the overall height of the plot, you'll have to separately compare the height of the top / bottom out-of-bounds objects: if they are within the confines of the plot, use the original heights; if they exceed that, use their heights instead.

# calculate height of all the grobs above the panel
height.above.panel <- gt$heights[1:(panel.row - 1)]
height.above.panel <- sum(as.numeric(grid::convertUnit(height.above.panel, "mm")))

# check whether the out-of-bound object (if any) exceeds this height, & replace if necessary
if(max.grob.heights > 1){
  oob.height.above.panel <- (max.grob.heights - 1) * panel.height
  height.above.panel <- max(height.above.panel, oob.height.above.panel)
}

# as above, calculate the height of all the grobs below the panel
height.below.panel <- gt$heights[(panel.row + 1):length(gt$heights)]
height.below.panel <- sum(as.numeric(grid::convertUnit(height.below.panel, "mm")))

# as above
if(min.grob.heights < 0){
  oob.height.below.panel <- abs(min.grob.heights) * panel.height
  height.below.panel <- max(height.below.panel, oob.height.below.panel)
}

# sum the result
result <- height.above.panel + panel.height + height.below.panel

这篇关于如何获得包括超出范围的对象的图的尺寸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆