3

I'm having problems using grid.edit() from an Rscript. I'm using grid.edit() to increase the thickness of hollow points in the legend and chart. I took this from this post (Change thickness of a marker in ggplot2). Just looks way better IMO. I know that from source files and Rscripts you can get ggplot objects to plot using print(p), but I need to use grid.edit() so I'm not sure how to fix this. Working example below.

My R script called test.r

library(ggplot2)
library(grid)
library(gtable)

p <- ggplot(mtcars, aes(wt, mpg)) + geom_point(aes(shape = factor(cyl))) + scale_shape(solid = FALSE)
lwd = 2   # Set line width
g = ggplotGrob(p); dev.off()  # Get the plot grob
# Get the indices for the legend: t = top, r = right, ...
indices <- c(subset(g$layout, name == "guide-box", select = t:r))
# Get the row number of the legend in the layout
rn <- which(g$layout$name == "guide-box")
# Extract the legend
legend <- g$grobs[[rn]]
# Get the legend keys
pointGrobs = which(grepl("points", legend$grobs[[1]]$grobs))
# Check them out - no line width set
# for (i in pointGrobs) str(legend$grobs[[1]]$grobs[[i]])
# Set line width
for (n in pointGrobs) legend$grobs[[1]]$grobs[[n]]$gp$lwd = lwd
# Check them out - line width set
# for (i in pointGrobs) str(legend$grobs[[1]]$grobs[[i]])
# Put the modified legend back into the plot grob
g$layout$clip[g$layout$name == "panel"] <- "off"
g = gtable_add_grob(g, legend, t=indices$t, l=indices$l)
###g$grobs[[4]]$children[[2]]$gp$lwd = gpar(lwd = lwd)  # Alternative for setting lwd for points in the plot
grid.newpage()
grid.draw(g)
grid.edit("geom_point.points", grep = TRUE, gp = gpar(lwd = lwd))

dev.print(cairo_pdf,filename="Aplot.pdf",
 width=11, 
height=8.5)

My batch file.

...\R-3.2.3\bin\x64\Rscript.exe test.r
PAUSE

The script runs and I get the follow error.

Error in editDLfromGPath(gPath,specs,strict,grep,global,redraw):
    'gPath' (geom_point.points) not found
Calls: grid.edit -> editDLfromGPath
Execution halted

Additionally a PDF is printed to my working directory called Rplots. This plot is the default size and interestingly the points in the legend are thick but the points in the plot are not. It appears that the script fails at grid.edit() but grid.draw() succeeds.

Community
  • 1
  • 1
CCurtis
  • 1,770
  • 3
  • 15
  • 25
  • I've built an Rscript to batch process data and produce a set of graphs. I want to distribute this to other people in my office that don't know R. Anyone with a connection to a network drive could run the script from their local computer and the script would process files in the batch file directory. Could I use Rterm and create an Rprofile that ran the commands directly or used `source()` at the beginning of the R session to get the same result, or will using `source()` run into the same problems? – CCurtis Mar 12 '16 at 00:29
  • 1
    Try this: Add `grid.force()` immediately before the `grid.edit(....` line. `grid.force()` makes the grobs visible to grid's editing functions. Without `grid.force()`, the editing functions see just one grob. – Sandy Muspratt Mar 12 '16 at 06:09
  • It got rid of the error but the output in the same. Doesn't seem like grid.edit is doing its job. Thanks, useful to know. I think I might try building a shiny app. – CCurtis Mar 12 '16 at 23:39
  • It works for me. I'm using ggplot2 v2.1.0 and gtable v0.2.0. – Sandy Muspratt Mar 12 '16 at 23:46
  • I'll post an answer. – Sandy Muspratt Mar 13 '16 at 00:10

1 Answers1

6

You need to grid.force() the plot so that grid editing functions can see all the grobs. I've increased the point size and the line width multiplier so that it is obvious that the edit has taken effect.

library(ggplot2)
library(grid)
library(gtable)

p <- ggplot(mtcars, aes(wt, mpg)) + geom_point(aes(shape = factor(cyl)), size = 5) + scale_shape(solid = FALSE)
lwd = 3   # Set line width
g = ggplotGrob(p); dev.off()  # Get the plot grob
# Get the indices for the legend: t = top, r = right, ...
indices <- c(subset(g$layout, name == "guide-box", select = t:r))
# Get the row number of the legend in the layout
rn <- which(g$layout$name == "guide-box")
# Extract the legend
legend <- g$grobs[[rn]]
# Get the legend keys
pointGrobs = which(grepl("points", legend$grobs[[1]]$grobs))
# Check them out - no line width set
# for (i in pointGrobs) str(legend$grobs[[1]]$grobs[[i]])
# Set line width
for (n in pointGrobs) legend$grobs[[1]]$grobs[[n]]$gp$lwd = lwd
# Check them out - line width set
# for (i in pointGrobs) str(legend$grobs[[1]]$grobs[[i]])
# Put the modified legend back into the plot grob
g$layout$clip[g$layout$name == "panel"] <- "off"
g = gtable_add_grob(g, legend, t=indices$t, l=indices$l)
###g$grobs[[4]]$children[[2]]$gp$lwd = gpar(lwd = lwd)  # Alternative for setting lwd for points in the plot
grid.newpage()
grid.draw(g)

grid.ls()
grid.ls(grid.force())  # Note the difference here

grid.force()
grid.edit("geom_point.points", grep = TRUE, gp = gpar(lwd = lwd))


# Or to edit the grob (rather than edit on screen)
g = editGrob(grid.force(g), "geom_point.points", grep = TRUE, gp = gpar(lwd = lwd))
grid.newpage()
grid.draw(g)

# To give it a print method
print.ggplotgrob <- function(x) {
   grid.newpage()   
   grid.draw(x)
}
class(g) = c("ggplotgrob", class(g)) 

g

enter image description here

My sessionInfo()

R version 3.2.3 (2015-12-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

locale:
[1] LC_COLLATE=English_Australia.1252  LC_CTYPE=English_Australia.1252   
[3] LC_MONETARY=English_Australia.1252 LC_NUMERIC=C                      
[5] LC_TIME=English_Australia.1252    

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
[1] Cairo_1.5-9   gtable_0.2.0  ggplot2_2.1.0

loaded via a namespace (and not attached):
[1] labeling_0.3     colorspace_1.2-6 scales_0.4.0     plyr_1.8.3      
[5] tools_3.2.3      Rcpp_0.12.3      digest_0.6.9     munsell_0.4.3
Sandy Muspratt
  • 31,719
  • 12
  • 116
  • 122
  • Nailed it! Guess i gave up to early. Works great. For some reason once I applied this to my actual charts providing a print method didn't work and it was necessary to use `grid.newpage` and `grid.draw but no complaints here. Very happy to get this working. Thank you very much. – CCurtis Mar 14 '16 at 21:50
  • It could be to do with the version of ggplot2. The print method will not work with older versions. – Sandy Muspratt Mar 14 '16 at 22:11
  • 1
    Ya its been several months since I've updated. Will have to do an update I guess. – CCurtis Mar 14 '16 at 22:41