3

While SO is not usually used for help with bugs, this one shows particularly simple and particularly annoying behavior. If you are a ggplot2 user, you can reproduce it in 10 seconds or less.

As this GitHub issue: ggplot_gtable creates blank display says, the following code

library(ggplot2)
stat = qplot(Sepal.Length, Petal.Length, data = iris, color = Species)
ggplot_gtable(ggplot_build(stat))

will produce a blank device. Note that since ggplot2 is a graphics library, some commands can bring up a graphics device to show the relevant plot. Specifically, just running ggplot_build(stat) will bring up a plot. But that doesn't explain this behaviour.

I'm not sure how to debug this (print statements don't really seem appropriate or useful), and the ggplot2 development community seems to be on vacation or something, so if any experienced R user can offer suggestions on how to debug this effectively, I would appreciate it. This is a trivial but incredibly annoying bug. Every time I run code which looks like the snippet, it brings up a blank device which the display switches focus to, and so I have to click it away before I can continue.

It is possible that I'm doing something horribly wrong and am the only person who can reproduce this bug. It is also possible, for some reason I can't imagine, that this is normal behavior. If you think either of these things are true, please let me know.

I'm using ggplot2 0.9.3.1 (latest release) on Debian squeeze.

Faheem Mitha
  • 6,096
  • 7
  • 48
  • 83
  • what do you want to do with `ggplot_gtable(ggplot_build())`? (btw there's `ggplotGrob()`. My guess is that during the gtable creation, an open device is needed to resolve some kinds of grid units. – baptiste Jun 09 '13 at 18:36
  • Does not happen on OSX: 10.7.5 /R: 3.0.1/ggplot2_0.9.3.1 when called from the GUI 1.60 (6475), but it does happen when called within an R session started in Terminal.app – IRTFM Jun 09 '13 at 18:45
  • @baptiste: The definition of `ggplotGrob` is `ggplot_gtable(ggplot_build())`. I'm using to get my hands on the grob table. – Faheem Mitha Jun 09 '13 at 18:48
  • @DWin Thanks. That's useful information. So it is OS specific. – Faheem Mitha Jun 09 '13 at 18:48
  • Added info in the 5 minute window. Interface specific as it turns out. – IRTFM Jun 09 '13 at 18:49
  • @DWin Ok, I'll update the issue with this information. Thanks. – Faheem Mitha Jun 09 '13 at 18:51
  • Hmmm... I'm on OSX 10.8.3, R 3.0.1, R.gui 1.61 (6492) and ggplot2 0.9.3.1 and the blank page appears for me in both R.app and command line R. The venn diagram of everyone's observations must point to the answer somehow. Thanks Faheem for pursuing these issues. – Bryan Hanson Jun 09 '13 at 19:13
  • another observation: `stat2 = stat + guides(colour="none")` doesn't open a window. Something about grid units in the guides – baptiste Jun 09 '13 at 19:55
  • ... and indeed, `ggplot2:::guides_build` calls `widthDetails/heightDetails` which can require an open device: try this for instance, `library(grid); widthDetails(textGrob("hi"))`. – baptiste Jun 09 '13 at 20:02
  • @baptiste I see. The chain looks like `ggplot_gtable` -> `build_guides` ->`guides_build`. This does look like what is going on. I don't understand why it is necessary to open a device, though. Can you add an answer? The page for `widthDetails` and `heightDetails` don't say anything about opening a device. – Faheem Mitha Jun 09 '13 at 20:14

4 Answers4

5

Some grid grobs have units that can only be resolved at drawing time, that is to say once a device window is open. This is the case of text grobs, for instance, as their size can depend (in the most general case) of the cex and fontsize arguments of the parent(s) viewports (which can be nested, etc.)

library(grid)
widthDetails(textGrob("hi"))

The current version of ggplot2 appears to use widthDetails in the code to build the legend grobs (guides_build function). It is conceivable that this could be replaced by grobWidth, unless the grob size is too convoluted.

baptiste
  • 75,767
  • 19
  • 198
  • 294
  • Thanks. What would the advantage of `grobWidth` be? – Faheem Mitha Jun 09 '13 at 20:33
  • it doesn't open a window, apparently. But I never fully understood the difference between the two to be honest, probably only few others than Paul Murrell could tell for sure. – baptiste Jun 09 '13 at 21:16
  • `grobWidth` works fine in place of `widthDetails`, but `ggplot_gtable` eventually calls `height_cm` --> `grid::convertWidth` --> `grid::convertUnit`, the last of which requires an open device. – Matthew Plourde Aug 05 '14 at 15:02
2

I wonder if it is related to this thread from 3 years ago on R-Help with this workaround from @G.Grothendieck (copied material follows)

https://stat.ethz.ch/pipermail/r-help/2010-December/263754.html

library(lattice)
library(zoo)

df <- data.frame(y = matrix(rnorm(24), nrow = 6), x = 1:6)
xyplot(zoo(df[1:4], df$x), type = "p")

plot.object <- xyplot(zoo(df[1:4], df$x), type = "p") 
# problem: a Quartz device is opened (on Mac OS X 10.6)

Grothendieck wrote in response:

This also opens up a window on Windows. It occurs within lattice when lattice issues a trellis.par.get . A workaround would be to open a device directed to null. On Windows this would work. I assume if you use "/dev/null" it would work on your machine.

png("NUL")
plot.object <- ...
dev.off()
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • That's interesting. I wonder if such a thing would be an option here. @baptiste? Maybe add a link to the r-help thread? Gmane is what I usually link to. I reformatted your answer a bit - could you approve? Thanks. – Faheem Mitha Jun 09 '13 at 22:10
  • 1
    it doesn't feel very elegant, but I guess in some cases it's the only way to work around grid's idiosyncrasies. The preferred null device, I believe, is `pdf(file = NULL)`. – baptiste Jun 09 '13 at 22:57
  • Replaced original text with link to the (real) R-help Archive at `stat.ethz.ch`. I use MarkMail for search. – IRTFM Jun 09 '13 at 23:37
0

I am still having this issue with R 3.6.1 in 2019.

My lack of reputation doesn't allow me to comment. So I am writing yet another answer:

Things become a bit tricky if your plot uses non-standard fonts, say

library (ggplot2)
stat = qplot(Sepal.Length, Petal.Length, data = iris, color = Species) + 
  theme(text = element_text (family="DejaVu Sans"))

As was explained in the answer by baptiste, the output device is needed in order to determine some text dimensions. With the non-standard font, however, you need the appropriate output device. If you just use a pdf(file=NULL) as baptiste said, you get the dimensions wrong (and a warning that 'DejaVu Sans' was substituted by another font which is responsible for the false dimensions). In order to resolve this, I had to open an output device that is able to render the non-standard font (with a temporary file, say):

cairo_pdf (tempfile (fileext=".pdf"))
grob = ggplot_gtable (ggplot_build (stat))
dummy = dev.off ()

Hope this information is useful.

HPF
  • 185
  • 8
-1

Problem seems to be caused by "color = Species". If replaced by "group = Species", then no more blank display device.

  • 1
    Welcome. This isn't really an answer -- it is a comment. If you read the other (complete) answers, you will understand **why** `group = Species` does not cause a problem when `colour = Species` does. – mnel Aug 01 '13 at 06:15
  • @mnel Agreed. user2640757, please change this to a comment. Thanks. – Faheem Mitha Aug 01 '13 at 08:13