How to make a PDF using bookdown including SVG images
Asked Answered
V

3

9

I have some R markdown that includes the following code:

```{r huff51, fig.show='hold', fig.cap='Design decisions connecting research purpose and outcomes [@huff_2009_designingresearchpublication p. 86].', echo=FALSE}

knitr::include_graphics('images/Huff-2009-fig5.1.svg')
```

When using bookdown to produce HTML output everything works as expected.

When using bookdown to produce PDF output I get an error saying ! LaTeX Error: Unknown graphics extension: .svg.

This is understandable as knitr uses Latex's \includegraphics{images/Huff-2009-fig5.1.svg} to include the image. So, it's not a bug per se.

Is there a better way to include the SVG image so I don't need to pre-process it into, say, a PDF or PNG?

Vicar answered 4/5, 2018 at 0:12 Comment(0)
S
3

You can create a helper function to convert SVG to PDF. For example, if you have the system package rsvg-convert installed, you may use this function to include SVG graphics:

include_svg = function(path) {
  if (knitr::is_latex_output()) {
    output = xfun::with_ext(path, 'pdf')
    # you can compare the timestamp of pdf against svg to avoid conversion if necessary
    system2('rsvg-convert', c('-f', 'pdf', '-a', '-o', shQuote(c(output, path))))
  } else {
    output = path
  }
  knitr::include_graphics(output)
}

You may also consider R packages like magick (which is based on ImageMagick) to convert SVG to PDF.

Selfcontradiction answered 8/5, 2019 at 15:54 Comment(5)
To avoid converting files each time, I took the rsvg-convert out of the R code and into a Makefile, which I then invoke through a bash block in the RMarkdown. Make will only re-build if the svgs have changed since the pdfs were last built, so it's a nice way to speed the knitting execution time.Istanbul
@Istanbul nice - do you also launch the knitting from make?Thormora
@Thormora - no, I wasn't. And this was a long time ago! If you're considering doing this now (2022) you may want to take a look at the targets package, which is a native R alternative for make.Istanbul
@Istanbul - targets looks interesting. Does it play nicely with external tools? For example, launch a latex/tikz generation of a figure to both svg and pdf?Thormora
@Thormora - haven't investigated that farIstanbul
W
4

An update to Yihui Xie 's answer in '22. The package you want is now rsvg and the code looks like:

show_fig <- function(f)
  {if (knitr::is_latex_output())
  {
    output = xfun::with_ext(f, 'pdf')
    rsvg::rsvg_pdf(xfun::with_ext(f,'svg'), file=output)
  } else {
    output = xfun::with_ext(f, 'svg')
  }
  knitr::include_graphics(output)
}

Then you can add inline code to your text with

`r show_fig("image_file_name_no_extension")`

knitr v 1.39, rsvg v 2.3.1

Washboard answered 28/7, 2022 at 21:50 Comment(2)
Thanks! This is definitely a better answer than mine. I hope the OP could accept this one instead of mine.Selfcontradiction
This only kind of worked for me. It showed the SVG without any of the text in it: axes, title.Batson
S
3

You can create a helper function to convert SVG to PDF. For example, if you have the system package rsvg-convert installed, you may use this function to include SVG graphics:

include_svg = function(path) {
  if (knitr::is_latex_output()) {
    output = xfun::with_ext(path, 'pdf')
    # you can compare the timestamp of pdf against svg to avoid conversion if necessary
    system2('rsvg-convert', c('-f', 'pdf', '-a', '-o', shQuote(c(output, path))))
  } else {
    output = path
  }
  knitr::include_graphics(output)
}

You may also consider R packages like magick (which is based on ImageMagick) to convert SVG to PDF.

Selfcontradiction answered 8/5, 2019 at 15:54 Comment(5)
To avoid converting files each time, I took the rsvg-convert out of the R code and into a Makefile, which I then invoke through a bash block in the RMarkdown. Make will only re-build if the svgs have changed since the pdfs were last built, so it's a nice way to speed the knitting execution time.Istanbul
@Istanbul nice - do you also launch the knitting from make?Thormora
@Thormora - no, I wasn't. And this was a long time ago! If you're considering doing this now (2022) you may want to take a look at the targets package, which is a native R alternative for make.Istanbul
@Istanbul - targets looks interesting. Does it play nicely with external tools? For example, launch a latex/tikz generation of a figure to both svg and pdf?Thormora
@Thormora - haven't investigated that farIstanbul
C
0

For bookdown, I really don't like having PDF files on my websites. So I use this code:

if (knitr::is_html_output()) {
  structure("images/01-02.svg", class = c("knit_image_paths", "knit_asis"))
} else {
  # do something for PDF, e.g. an actual PDF file if you have one,
  # or even use Yihui's code in the other answer
  knitr::include_graphics("images/01-02.pdf")
}

It uses the SVG file for websites (i.e., HTML output).

It works perfectly for generating everything: website, gitbook, pdfbook and epub.

To prevent adding this code to every chunk in your bookdown project, add this to index.Rmd:

insert_graphic <- function(path, ...) {
  if (knitr::is_html_output() && grepl("[.]svg$", basename(path), ignore.case = TRUE)) {
    structure(path, class = c("knit_image_paths", "knit_asis"))
  } else {
    knitr::include_graphics(path, ...)
  }
}
Cartouche answered 16/9, 2021 at 12:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.