用grid和gtable拆解ggplot

时间:2015-01-03 01:12:39

标签: r ggplot2 gtable r-grid

我正在努力构建基于ggplot个对象的双轴绘图。在巴蒂斯特的建议下,我将问题分解为更小的部分。目前的问题是:

  1. 如何从grobs删除所有数据,同时保留轴,轴标签,轴标记和网格线?按'数据'我的意思是与geom_line()geom_points()相关联的数据。
  2. 想要这样做的原因是,在构建双轴绘图的过程中,我遇到了以下问题:来自一个grob的网格线将覆盖来自另一个grob的数据。通过删除数据线和点,就不会有覆盖。

    让我说清楚:我确实有一些解决方法,包括在aes()中添加线型并设置scale_linetype_manual(values = c(“solid”,“blank”),或者,从网格发送数据' ',但是我想对一个没有为了目的而过多修饰的情节对象进行后期处理。

    下面是一些代码和数据。

    # Data
    df <- structure(list(Year = c(1950, 2013, 1950, 2013), Country = structure(c(1L, 
    1L, 2L, 2L), .Label = c("France", "United States"), class = "factor"), 
    Category = c("Hourly minimum wage", "Hourly minimum wage", 
    "Hourly minimum wage", "Hourly minimum wage"), value = c(2.14, 
    9.43, 3.84, 7.25), variable = c("France (2013 euros)", 
    "France (2013 euros)", "United States (2013 dollars)", "United States (2013 dollars)"
    ), Unit = c("2013 euros", "2013 euros", "2013 dollars", "2013 dollars"
    )), .Names = c("Year", "Country", "Category", "value", "variable", 
    "Unit"), row.names = c(NA, 4L), class = "data.frame")
    
    # Plot data with ggplot
    library(ggplot2)
    p <- ggplot(data = df, aes(x = Year, y = value, group = variable, colour = variable, shape = variable)) + 
    geom_line(size = 2) + 
    geom_point(size = 4) +
    theme(panel.grid.major = element_line(size = 1, colour = "darkgreen"), 
          panel.grid.minor = element_line(size = 1, colour = "darkgreen", linetype = "dotted"))
    
    # Manipulate grobs with gtable
    library(gtable)
    g <- ggplot_gtable(ggplot_build(p))
    ## Here remove the geom_line() and geom_point()
    ## g <- stripdata(g)  # pseudo-code!
    grid.newpage()
    grid.draw(g)
    

    在下面的图中,我希望线条不见了!

    enter image description here

    编辑:按照baptiste的建议,我尝试删除数据层。但是,正如BondedDust在评论部分中指出的那样,这会破坏ggplot对象:

    # Remove the two layers of data
    p$layers[[1]] <- NULL
    p$layers[[1]] <- NULL
    g <- ggplot_gtable(ggplot_build(p))
    ## Error: No layers in plot
    

    从ggplot对象中删除数据会破坏它。我在应用程序中使用的一种解决方法是“从网格中发送数据”,例如将每个单元格乘以-999999并用+ scale_y_continuous(limits = c(1, 10))切断显示,但如果可行的话,我想避免这种丑陋的黑客攻击。如果我用NA或NULL替换每个数据点,我希望关联的gtable不会被破坏,这就是为什么我正在寻找一种方法从g对象内部而不是p对象中删除数据。

    在操纵grobs之后(而不是直接攻击ggplot对象),grid.draw(g)的结果将是:

    enter image description here

    仅供参考,第二个图是通过以下解决方法获得的。

    p <- ggplot(data = within(df, value <- -999999), aes(x = Year, y = value, group = variable, colour = variable, shape = variable)) + 
    geom_line() + 
    geom_point() +
    theme(panel.grid.major = element_line(size = 1, colour = "darkgreen"), 
          panel.grid.minor = element_line(size = 1, colour = "darkgreen", linetype = "dotted")) +
    scale_y_continuous(limits = c(1, 10))
    

1 个答案:

答案 0 :(得分:5)

更自然的策略是使用不可见的geom_blank图层,以便ggplot2仍然训练尺度等来构建图,但不显示数据。但是,由于您要处理已经格式化的绘图,因此您可能必须从绘图gTree中手动删除这些凹凸。这是一次尝试,

library(gtable)
g <- ggplotGrob(p)

stripdata <- function(g){
  keep <- grepl("border|grill", 
                names(g[["grobs"]][[4]][["children"]]))
  g[["grobs"]][[4]][["children"]][!keep] <- NULL
  g
}

grid.newpage()
grid.draw(stripdata(g))