Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot2 - custom grob over axis lines

Tags:

I'm trying to generate an axis line break in ggplot2 (with a white segment over the axis lines) and I'm having some trouble.

Using the informative post annotate-ggplot-with-an-extra-tick-and-label I was able to generate the custom grobs in given location, while also turning the panel off to "draw" outside of the plotting area.

I'm also familiar with other packages such as plotrix and am able to replicate broken axis in base, but more than anything I'm interested in learning why the axis grobs I'm creating aren't overwriting the line. Here is some sample code:

library(ggplot2) # devtools::install_github("hadley/ggplot2")
library(grid)
library(scales)


data("economics_long")
econ <- economics_long
econ$value01 <- (econ$value01/2)
x <- ggplot(econ, aes(date, value01,group=1)) + scale_y_continuous(labels=c(0.0,0.1,0.2,0.3,0.4,0.5,1.0), breaks=c(0.0,0.1,0.2,0.3,0.4,0.5,0.6),limits = c(0,.6),expand = c(0, 0)) +
  geom_smooth(colour="deepskyblue", show.legend = TRUE ) + theme_bw()

theme_white <- theme(panel.background=element_blank(),
                     panel.border=element_rect(color="white"),
                     plot.margin = unit(c(.2, 0, .2, .2), "cm"),
                     panel.grid.major.y=element_blank(),
                     panel.grid.major.x=element_blank(),
                     panel.grid.minor.x=element_blank(),
                     panel.grid.minor.y=element_blank(),
                     axis.title.y = element_blank(),
                     axis.line.x=element_line(color="gray", size=1),
                     axis.line.y=element_line(color="gray", size=1),
                     axis.text.x=element_text(size=12),
                     axis.text.y=element_text(size=12),
                     axis.ticks=element_line(color="gray", size=1),
                     legend.position="none"
)
x <- x + theme_white


gline = linesGrob(y = c(0, 1.5),x = c(-.015, .015),  gp = gpar(col = "black", lwd = 2.5)) 
gline2 = linesGrob(y = c(-0.25, 0.5),x = c(0, 0),  gp = gpar(col = "red", lwd = 5))

p = x + annotation_custom(gline, ymin=.55, ymax=.575, xmin=-Inf, xmax=Inf) + 
  annotation_custom(gline, ymin=.525, ymax=.55, xmin=-Inf, xmax=Inf) +
  annotation_custom(gline2, ymin=.55, ymax=.575, xmin=-Inf, xmax=Inf)

# grobs are placed under the axis lines....

g = ggplotGrob(p)
g$layout$clip[g$layout$name=="panel"] <- "off"
grid.draw(g)

Which creates this image: enter image description here

I'm curious why the annotation_custom grobs are placed under the axis lines and whether there is a better solution to adding custom grobs using ggplot2. There appears to be an order in which graphics are placed in the plotting windows - how might this be alternated so that the custom grobs are placed after the axis lines?

like image 555
Michael Lee Avatar asked Sep 27 '16 20:09

Michael Lee


1 Answers

You were close. The layout data frame is were you turned off clipping. There is another column in the layout data frame that gives the order in which the various plot elements are drawn - z. The plot panel (including the annotation) is drawn second (after the background), then later the axes are drawn. Change the value of z for the plot panel to something larger than the z values for the axes.

library(ggplot2) # devtools::install_github("hadley/ggplot2")
library(grid)
library(scales)


data("economics_long")
econ <- economics_long
econ$value01 <- (econ$value01/2)


x <- ggplot(econ, aes(date, value01,group=1)) + scale_y_continuous(labels=c(0.0,0.1,0.2,0.3,0.4,0.5,1.0), breaks=c(0.0,0.1,0.2,0.3,0.4,0.5,0.6),limits = c(0,.6),expand = c(0, 0)) +
  geom_smooth(colour="deepskyblue", show.legend = TRUE ) + theme_bw()

theme_white <- theme(panel.background=element_blank(),
                     panel.border=element_rect(color="transparent"),
                     plot.margin = unit(c(.2, 0, .2, .2), "cm"),
                     panel.grid.major.y=element_blank(),
                     panel.grid.major.x=element_blank(),
                     panel.grid.minor.x=element_blank(),
                     panel.grid.minor.y=element_blank(),
                     axis.title.y = element_blank(),
                     axis.line.x=element_line(color="gray", size=1),
                     axis.line.y=element_line(color="gray", size=1),
                     axis.text.x=element_text(size=12),
                     axis.text.y=element_text(size=12),
                     axis.ticks=element_line(color="gray", size=1),
                     legend.position="none"
)
x <- x + theme_white


gline = linesGrob(y = c(0, 1.5),x = c(-.015, .015),  gp = gpar(col = "black", lwd = 2.5)) 
gline2 = linesGrob(y = c(-0.25, 0.5),x = c(0, 0),  gp = gpar(col = "red", lwd = 5))

p = x + annotation_custom(gline, ymin=.55, ymax=.575, xmin=-Inf, xmax=Inf) + 
  annotation_custom(gline, ymin=.525, ymax=.55, xmin=-Inf, xmax=Inf) +
  annotation_custom(gline2, ymin=.55, ymax=.575, xmin=-Inf, xmax=Inf)

# grobs are placed under the axis lines....

g = ggplotGrob(p)
g$layout$clip[g$layout$name=="panel"] <- "off"

g$layout  # Note that z for panel is 1.  Change it to something bigger.

g$layout$z[g$layout$name=="panel"] = 17    

grid.newpage()
grid.draw(g)
like image 63
Sandy Muspratt Avatar answered Oct 11 '22 08:10

Sandy Muspratt