R 是否可以先绘制轴线,然后再绘制数据?

R 是否可以先绘制轴线,然后再绘制数据?,r,ggplot2,grob,R,Ggplot2,Grob,这是一个跟进,我一直在寻找一个解决方案,首先绘制轴,然后绘制数据。答案适用于特定的问题和示例,但它提出了一个更一般的问题,即如何更改基础grob的绘图顺序。首先是轴,然后是数据 非常类似于面板网格grob是否可以在顶部绘制 “面板栅格”和“轴”GROB的生成方式显然不同——轴更多地是作为导向对象,而不是“简单”GROB。(轴是使用ggplot2:::draw_axis()绘制的,而面板网格是作为ggplot2::Layout对象的一部分构建的) 我想这就是为什么在顶部绘制轴,我想知道是否可以更改

这是一个跟进,我一直在寻找一个解决方案,首先绘制轴,然后绘制数据。答案适用于特定的问题和示例,但它提出了一个更一般的问题,即如何更改基础grob的绘图顺序。首先是轴,然后是数据

非常类似于面板网格grob是否可以在顶部绘制

“面板栅格”和“轴”GROB的生成方式显然不同——轴更多地是作为导向对象,而不是“简单”GROB。(轴是使用
ggplot2:::draw_axis()
绘制的,而面板网格是作为
ggplot2::Layout
对象的一部分构建的)

我想这就是为什么在顶部绘制轴,我想知道是否可以更改绘制顺序

#一个可以玩的例子
图书馆(GG2)

df这里有一个hack,它不需要“在引擎盖下”,而是使用
补丁来在顶部添加另一层,即geom层

a <- [your plot above]

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

aa
ggplot
可以用其
gtable
表示。GROB的位置由
布局
元素和给出

然后可以增加包含点grob的
面板的
z
值,以便最后绘制

因此,如果
p
是您的绘图,那么

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

g既然您正在寻找一个更“在绘图级别”的解决方案,那么首先要问“ggplot是如何绘制的?”。答案可以在ggplot对象的
打印
方法中找到:

ggplot2:::print.ggplot
#>函数(x,newpage=is.null(vp),vp=null,…)
#> {
#>设置最后一个绘图(x)
#>如果(新页)
#>grid.newpage()
#>grDevices::recordGraphics(需要重命名空间(“ggplot2”),
#>默认值为TRUE)、list()、getNamespace(“ggplot2”))
#>数据gtable if(为空(vp)){
#>网格绘制(gtable)
#>     }
#>否则{
#>如果(是字符(vp))
#>seekViewport(副总裁)
#>视口(vp)
#>网格绘制(gtable)
#>upViewport()
#>     }
#>不可见(x)
#> }
其中,您可以通过在ggplot对象上调用
ggplot\u build
,然后在
ggplot\u build
的输出上调用
ggplot\u gtable
来实际绘制ggplot

困难在于面板及其背景、网格线和数据被创建为一个独特的grob树。然后将其作为单个实体嵌套在由
ggplot\u build
生成的最终grob表中。轴线在该面板的“顶部”绘制。如果先绘制这些线,其厚度的一部分将与面板一起过度绘制。正如user20650的回答中所提到的,如果您不需要将绘图设置为背景色,则这不是问题

据我所知,除非您自己将轴线添加为GROB,否则没有本地方法将轴线作为面板的一部分

以下小功能套件允许您获取打印对象,从中删除轴线并将轴线添加到面板中:


get_axis\u grobs这可能不是您想要的,但是如何更改gtable中的“z”列,即
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是和否。我认为这是非常正确的方向。我通常更喜欢一个“在绘图级别的解决方案”,实际上主要是出于好奇。2) 不知道为什么,但当我尝试交换z列时,轴的外观会发生变化。可能是个设备问题。现在是睡觉的时候了,明天我们需要深入研究一下。已经谢谢你了!是的,我认为轴线看起来有点细。。。可能因为面板现在正在绘制其中的一部分?我很欣赏这个建议,我不知道inset_元素,我喜欢拼凑的包,但我不是在问如何伪造绘制在轴上的数据的外观。在这种情况下,我假设数据甚至绘制了两次,这可能会在最终输出中产生一些奇怪的效果。我想给出一个简单的方法,它适用于大多数情况,例如,在不使用alpha的情况下。如果您的绘图涉及alpha,我建议在原始的
geom\uuz
中将颜色设置为NA,然后在第二个绘图中添加geom。我知道这不是你想要的优雅解决方案,但你当然可以使用这种技术绘制真实轴,然后在顶部绘制真实数据,而不需要“伪造”。我认为过度拉伸也可能会在没有alpha的情况下产生奇怪的效果,例如,我相信你知道在同一点上绘制多个标签时geom_文本的效果(无可否认,这也可能是由于渲染/抗锯齿问题,但我猜直线也是如此)。此外,到目前为止,我一直在努力绘制一个没有数据但尺寸完全相同的“空图”,这将需要仅绘制轴,然后先绘制数据。(对于那些希望轴位于点下方且不关心如何操作的人,另一种方法是提取桥层并重新绘制:
g,如果我们添加
theme(panel.background=element_rect(fill=NA))
对于绘图,轴不再部分模糊。这既证明了这是轴线变细的原因,也提供了合理的解决方法,前提是您不需要彩色面板背景。这很好,艾伦。我学到了很多,谢谢!
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)
}
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