make sure graphics device gets closed - r

I am closing the device (here: pdf() ) I am plotting to at the end of my function with dev.off(). However, if the function/loop terminates due to an error the device stays open. When a function gets repeatedly called, this can lead to quite a lot of open devices; and file handles.
How can I make sure the device gets closed even if the function fails?
I do remember that I once saw how to do this, but I cannot remember.

on.exit() is made for situations just like this. It's good practice to use it whenever opening a (file or other) connection in a non-interactive setting.
f <- function() {
pdf(tempfile()) # tempfile() so example doesn't clutter up working directory.
on.exit(dev.off())
plot(randomNonExistentObjectName)
}
f()
# Error in plot(randomNonExistentObjectName) :
# object 'randomNonExistentObjectName' not found
dev.list()
# NULL

Wrap your whole plotting expression into a tryCatch like so:
tryCatch(expr={pdf(...); plot(...)}, finally=dev.off())

Related

Error with on.exit(close(con)) with writeLines()

I’m writing a function for writing some information to file. To offer more options for fine control I’m first opening a connection before calling writeLines().
As it has been stated in many places (eg How and when should I use on.exit?) the function on.exit() may be very helpful to reset settings in case unforeseen events making functions stall.
I hope you agree, writing files can certainly be considered a somehow risky activity (eg no more disk space, …).
So I was thinking of charging on.exit() to make sure the connection gets closed if anything during writeLines() caused my function to stop with an error. However, when I do so I get an error right after writeLines() gets run !
Has anybody an explanation ?
The workarounds I found is a) don’t use on.exit() or b) add try(). But I wonder if the second option would realy be helpful if an unforeseen event would make writeLines() stall. Even checking if the connection is still open to avoid closing twice didn't help.
Surprisingly, so far I couldn't find other examples of people using on.exit() to make sure the current connection gets closed when/after writing text.
Here an example :
txt1 <- c("ABCDEF","abcdefgh")
fxWrite <- function(txt, fileName, opt=0, eol="\n") {
con <- file(fileName)
open(con, open="wb")
if(identical(opt,1)) on.exit(try(close(con), silent=TRUE), add=TRUE)
if(identical(opt,2)) on.exit(close(con), add=TRUE) # regular on.exit() call
writeLines(as.character(txt), con=con, sep=eol)
if(isOpen(con=con)) close(con)
}
fxWrite(txt1, "test1.txt", 0) # no on.exit()
fxWrite(txt1, "test2.txt", 1)
fxWrite(txt1, "test3.txt", 2) # regular on.exit(),
# with opt=2 the file gets written, BUT : Error in close.connection(con) : invalid connection

"Empty" graphics device to avoid opening new window with par

Consider the following:
dev.off()
dev.cur() # null device
par("las") # opens a new device
dev.cur() # default device
My problem is identical to the one described in this question, I do not want to open a new device but the library I'm calling has unavoidable calls to par(). Also, I'd prefer a better solution than the hack described there.
My idea for solving it was the following:
change options("device") via
options(device = function(){}) # WARNING CHRASHES R WHEN CALLING PAR()
so that no new device get's opened. However as the comment indicates, this chrashes R. My question is, what should I change options("device") to such that no new device get's opened, but also R doesn't chrash when calling par.

Sink does not release file

I know that the sink() function can be used to divert R output into a file, e.g.
sink('sink-closing.txt')
cat('Hello world!')
sink()
Is there a simple command to close all outstanding sinks?
Below, I elaborate on my question.
Suppose that my R-script opens a sink() in an R-script, but there is an error in the R-script which occurs before the script closes the sink(). I may run the R-script multiple times, trying to fix the error. Finally, I want to close all the sinks and print to the console. How do I do so?
Finally, in the interest of concreteness, I provide a MWE to illustrate the problem I face.
First, I write an R-script sink-closing.R which has an error in it.
sink('sink-closing.txt')
foo <- function() {
cat(sprintf('Hello world! My name is %s\n',
a.variable.that.does.not.exist))
}
foo()
sink()
Next, I source the R-script multiple times, say 3 times by mistake as I try to find and fix the bug.
> source('~/Dropbox/cookbook/r-cookbook/sink-closing.R')
Error in sprintf("Hello world! My name is %s\n", a.variable.that.does.not.exist) :
object 'a.variable.that.does.not.exist' not found
Now, suppose that I am debugging the R-script and want to print to the console. I can call sink() multiple times to close the earlier sinks. If I call it 3 times, then I can finally print to the console as before. But how do I know how many sinks I need to close?
closeAllConnections() # .........................
I'm getting upvotes for this as time goes along but Simon.S.A and others are better.
You can use sink.number() to tell you how many diversions are already set and then call sink that many times. Putting it into a function you could have this
sink.reset <- function(){
for(i in seq_len(sink.number())){
sink(NULL)
}
}
Based on #mnel's comment:
sinkall <- function() {
i <- sink.number()
while (i > 0) {
sink()
i <- i - 1
}
}
Should close all open sinks.
You may also encounter this problem when dealing with devices and plots, where the number of open devices isn't reported anywhere. For a more general case you could use this:
stopWhenError <- function(FUN) {
tryCatch({
while(TRUE) {
FUN()
}
}, warning = function(w) {
print("All finished!")
}, error = function(e) {
print("All finished!")
})
}
stopWhenError(sink) # for sink.
stopWhenError(dev.off) # close all open plotting devices.
EDIT:
sink throws a warning not an error so I've modified the code so that it won't run forever, whoops!
The most common time I experience this is when an error occurs preventing a sink from closing. For example, the following will leave an open sink after execution.
sink("output.txt")
my_function_that_will_error()
sink()
This can be avoided using on.exit(sink()). This will close the sink "when the current function exits (either naturally or as the result of an error)" (documentation here).
But you do have to change the order:
sink("output.txt")
on.exit(sink())
my_function_that_might_error()
So we create the sink, tell R to close it when it exits, and then execute the code that might error. This will close the sink regardless of whether the code errors or not.

Message within function (for status) not showing immediately in console

I have written a function, which takes some time to run (due to a 1000+ loop on a huge dataset in combination with forecasting model testing).
To have any idea on the status, while the function is called, I use the message command inside the for-loop in the function. The problem is that all the messages are shown in the console after the function is finished, instead of showing immediately. So it doesn't help me :)
I tried to find a solution on Stackoverflow, but didn't found one. I looked for instance on the question "showing a status message in R". All answers and example codes in that topic still give me only text in the console after a function is processed instead of immediately.
How to solve this? Is there maybe a setting in R which prevents immediate printing of message text in the console?
note: examples I tried below, which give the same results as my function; showing text after processing the function.
example1 (Joshua Ulrich):
for(i in 1:10) {
Sys.sleep(0.2)
# Dirk says using cat() like this is naughty ;-)
#cat(i,"\r")
# So you can use message() like this, thanks to Sharpie's
# comment to use appendLF=FALSE.
message(i,"\r",appendLF=FALSE)
flush.console()
}
example2 (Tyler):
test.message <- function() {
for (i in 1:9){
cat(i)
Sys.sleep(1)
cat("\b")
}
}
edit: the first example does work ('flush console' was the problem)...but when I tested it, I commented out flush console for some reason :S
test.message <- function() {
for (i in 1:9){
cat(paste(as.character(i),'\n'))
flush.console()
Sys.sleep(1)
}
}
which is similar to the recommendation by fotNelton.
Edit: ttmaccer is most likely right. I've just tested on a Ubuntu server and the code works without flushing the console.
I seem to think this maybe a windows specific problem. On linux or running R in a cygwin shell the flush.console() may not be needed.
You may be interested in using one of the progress bar functions (winProgressBar, tkProgressBar, or txtProgressBar). The win version only works on windows, but the win and tk versions have the advantage that they do not clutter your output, but rather open another small window and display the progress there.
The progress through a loop can be shown with the progress bar, but other detailed information can be updated and shown with the label argument.

Suppressing "null device" output with R in batch mode

I have a number of bash scripts which invoke R scripts for plotting things. Something like:
#!/bin/bash
R --vanilla --slave <<RSCRIPT
cat("Plotting $1 to $2\n")
input <- read.table("$1")
png("$2")
plot(as.numeric(input[1,]))
dev.off()
RSCRIPT
The problem is that despite --slave, the call to dev.off() prints the message null device 1. Once there are a lot of plots being done, or for more complex scripts which plot to a number of files, this gets to be a real hassle.
Is there some way to suppress this message?
For no good reason I'm aware of, dev.off(), unlike device related functions like png() returns a value: "the number and name of the new active device." That value is what's being echoed to stdout.
Suppressing it can thus be achieved by just putting it somewhere, i.e.,
garbage <- dev.off()
One of the nice things about R is that you can view the source of many functions:
> dev.off
function (which = dev.cur())
{
if (which == 1)
stop("cannot shut down device 1 (the null device)")
.Internal(dev.off(as.integer(which)))
dev.cur()
}
<environment: namespace:grDevices>
So it calls .Internal(dev.off(...)) and then returns dev.cur(), which I suppose would be useful if you have several devices open so you know which one became active. You could use .Internal(dev.off(as.integer(dev.cur()))) in your script, or even patch dev.off to only return the value of dev.cur() if it is something else than the null device, and send the patch to the maintainers of R.
Also, graphics.off() calls dev.off() for all devices and doesn't return anything.
Ran into the same issue recently and noticed that one more possibility is not mentioned in the answers here:
invisible(dev.off())
This will hide the output from dev.off() and will not create additional variables unlike assigning the output to garbage variable: garbage <- def.off() would.
Another option would be to use sink() and output everything to a log file, so you can check up on whether the plots worked if you need to.
You can use littler instead which is a) an easier way to write R 'scripts' and b) suppresses output so you get the side effect of dev.off being silent:
$ foo.r /tmp/foo.txt /tmp/foo.png
Plotting /tmp/foo.txt to /tmp/foo.png
$ cat /tmp/foo.r
#!/usr/bin/r
cat("Plotting", argv[1], "to", argv[2], "\n")
input <- read.table(argv[1])
png(argv[2])
plot(as.numeric(input[1,]))
dev.off()
$
Rscript will probably work too; I tend to prefer littler.

Resources