%\VignetteEngine{knitr::knitr} %\VignetteIndexEntry{figr-showcase}

require(knitr, quietly=TRUE)
opts_chunk$set(message=FALSE, warning=FALSE, tidy=FALSE)

Showcase figr: a tour of the package

figr is designed to be a simple figure and table reference manager for markdown documents. The package provides automatic numbering of document elements (figures and tables) and allows you to cite, cross-reference (i.e. link) and label (i.e. caption) these elements. Functionality for inserting figures from external files is also provided.

The package is designed to be used with the knitr package and uses both markdown syntax and HTML tags to provide cross-referencing and within-document linking to figures and tables. knitr hooks are defined to allow anchoring and figure captioning via chunk options. The package is designed to be easily extendable to other distinct types of document elements, e.g. animations, videos or interactive objects (TODO: add referencing functionality for code chunks). This vignette provides a tour of the main features of figr.

Placing and referencing figures

We will first show how figr tracks figures in a document. First, create a plot as you would normally would in a knitr document. This is most easily done using the ggplot2 package:

require(ggplot2)
p = qplot(rnorm(500),geom="histogram")

Next, we index it using figr:

require(figr)
addFigure('normal', p, caption='500 draws from a normal distribution.')
# note that figr makes a copy of the plot object
rm(p)

A number has not been assigned to the figure yet. Using addFigure simply registers the plot with figr for future use. Registering the plot with figr allows you to place figures using labels, rather than requiring that you remember the variable name itself. This is analogous to \label{} in LaTeX.

figr provides cross-referencing capability using the HTML anchor (<a>) tag. figr defines a new knitr code chunk option, anchor, to write an anchor element to the document for rendering. A simplified definition of the anchor hook provided by figr is shown below. figr defines this hook when it is loaded so you do can immediately use the anchor option after loading figr.

knitr::knit_hooks$set(anchor = function(before, options, envir) {
    if (before) 
      paste('<a name="', options$anchor, '"></a>', sep='')
})

Note that the anchors are placed above the code chunk because we are using if(before) to specify that the hook is evaluated before the code chunk itself. (You can redefine the hook to place the anchor below the chunk by using if(!before) instead). We can automatically generate an anchor that will match a figure object using with anchorFigure(figure name).

You can place a figure and assign it a number with placeFigure(figure name) (as shown below) and simultaneously create an anchor for the plot. Note that the following code chunk includes the option anchor=anchorFigure('normal') in its header.

placeFigure('normal')

figr determines figure numbers by ranking them based on the order they are placed or cited in the document. When placeFigure is called, the referenced object is assigned a rank (if it does not have one already--see next paragraph). We can reference a figure, e.g. r citeFigure("normal") (I just did!) using citeFigure(figure name) in an inline code chunk. Note that anchoring also updates a figure rank, so the addFigure and placeFigure functions are not technically needed if you will not need to reproduce the figure again later (i.e. in an appendix).

Calling placeFigure() or citeFigure() a second time will not change the rankings. This is the result of code that allows a figure to be cited before it is placed. A figure is not ranked until it is placed, cited or anchored, so if for some reason you need to refer to a later figure you must cite or place any intervening figures first. Note that you can cite a figure before placing or even creating the figure:r invisible(citeFigure('lognormal'))

# you can also do this inline!
invisible(citeFigure('lognormal'))

Now we can reference the later plot, r citeFigure('gamma'), before placing the one we just invisibly cited (r citeFigure('lognormal')).

p2 = qplot(rlnorm(500), geom="histogram")
addFigure('lognormal', p2, '500 draws from a lognormal distribution.')
placeFigure('lognormal')

And now we'll place r citeFigure('gamma'):

p3 = qplot(rgamma(500, 3), geom='histogram')
addFigure('gamma', p3, '500 draws from a gamma distribution.')
placeFigure('gamma')

As you can see, placing, anchoring and referencing figures is straightforward. Note that due to the way knitr evaluates a document, automatic generation of a list of figures in the front matter of a document is not possible. However, it would be simple to write a function to generate a list of figures at the end of a document, or even write all referenced figures to the end matter of a document. If you are creating a document that requires a list of figures in the front matter of a document, you may want to consider using LaTeX instead of Markdown.

Adding figure captions

So far we have ignored figure captions. figr also defines a new knitr hook for adding captions to a figure. The hook definition is shown below, but you do not need to define this hook yourself as figr defines it on load.

knit_hooks$set(plot = function(x, options) {
  paste('<figure><img src="',
        knitr::opts_knit$get('base.url'), paste(x, collapse = '.'),
        '"><figcaption>', text=options$fig.cap, '</figcaption></figure>',
        sep = '')
})
opts_knit$set(eval.after='fig.cap')

Note that the hook definition allows the figure caption to be generated within the referenced code chunk thanks to the eval.after option. The fig.caption hook will likely be included in a future knitr release (> version 1.6).

A figure caption can be referenced using labelFigure(figure name) (recall that we defined the caption when we registered the figure using addFigure). an anchor link is placed within the caption itself; Having the link in the caption is not really useful, but it is nice for labelling consistency. In r citeFigure('chisquared') below, the chunk options fig.cap=labelFigure('chisquared') and anchor=anchorFigure('chisquared') are used.

addFigure('chisquared', qplot(rchisq(500, 3), geom='histogram'), 
          '500 draws from a Chi-squared distribution.')
placeFigure('chisquared')

Placing figures from external files

Placing an external image in a markdown document is straightforward from an HTML standpoint, but requires specific formatting to take advantage of the figr and knitr packages. Placing an external image as a figure is similar to placing an R plot object, but uses the function ExternalFigure instead of placeFigure. Furthermore, it requires that the code chunk results option is specified 'asis'. When adding an external image as a Figure using addFigure, the path to the file is specified instead of an R plot object in the call to addFigure. figr automatically copies or downloads this file into knitr's fig.path directory. In r citeFigure('external') below, the chunk options fig.cap=labelFigure('external'), anchor=anchorFigure('external'), and results='asis' are used.

# note that you can place other links in a caption using regular markdown syntax!
addFigure('external', 
          'http://upload.wikimedia.org/wikipedia/commons/5/5f/Pantheon_Rome_miniature_XV.jpg', 
          'an image from [Wikipedia](http://en.wikipedia.org/wiki/Piazza_della_Rotonda).')
ExternalFigure("external", caption=TRUE)

Note that when adding a caption to an external figure, labelFigure is called internally by placeTable when caption=TRUE (rather than being used through a code chunk option). externalFigure also accepts arguments for figure height and width, in inches (same units as knitr's fig.width and fig.height chunk options). If height or width are not specified, the knitr global settings are assumed.

Placing and referencing tables

figr provides identical functionality (e.g. addTable, citeTable, etc.) for kable objects, as shown by r citeTable('example'). Note that tables can have identical names to figures without risk of overwriting. Remember that when printing kable tables, the code chunk results must be specified 'asis'.

# note only the dataframe is passed to addTable
d = head(iris[,1:5])
addTable('example', d, 
caption='The first five rows of the [iris](http://stat.ethz.ch/R-manual/R-patched/library/datasets/html/iris.html) dataset.')
placeTable('example', caption=TRUE)

Note that table captioning is handled slightly differently, as the table caption is defined in the call to kable. A labelTable function is defined for symmetry with labelFigure but is called internally by placeTable when caption=TRUE, rather than being used through a code chunk option (similar to adding captions with externalFigure).

Citing code chunks

figr also enables you to cross-reference and anchor chunks. Chunks can be cited and anchored in the same manner as figures and tables using the citeChunk and addChunk functions. However, usershould consider the following when citing chunks:

  1. if you want to anchor both the chunk and any plots or figures produced in the chunk, you must concatenate the anchors into a single string (e.g. anchor=paste(anchorFigure('example'), anchorChunk('example'))). This means that multiple anchors will be indistinguishable. It may be preferable to split example code and outputs into separate chunks for anchoring.
  2. You cannot add a caption to a code chunk (there is no labelChunk function).
  3. A chunk must be anchored or cited in order to be ranked.

The third point can create some confusion when a user selectively anchors chunks. For example, r citeChunk('cite-chunk') below is clearly not the first chunk in the document, but it is the first cited chunk. However, anchored chunks are not visually distinguished from non-anchored chunks, which may make it difficult for users to refer to specific chunks when linking is not available. It may therefore be desirable to format anchored chunks differently from standard chunks. This could perhaps be achieved using some kind of frame, and using the term "blocks" to refer to anchored chunks.

An example of chunk anchoring is shown below. As an additional shortcut, passing the chunk option anchor=TRUE allows the user to anchor and register a chunk using its label option.

knit_hooks$set(anchor = function(before, options, envir) {
    if (before){ 
      if(is.character(options$anchor))
        paste('<a name="', options$anchor, '"></a>', sep='')
      else if(as.logical(options$anchor))
        paste('<a name="', anchorChunk(options$label), '"></a>', sep='')
    }
  })
  opts_chunk$set(anchor=FALSE)
# You can cite chunks even if they are not evaluated
# label = 'cite-chunk'
paste(opts_current$get('label'), '   ', opts_current$get('anchor'))

Referencing a chunk that references another chunk using the ref.label chunk option is equivalent to the expected behavior of a placeChunk function. Chunks that refer to other chunks (like r citeChunk('refer-chunk')) are given their own rank. Note that r citeChunk('refer-chunk') uses the options ref.label='cite-chunk' and anchor=anchorChunk('refer-chunk').


Beware that there are no checks for whether an anchored chunk is evaluated or even echoed. Anchoring non-echoed chunks will be cause them to be ranked and an anchor to appear where the code block would be placed if echo=TRUE. The definition of the anchor hook is shown in r citeChunk('redefine-anchor'). Note that the chunk shown is actually a reference to a hidden chunk I defined earlier by creating an empty chunk with the same name as the hidden chunk and using anchor=TRUE`.


Things on my TODO list



mkoohafkan/figr documentation built on May 23, 2019, 2:02 a.m.