这是我之前的问题的后续问题,我正在寻找一种解决方案,先绘制轴,然后绘制数据。答案适用于该特定问题和示例,但它提出了一个更一般的问题,即如何更改底层 grobs 的绘图顺序。首先是轴,然后是数据。
非常类似于面板网格 grob 可以绘制在顶部或不绘制的方式。
面板网格和轴格布显然是不同的——轴更多地作为引导对象而不是“简单”格布。(轴是用 绘制的ggplot2:::draw_axis(),而面板网格是作为ggplot2:::Layout对象的一部分构建的)。
我想这就是为什么在顶部绘制轴的原因,我想知道是否可以更改绘制顺序。
# An example to play with
library(ggplot2)
df <- data.frame(var = "", val = 0)
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()
Run Code Online (Sandbox Code Playgroud)

PS我不会接受甚至不赞成创建假轴的答案,因为这不是我正在寻找或试图理解的。
Aggplot可以用它的 表示gtable。grobs 的位置由layout元素给出,“z 列用于定义 grobs 的绘制顺序”。
在z该值panel,其中包含点GROB,然后可以增加,所以它是最后绘制。
所以如果p是你的情节那么
g <- ggplotGrob(p) ;
g$layout[g$layout$name == "panel", "z"] <- max(g$layout$z) + 1L
grid::grid.draw(g)
Run Code Online (Sandbox Code Playgroud)
然而,正如评论中所指出的,这会改变轴的外观,这可能是由于面板被绘制在一些轴上。
但是在来自dww 的令人兴奋的新消息中
如果我们添加
theme(panel.background = element_rect(fill = NA))到图中,轴不再部分被遮挡。这既证明这是导致轴线变细的原因,也提供了合理的解决方法,前提是您不需要彩色面板背景。
由于您正在寻找更多“在绘制级别”的解决方案,那么开始的地方是询问“首先如何绘制 ggplot?”。答案可以在printggplot 对象的方法中找到:
ggplot2:::print.ggplot
#> function (x, newpage = is.null(vp), vp = NULL, ...)
#> {
#> set_last_plot(x)
#> if (newpage)
#> grid.newpage()
#> grDevices::recordGraphics(requireNamespace("ggplot2",
#> quietly = TRUE), list(), getNamespace("ggplot2"))
#> data <- ggplot_build(x)
#> gtable <- ggplot_gtable(data)
#> if (is.null(vp)) {
#> grid.draw(gtable)
#> }
#> else {
#> if (is.character(vp))
#> seekViewport(vp)
#> else pushViewport(vp)
#> grid.draw(gtable)
#> upViewport()
#> }
#> invisible(x)
#> }
Run Code Online (Sandbox Code Playgroud)
在那里您可以看到 ggplot 实际上是通过调用ggplot_buildggplot 对象绘制的,然后ggplot_gtable在ggplot_build.
困难在于面板及其背景、网格线和数据被创建为一个独特的 grob 树。然后将其作为单个实体嵌套在由ggplot_build. 轴线绘制在该面板的“顶部”。如果先绘制这些线,它们的一部分粗细将被面板过度绘制。正如 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
}
Run Code Online (Sandbox Code Playgroud)
这些现在都可以协调成一个单一的功能,使整个过程更容易:
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)
}
Run Code Online (Sandbox Code Playgroud)
现在你可以调用underplot_axesggplot 对象。我稍微修改了您的示例以创建一个灰色背景面板,以便我们可以更清楚地看到发生了什么:
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
Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)

由reprex 包(v0.3.0)于 2021 年 5 月 7 日创建
现在,您可能会认为这是“创建假轴”,但我认为它更像是将轴线从 Grob 树中的一个位置“移动”到另一个位置。遗憾的是,该选项似乎没有内置到 ggplot 中,但我也可以看到,它需要对 ggplot 的构造方式进行重大改革以允许该选项。
| 归档时间: |
|
| 查看次数: |
292 次 |
| 最近记录: |