既然您正在寻找更高级的解决方案,那么开始的地方就是问“ggplot首先是如何绘制的?”答案可以在ggplot对象的print
方法中找到:
ggplot2:::print.ggplot
在这里,你可以看到绘制ggplot实际上是通过对ggplot对象调用ggplot_build
,然后对ggplot_build
的输出调用ggplot_gtable
来完成的。
困难之处在于,面板及其背景、网格线和数据是作为单个grob树创建的。然后将其嵌套为ggplot_build
产生的最终grob表中的单个实体。轴线在该面板的“顶部”绘制。如果先绘制这些线,则它们的一部分厚度将被面板覆盖。如user20650的答案所述,如果您不需要绘图具有背景颜色,则这不是问题。
据我所知,除非您自己添加grob,否则没有本地方法将轴线包括在面板中。
以下一系列小函数允许您获取绘图对象,从中删除轴线,并将轴线添加到面板中:
get_axis_grobs <- function(p_table)
{
axes <- grep("axis", p_table$layout$name)
axes[sapply(p_table$grobs[axes], function(x) class(x)[1] == "absoluteGrob")]
}
remove_lines_from_axis <- function(axis_grob)
{
axis_grob$children[[grep("polyline", names(axis_grob$children))]] <- zeroGrob()
axis_grob
}
remove_all_axis_lines <- function(p_table)
{
axes <- get_axis_grobs(p_table)
for(i in axes) p_table$grobs[[i]] <- remove_lines_from_axis(p_table$grobs[[i]])
p_table
}
get_panel_grob <- function(p_table)
{
p_table$grobs[[grep("panel", p_table$layout$name)]]
}
add_axis_lines_to_panel <- function(panel)
{
old_order <- panel$childrenOrder
panel <- grid::addGrob(panel, grid::linesGrob(x = unit(c(0, 0), "npc")))
panel <- grid::addGrob(panel, grid::linesGrob(y = unit(c(0, 0), "npc")))
panel$childrenOrder <- c(old_order[1],
setdiff(panel$childrenOrder, old_order),
old_order[2:length(old_order)])
panel
}
现在,所有这些都可以协调到一个单一的函数中,使整个过程更加容易:
underplot_axes <- function(p)
{
p_built <- ggplot_build(p)
p_table <- ggplot_gtable(p_built)
p_table <- remove_all_axis_lines(p_table)
p_table$grobs[[grep("panel", p_table$layout$name)]] <-
add_axis_lines_to_panel(get_panel_grob(p_table))
grid::grid.newpage()
grid::grid.draw(p_table)
invisible(p_table)
}
现在,您只需在ggplot对象上调用
underplot_axes
即可。我稍微修改了您的示例以创建一个灰色背景面板,这样我们可以更清楚地看到正在发生的事情:
library(ggplot2)
df <- data.frame(var = "", val = 0)
p <- ggplot(df) +
geom_point(aes(val, var), color = "red", size = 10) +
scale_x_continuous(
expand = c(0, 0),
limits = c(0,1)
) +
coord_cartesian(clip = "off") +
theme_classic() +
theme(panel.background = element_rect(fill = "gray90"))
p
![](https://i.imgur.com/wIvy22Q.png)
underplot_axes(p)
![](https://i.imgur.com/i1fOcxK.png)
此内容创建于2021年5月7日,使用reprex package(v0.3.0)
现在,您可能认为这是“创建虚假轴”,但我更倾向于将其视为将轴线从grob树中的一个位置移动到另一个位置。很遗憾这个选项似乎没有内置到ggplot中,但我也可以看出,要允许该选项需要对构建ggplot的方式进行重大改进。
g = ggplotGrob(p) ; g$layout[g$layout$name == "panel", "z"] = 12 ; g$layout[g$layout$name == "ylab-l", "z" ] = 0 ; grid::grid.draw(g)
。 - user20650