user101089
user101089

Reputation: 3992

knitr .Rmd -> Word document: control details of figures

I'm producing a solutions manual for a book, using .Rmd files with the following YAML header:

---
title: "DDAR: Solutions and Hints for Exercises"
date: "`r Sys.Date()`"
output: 
  word_document:
    reference_docx: solutions-setup.docx
---

where I control the general layout of the document with the reference_docx to get an output Word document.

There will be many figures, and I'd like to set some global graphics parameters to give relatively tight bounding boxes and reasonable font sizes in the figures without having to tweak each one from what I see in a PDF document.

I tried the following, but the par() setting doesn't seem to have any effect:

{r setup, echo=FALSE} options(digits=4) par(mar=c(5,4,1,1)+.1)

Instead I get images like the following in my document with larger bounding boxes than I would like and with much larger font sizes than I would like.

sample image

I know how to control all this in .Rnw files produced with LaTeX, but I can't find how to do it in .Rmd -> Word. Is there a chunk hook I could use? I don't think that there is an out.width chunk option that re-scales a figure as in LaTeX.

Upvotes: 1

Views: 1805

Answers (2)

CL.
CL.

Reputation: 14957

@scoa's answer shows how to use a hook to set some graphical parameters at the beginning of each chunk. This is necessary because "by default, knitr opens a new graphics device to record plots and close it after evaluating the code, so par() settings will be discarded", i.e. graphical parameters for later chunks cannot be set in an early setup-chunk but need to be set for each chunk separately.

If this behavior is not wanted, the package option global.par = TRUE can be used:

opts_knit$set(global.par = TRUE)

Finding the correct values for the margins is sometimes quite painful. In these cases, hook_pdfcrop can help. In all chunks where the option crop = TRUE, white margins will be removed. To apply this to all chunks, use

library(knitr)
knit_hooks$set(crop = hook_pdfcrop)
opts_chunk$set(crop = TRUE)

This works for docx output as well because "when the plot format is not PDF (e.g. PNG), the program convert in ImageMagick is used to trim the white margins" (from ?hook_pdfcrop).

Note that under some circumstances, cropping plots has the side effect of sometimes apparently different "zoom" factors of plots: This happens in cases where we start with identical sized elements on two plots but larger white margins around one of the plots. If then both are resized to a fixed output width after cropping, elements on the plot with larger margins look larger. However, this is not relevant for docx output because out.width/out.height cannot be used in that case.

Upvotes: 4

scoa
scoa

Reputation: 19867

The knitr documentation for hooks actually uses small margins as an example of what you can do with hooks. Here is a solution (adapted from this documentation).

---
output: word_document
---

```{r setup, echo=FALSE}
library(knitr)
knit_hooks$set(small.mar = function(before, options, envir) {
    if (before)    par(mar=c(5,4,1,1)+.1)  # smaller margin on top and right
})
opts_chunk$set(small.mar=TRUE)
```

```{r}
plot(iris$Sepal.Length)
```

Using opts_chunk$set(small.mar=TRUE) is a way to avoid passing it to every chunk in the document.

The margin appears fixed (screenshot from the docx output in libreoffice with default reference-docx).

enter image description here

Upvotes: 2

Related Questions