3

I'm using knitr for my analysis. I can save graphs in PDF format with \SweaveOpts{dev=pdf} and in PNG format with \SweaveOpts{dev=png}. I'm interested to save graphs both in PDF and PNG format in one run but to use the PDF in the final documents interactively.

How can I do this?

halfer
  • 19,824
  • 17
  • 99
  • 186
MYaseen208
  • 22,666
  • 37
  • 165
  • 309
  • Do you have multiple plots per chunk? If you do not, I can show you a simple approach via a chunk hook; if you do, I will need to change the internal code to allow multiple devices per chunk, e.g. by `dev=c('pdf', 'png')`. – Yihui Xie Mar 12 '12 at 01:14
  • Thanks @Yihui for your comment. Yes I do have multiple plots per chunk. – MYaseen208 Mar 12 '12 at 01:50
  • The answer below is a generic solution which does not require one plot per chunk, and I'll think about how to add native support in knitr for multiple devices; maybe this can be done in knitr 0.4. – Yihui Xie Mar 12 '12 at 02:13
  • That would be great. Thanks Yihui for your nice work. – MYaseen208 Mar 12 '12 at 02:14
  • OK, I have implemented the support for multiple devices now. See modified answer below. – Yihui Xie Mar 12 '12 at 07:07

1 Answers1

4

Here comes the real solution:

Knitr 0.3.9 starts to support multiple devices per chunk (for now, you have to install from GitHub); in your case, you can set the chunk option dev=c('pdf', 'png') to get both PDF and PNG files.


Here is a solution that uses ImageMagick to convert PDF files to PNG. Of course you have to install ImageMagick first, and make sure its bin directory is in PATH:

knit_hooks$set(convert = function(before, options, envir) {
  # quit if before a chunk or no figures in this chunk
  if (before || (n <- options$fig.num) == 0L) return()
  # only convert pdf files
  if (options$fig.ext != 'pdf') return()

  # use ImageMagick to convert all pdf to png
  name = fig_path()  # figure filename
  owd = setwd(dirname(name)); on.exit(setwd(owd))
  files = paste(basename(name), if (n == 1L) '' else seq(n), sep = '')
  lapply(files, function(f) {
    system(sprintf('convert %s.pdf %s.png', f, f))
  })
  NULL
})

Basically this hook is executed after a chunk and run convert foo.pdf foo.png on all PDF figures. You can use it like

<<test-png, convert=TRUE>>=
  plot(1); plot(2)
@

Or if you put all figures in a separate directory, you can run convert directly in that directory (i.e. do not have to call system() in R).

This is not an ideal solution but should work. To make use of R's native png() device, you need to answer my question in the above comment first.

Yihui Xie
  • 28,913
  • 23
  • 193
  • 419
  • 1
    Assuming working with `Rnw` file and generating pdf document: Is there an option to specify which files will be used to generate document? I have a rpeort with large amount of graphics and would like to prearep high and low resolution of it (ie. one using png and one pdf). – radek Nov 11 '13 at 15:05
  • 1
    @radek You can do this with LaTeX tricks: http://en.wikibooks.org/wiki/LaTeX/Importing_Graphics – Yihui Xie Nov 11 '13 at 18:43
  • Thanks for quick answer. I saw that the generated `tex` file doesn't specify extension of the graphics. Would something like `\DeclareGraphicsExtensions{.pdf}` produce report with pdf images only? Then - I still need to compile two separate tex documents - one with `pdf` option, one with `png`? – radek Nov 11 '13 at 20:13
  • 1
    @radek `\DeclareGraphicsExtensions` is the key. You can certainly automate it. Nothing can stop a brave programmer. You can post a new question if you want. – Yihui Xie Nov 11 '13 at 22:27