是否可以在数据之前先绘制轴线?

这是 to my previous question 的后续内容,我一直在寻找一种解决方案,先绘制轴,然后绘制数据。答案适用于该特定问题和示例,但它提出了一个更一般的问题,即如何更改底层 grobs 的绘图顺序。首先是轴,然后是数据。

非常类似于可以在顶部绘制或不绘制面板网格。

面板网格和轴格布显然是不同的——轴更多地作为引导对象而不是“简单”格布。 (轴是用 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() 

是否可以在数据之前先绘制轴线?

附言我不会接受甚至不赞成制造假轴的答案,因为这不是我正在寻找或试图理解的。

iCMS 回答:是否可以在数据之前先绘制轴线?

一个 ggplot 可以用它的 gtable 来表示。 grob 的位置由 layout 元素和 "the z-column is used to define the drawing order of the grobs" 给出。

然后可以增加 zpanel 值,其中包含点 grob,以便最后绘制。

所以如果 p 是你的情节,那么

g <- ggplotGrob(p) ;
g$layout[g$layout$name == "panel","z"] <-  max(g$layout$z) + 1L
grid::grid.draw(g)

然而,as noted in the comment 这会改变轴的外观,这可能是由于面板被绘制在一些轴上。

但是来自dww

的令人兴奋的新消息

如果我们将 theme(panel.background = element_rect(fill = NA)) 添加到图中,轴不再被部分遮挡。这既证明这是导致轴线变细的原因,也提供了一个合理的解决方法,前提是您不需要彩色面板背景。

,

既然您正在寻找更多“在绘制级别”的解决方案,那么开始的地方是询问“首先如何绘制 ggplot?”。答案可以在 ggplot 对象的 print 方法中找到:

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)
#> }

通过在 ggplot 对象上调用 ggplot_build,然后在 ggplot_gtable 的输出上调用 ggplot_build,您可以看到实际上绘制了 ggplot。

难点在于面板及其背景、网格线和数据被创建为一个独特的 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,"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,limits = c(0,1)
  ) +
  coord_cartesian(clip = "off") +
  theme_classic() +
  theme(panel.background = element_rect(fill = "gray90"))

p

underplot_axes(p)

reprex package (v0.3.0) 于 2021 年 5 月 7 日创建

现在,您可能会认为这是“创建假轴”,但我认为它更像是将轴线从 Grob 树中的一个位置“移动”到另一个位置。遗憾的是,该选项似乎没有内置到 ggplot 中,但我也可以看到,它需要对 ggplot 的构造方式进行重大改革以允许该选项。

,

这里有一个 hack,不需要“深入了解”,而是使用 patchwork 在顶部添加另一个层,这只是 geom 层。

a <- [your plot above]

library(patchwork)
a + inset_element(a + them_void(),left = 0,bottom = 0,right = 1,top = 1)

enter image description here

本文链接:https://www.f2er.com/493830.html

大家都在问