Skip to content

[R-pkg-devel] R CMD BATCH plot output

8 messages · Josiah Parry, Duncan Murdoch, Ben Bolker +2 more

#
Hey folks! I am working with R CMD BATCH and providing a providing a
logfile output e.g.

R CMD BATCH main.R 2024-07-28.log

This creates the desired log file with the contents of stdout and stderr.

However, if plots are generated in the process, the plots are stored in
Rplots.pdf.

Is there a way via command line arguments to change the name of the pdf
output.

There might be multiple runs of this script and it would be ideal to store
the plot output independently.
#
On 2024-07-28 1:48 p.m., Josiah Parry wrote:
That's the default filename if you open a PDF device.  Open it 
explicitly and you can specify any file you like.

That is,

   plot(rnorm(100))

will call dev.new() which in a non-interactive session calls pdf().  If 
you specify

   dev.new(file = "something.pdf")
   plot(rnorm(100))

the "file" argument will be ignored in an interactive session, but will 
be used in a non-interactive one.

Duncan Murdoch
#
Thanks, Duncan!

Is there a way to override this using the command line arguments?

I'd like to be able to have a generalizable way to address this without
having to modify R source code.

My understanding is that when there is a plot output, R CMD BATCH uses the
PDF device which is a fair default.

However, there is not any use of `dev.new()` or `pdf()` called anywhere in
the code.

On Sun, Jul 28, 2024 at 3:44?PM Duncan Murdoch <murdoch.duncan at gmail.com>
wrote:

  
  
#
Dirk Eddelbuettel would tell you to use his 'little r' script instead,
though not sure if it has this particular flexibility. You could wrap R CMD
BATCH in your own script that moved Rplots.pdf where you wanted it ...
On Sun, Jul 28, 2024, 4:05 PM Josiah Parry <josiah.parry at gmail.com> wrote:

            

  
  
#
On 2024-07-28 4:05 p.m., Josiah Parry wrote:
I assume you could do that using commandArgs() in the dev.new() call, 
but I don't use BATCH.
Take a look at the source to dev.new().  It tries various things, maybe 
one of those will suit you.
Not explicitly, but if you try to call a plot function with no device 
active, the graphics system will call dev.new().

Duncan Murdoch
#
On 28 July 2024 at 15:44, Duncan Murdoch wrote:
| On 2024-07-28 1:48 p.m., Josiah Parry wrote:
| > However, if plots are generated in the process, the plots are stored in
| > Rplots.pdf.
| > 
| > Is there a way via command line arguments to change the name of the pdf
| > output.
| > 
| > There might be multiple runs of this script and it would be ideal to store
| > the plot output independently.
| 
| That's the default filename if you open a PDF device.  Open it

It's the default (and fallback) device and filename you fail to specify
something else. Ie 'Rscript -e "plot(1:10)"' will create it too.

My preferred alternative is to wrap call to plot() with actual device create
(something like 'if (!interactive()) pdf(my_filename, 8. 6)' with a
corresponding 'if (!interactive()) dev.off()' to ensure the file finalised
and close.

If we cannot (or do not want to) modify the given main.R, I would suggest
something along the lines of

  Rscript -e 'pdf(myfilenamevar); source("main.R"); dev.off()' | tee 2024-07-28.log

and Bob's your uncle now in terms of how you spec the filename.

In short, I would let go of `R CMD BATCH` if it does not do what you want.

Dirk
#
On Sun, 28 Jul 2024 15:27:33 -0500
Dirk Eddelbuettel <edd at debian.org> wrote:

            
Perhaps even options(device = \(file = myfilenamevar, ...) pdf(file =
file, ...)) so that every plot would get the same treatment, though
that requires re-implementing the dev.new() logic to guess an available
file name. You can even misuse R_PROFILE_USER to inject the code into
the R CMD BATCH session:

# myplots.R:
local({
	cmdline <- commandArgs(FALSE)
	srcfile <- cmdline[[which(cmdline == '-f')[[1]] + 1]]
	plotfile <- sub('(\\.R)?$', '', srcfile)
	options(device = \(file, ...) {
		i <- 1
		if (missing(file)) repeat {
			file <- sprintf('%s_%03d.pdf', plotfile, i)
			if (!file.exists(file)) break
			i <- i+1
		}
		pdf(file = file, ...)
	})
})

# example.R:
plot(1:100 / 10, sin(1:100 / 10))
dev.off()
plot(1:100 / 10, cos(1:100 / 10))

R_PROFILE_USER=myplots.R R CMD BATCH example.R
# produces example.Rout, example_001.pdf, example_002.pdf
#
On 29 July 2024 at 13:02, Ivan Krylov wrote:
| On Sun, 28 Jul 2024 15:27:33 -0500
| Dirk Eddelbuettel <edd at debian.org> wrote:
| 
| > If we cannot (or do not want to) modify the given main.R, I would
| > suggest something along the lines of
| > 
| >   Rscript -e 'pdf(myfilenamevar); source("main.R"); dev.off()' | tee
| > 2024-07-28.log
| 
| Perhaps even options(device = \(file = myfilenamevar, ...) pdf(file =
| file, ...)) so that every plot would get the same treatment, though
| that requires re-implementing the dev.new() logic to guess an available
| file name. You can even misuse R_PROFILE_USER to inject the code into
| the R CMD BATCH session:
| 
| # myplots.R:
| local({
| 	cmdline <- commandArgs(FALSE)
| 	srcfile <- cmdline[[which(cmdline == '-f')[[1]] + 1]]
| 	plotfile <- sub('(\\.R)?$', '', srcfile)
| 	options(device = \(file, ...) {
| 		i <- 1
| 		if (missing(file)) repeat {
| 			file <- sprintf('%s_%03d.pdf', plotfile, i)
| 			if (!file.exists(file)) break
| 			i <- i+1
| 		}
| 		pdf(file = file, ...)
| 	})
| })
| 
| # example.R:
| plot(1:100 / 10, sin(1:100 / 10))
| dev.off()
| plot(1:100 / 10, cos(1:100 / 10))
| 
| R_PROFILE_USER=myplots.R R CMD BATCH example.R
| # produces example.Rout, example_001.pdf, example_002.pdf

Impressive. A very creative way to inject a modification into the (to my
taste overly restrictive) setup provided by R CMD BATCH.

Personally I would much rather script something cleaner with r or Rscript but
we all have our preferences.

Dirk