7
votes

I have a figure that looks like this:

<<foo, fig.lp='', fig.cap='name', fig.subcap=c('left', 'right'),>>=
plot1
plot2
@

Now I would like to display a set of notes about this figure right below (i.e. a multiline text). Is there any convenient way to do this within the figure environment created by knitr?


As already pointed out in the comments above, there is currently no solution to my problem. I have filed a feature request.

3
what's wrong with the caption, sub caption, or just writing text below the figures?rawr
Text should go in addition to caption (like tablenotes in a table).JBDonges
To be more precise: Caption doesn't work because I might decide to shift around the captions, but I still want the notes be right under the figure. Sub caption doesn't work for the same reason. Writing text below the figure doesn't work, because when the figure moves, there is no guarantee that the figure and text will stay together (in LaTeX).JBDonges
You are up to something like this, right? As knitr offers no built-in way to add stuff inside the figure environment, my guess is that you will have to hide the figure (fig.show = "hide") and the include it manually, along with the desired LaTeX markup.CL.
You can file a feature request. But then I'd recomment not to use wordings like "it's a shame", but rather "It would be a valuable feature ... because ...".CL.

3 Answers

5
votes

I know this is a really late answer but here is what I ended up doing for the same type of a problem.

I defined a custom hook that would plot the image as I want it

# Custom knitr hook to add notes to the plot
knit_hooks$set(plot = function(x, options) {
  paste("\n\\end{kframe}\n\\begin{figure}\n",
        "\\includegraphics[width=\\maxwidth]{",
        opts_knit$get("base.url"), paste(x, collapse = "."),
        "}\n",
        "\\textsc{Note} -- here is some car stuff with notes",
        "\\caption{", options$fig.cap, "}\n",
        "\n\\end{figure}\n\\begin{kframe}\n",
        sep = '')
})

Here is the full .Rnw

\documentclass{article}

\usepackage[font=large,labelfont=sc]{caption}

\begin{document}

<<setup, echo=FALSE, message=FALSE, results='hide'>>=
suppressPackageStartupMessages({
  library(ggplot2)
})

opts_chunk$set(echo=FALSE)
opts_chunk$set(results="hide")
@

<<foo, fig.cap='with notes', fig.height=4, fig.width=6>>=
# save a regular plotting function
regular_plot <- knit_hooks$get("plot")

# Custom knitr hook to add notes to the plot
knit_hooks$set(plot = function(x, options) {
  paste("\n\\end{kframe}\n\\begin{figure}\n",
        "\\includegraphics[width=\\maxwidth]{",
        opts_knit$get("base.url"), paste(x, collapse = "."),
        "}\n",
        "\\textsc{Note} -- here is some car stuff with notes",
        "\\caption{", options$fig.cap, "}\n",
        "\n\\end{figure}\n\\begin{kframe}\n",
        sep = '')
})

ggplot(data = mtcars) + geom_point(aes(disp,mpg))
@

<<bar, fig.cap='without notes', fig.height=4, fig.width=6>>=
# restore regular plotting function
knit_hooks$set(plot = regular_plot)

ggplot(data = mtcars) + geom_point(aes(disp,mpg))
@

\end{document}

and here is the resulting PDF:

enter image description here

2
votes

akhmed answer was absolutely amazing!

I made an slighly modification for Rmd to get caption first and to generalize for every chunk in the document.

We have to add these lines at the beginning:

knit_hooks$set(plot = function(x, options, .notes = notes, .sources = sources) {
  paste("\n\n\\begin{figure}\n",
        "\\includegraphics[width=\\maxwidth]{",
        opts_knit$get("base.url"), paste(x, collapse = "."),
        "}\n",
        "\\caption{",options$fig.cap,"}","\\label{fig:",opts_current$get("label"),"}","\\textsc{}",
        "\n\\textsc{Notas} -- ",.notes,
        "\n\\textsc{Fuentes} -- ", .sources,
        "\n\\end{figure}\n",
        sep = '')
})

Then in every chunk we only write the notes and sources of the plot

notes = "Notes to explain the plot"
sources = "Explain the sources"

Again, thanks a lot akhmed!!

Pd: I use "\\textsc{}" to generate an space among caption and notes & sources.

It would be nice to generalize this to use subcaptions with many figures in the same plot.

1
votes

The solution from @akhmed was enormously helpful for me. I needed to make a few additional customizations which I pass along as an answer (it was too long for a comment).

  • First, I wanted a little more control over the margins for the note and found adding the minipage environment helped (\\begin{minipage} below set at 6 inches wide).
  • Second, I added a couple of minor formatting additions by setting a typeface size and left justifying the text (\\small and \\begin{flushleft} below).

  • Finally, for some figures, I wanted to use the fig.pos="h!" or figure position = "here" option of Knitr / Latex and it took me a minute to realize that this hook overwrites that chunk option so I manually added it as \\begin{figure}[h!].

Again, my thanks to @akhmed for offering this solution.

knit_hooks$set(plot = function(x, options) {
    paste("\n\\end{kframe}\n\\begin{figure}[h!]\n",
      "\\includegraphics[width=\\maxwidth]{",
      opts_knit$get("base.url"), paste(x, collapse = "."),
      "}\n",
      "\\begin{minipage}{6in}\\small\\begin{flushleft}Note: Lorem ipsum \\end{flushleft}\\end{minipage}",
      "\\caption{", options$fig.cap, " \\label{", options$fig.lp, opts_current$get("label"), "}}\n",
      "\n\\end{figure}\n\\begin{kframe}\n",
      sep = '')
    })