如何获取包括越界对象的图的尺寸
How to get dimensions of a plot including out of bounds objects
我可以这样计算地块的高度:
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 对象,它 returns 相同的高度:
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。
有没有办法获取包含此越界文本的图的高度?
我不确定你的用例是什么,但是是的,这是可能的。
问题的症结在于文本(或任何其他geom层)的高度不是在gt$heights
中捕获的,而是在高度参数中相应的 grob(表示为 .$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 层的高度,我们可以深入挖掘以查看面板 grob 的 children 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 个 children grob 并查看高度那里:
> 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
帮助文件,"native" 坐标系表示测量值与视口的 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 object 的组合高度的关系),您可以使用 max / min grob 高度作为面板高度的乘数:
panel.multiplier <- max(1, max.grob.heights) + abs(min.grob.heights)
result <- panel.multiplier * panel.height
如果你想计算地块的整体高度,你必须分别比较顶部/底部的高度out-of-bounds objects:如果它们在范围内情节,使用原来的高度;如果他们超过那个,请改用他们的身高。
# 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
我可以这样计算地块的高度:
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 对象,它 returns 相同的高度:
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。
有没有办法获取包含此越界文本的图的高度?
我不确定你的用例是什么,但是是的,这是可能的。
问题的症结在于文本(或任何其他geom层)的高度不是在gt$heights
中捕获的,而是在高度参数中相应的 grob(表示为 .$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 层的高度,我们可以深入挖掘以查看面板 grob 的 children 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 个 children grob 并查看高度那里:
> 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
帮助文件,"native" 坐标系表示测量值与视口的 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 object 的组合高度的关系),您可以使用 max / min grob 高度作为面板高度的乘数:
panel.multiplier <- max(1, max.grob.heights) + abs(min.grob.heights)
result <- panel.multiplier * panel.height
如果你想计算地块的整体高度,你必须分别比较顶部/底部的高度out-of-bounds objects:如果它们在范围内情节,使用原来的高度;如果他们超过那个,请改用他们的身高。
# 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