我可以这样计算图的高度:
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对象,它将返回相同的高度:
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.35411mm。
有没有一种方法可以获取包括超出范围的文字在内的绘图的高度?
答案 0 :(得分:1)
我不确定您的用例是什么,但是是的,有可能。
问题的症结在于,文本(或任何其他geom层)的高度不是在gt$heights
中捕获的,不是 ,而是在各个小齿轮的高度参数(表示为如.$x
或$height
)在嵌套层次结构的下方。
# 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
。我们可以验证所有高度值均保持不变,而不管面板的剪辑是否已关闭:
> 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行第5列,可以通过检查gt
本身的控制台打印输出或通过gtable_show_layout()
来验证该面板从gtable包中:
> 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图层的高度,我们可以更深入地研究面板对象的子对象:
> 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个子对象,并查看其中的高度:
> 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面板高度(4cm)= 9.25cm。
更一般而言,要获取两个方向的高度限制:
# 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"))
如果只希望包括所有几何图层的面板组件的高度(并且不在乎它们与整个grob对象的组合高度的关系),则可以将max / min grob高度用作面板的乘数高度:
panel.multiplier <- max(1, max.grob.heights) + abs(min.grob.heights)
result <- panel.multiplier * panel.height
如果要计算绘图的整体高度,则必须分别比较顶部/底部边界对象的高度:如果它们在绘图范围之内,请使用原始高度;如果超过该高度,请改用其高度。
# 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