Skip to content

Commit

Permalink
Merge pull request #26 from jonmcalder/master
Browse files Browse the repository at this point in the history
Add tufte handout engine
  • Loading branch information
stephlocke authored May 10, 2017
2 parents 119492d + d0459b4 commit 57a3605
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 11 deletions.
7 changes: 5 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
Package: pRojects
Title: Manage Project Directories for R Projects
Version: 0.0.1.9001
Authors@R: person("Steph", "Locke", email = "steph@itsalocke.com", role = c("aut", "cre"))
Version: 0.0.1.9002
Authors@R: c(
person("Steph", "Locke", email = "steph@itsalocke.com", role = c("aut", "cre")),
person("Jon", "Calder", email = "jonmcalder@gmail.com", role = "aut")
)
Description: Setting up R project directories for teaching, presenting, analysis,
package development can be a pain. pRojects shortcuts this by creating
folder structures and setting good defaults for you.
Expand Down
12 changes: 6 additions & 6 deletions R/createTrainingProject.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ createTrainingProject <- function(name,
...) {
# Supported packages
handoutEngine <-
match.arg(handoutEngine, c("rmarkdown", "bookdown"))
match.arg(handoutEngine, c("rmarkdown", "bookdown", "tufte"))
slideEngine <- match.arg(slideEngine, c("rmarkdown", "revealjs"))

# Installation dir
Expand All @@ -38,12 +38,12 @@ createTrainingProject <- function(name,

# Handouts prep
if ("handouts" %in% dirs) {
devtools:::add_desc_package(name,"Imports",handoutEngine)
devtools:::add_desc_package(name, "Imports", handoutEngine)

if (handoutEngine == "bookdown") {
message("bookdown demo added")
if (handoutEngine != "rmarkdown") {
message(paste(handoutEngine, "demo added"))
file.copy(
list.files(system.file("templates","bookdown", package = "pRojects"),full.names = TRUE),
list.files(system.file("templates", handoutEngine, package = "pRojects"), full.names = TRUE),
file.path(name,"handouts"),
overwrite = TRUE,
recursive = TRUE
Expand All @@ -57,7 +57,7 @@ createTrainingProject <- function(name,
devtools:::add_desc_package(name,"Imports",slideEngine)
}

if(usePackrat){
if (usePackrat) {
packrat::snapshot(name)
packrat::restore(name)
}
Expand Down
2 changes: 1 addition & 1 deletion R/shinyGadget.R
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ projectGadget <- function() {
selected = c("data", "handouts", "slides"),
multiple = TRUE),
shiny::radioButtons("handoutE", label = "Handouts",
choices=c("rmarkdown","bookdown"),
choices=c("rmarkdown","bookdown","tufte"),
selected = "rmarkdown"),
shiny::radioButtons("slideE", label = "Slides",
choices=c("rmarkdown","revealjs"),
Expand Down
223 changes: 223 additions & 0 deletions inst/templates/tufte/Tufte_Handout.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
---
title: "Tufte Handout"
subtitle: "An implementation in R Markdown"
author: "JJ Allaire and Yihui Xie"
date: "`r Sys.Date()`"
output:
tufte::tufte_html: default
tufte::tufte_handout:
citation_package: natbib
latex_engine: xelatex
tufte::tufte_book:
citation_package: natbib
latex_engine: xelatex
bibliography: skeleton.bib
link-citations: yes
---

```{r setup, include=FALSE}
library(tufte)
# invalidate cache when the tufte version changes
knitr::opts_chunk$set(tidy = FALSE, cache.extra = packageVersion('tufte'))
options(htmltools.dir.version = FALSE)
```

# Introduction

The Tufte handout style is a style that Edward Tufte uses in his books and handouts. Tufte's style is known for its extensive use of sidenotes, tight integration of graphics with text, and well-set typography. This style has been implemented in LaTeX and HTML/CSS^[See Github repositories [tufte-latex](https://github.com/tufte-latex/tufte-latex) and [tufte-css](https://github.com/edwardtufte/tufte-css)], respectively. We have ported both implementations into the [**tufte** package](https://github.com/rstudio/tufte). If you want LaTeX/PDF output, you may use the `tufte_handout` format for handouts, and `tufte_book` for books. For HTML output, use `tufte_html`. These formats can be either specified in the YAML metadata at the beginning of an R Markdown document (see an example below), or passed to the `rmarkdown::render()` function. See @R-rmarkdown more information about **rmarkdown**.

```yaml
---
title: "An Example Using the Tufte Style"
author: "John Smith"
output:
tufte::tufte_handout: default
tufte::tufte_html: default
---
```

There are two goals of this package:

1. To produce both PDF and HTML output with similar styles from the same R Markdown document;
1. To provide simple syntax to write elements of the Tufte style such as side notes and margin figures, e.g. when you want a margin figure, all you need to do is the chunk option `fig.margin = TRUE`, and we will take care of the deails for you, so you never need to think about `\begin{marginfigure} \end{marginfigure}` or `<span class="marginfigure"> </span>`; the LaTeX and HTML code under the hood may be complicated, but you never need to learn or write such code.

If you have any feature requests or find bugs in **tufte**, please do not hesitate to file them to https://github.com/rstudio/tufte/issues. For general questions, you may ask them on StackOverflow: http://stackoverflow.com/tags/rmarkdown.

# Headings

This style provides first and second-level headings (that is, `#` and `##`), demonstrated in the next section. You may get unexpected output if you try to use `###` and smaller headings.

`r newthought('In his later books')`^[[Beautiful Evidence](http://www.edwardtufte.com/tufte/books_be)], Tufte starts each section with a bit of vertical space, a non-indented paragraph, and sets the first few words of the sentence in small caps. To accomplish this using this style, call the `newthought()` function in **tufte** in an _inline R expression_ `` `r ` `` as demonstrated at the beginning of this paragraph.^[Note you should not assume **tufte** has been attached to your R session. You should either `library(tufte)` in your R Markdown document before you call `newthought()`, or use `tufte::newthought()`.]

# Figures

## Margin Figures

Images and graphics play an integral role in Tufte's work. To place figures in the margin you can use the **knitr** chunk option `fig.margin = TRUE`. For example:

```{r fig-margin, fig.margin = TRUE, fig.cap = "MPG vs horsepower, colored by transmission.", fig.width=3.5, fig.height=3.5, cache=TRUE}
library(ggplot2)
mtcars2 <- mtcars
mtcars2$am <- factor(
mtcars$am, labels = c('automatic', 'manual')
)
ggplot(mtcars2, aes(hp, mpg, color = am)) +
geom_point() + geom_smooth() +
theme(legend.position = 'bottom')
```

Note the use of the `fig.cap` chunk option to provide a figure caption. You can adjust the proportions of figures using the `fig.width` and `fig.height` chunk options. These are specified in inches, and will be automatically scaled down to fit within the handout margin.

## Arbitrary Margin Content

In fact, you can include anything in the margin using the **knitr** engine named `marginfigure`. Unlike R code chunks ```` ```{r} ````, you write a chunk starting with ```` ```{marginfigure} ```` instead, then put the content in the chunk. See an example on the right about the first fundamental theorem of calculus.

```{marginfigure}
We know from _the first fundamental theorem of calculus_ that for $x$ in $[a, b]$:
$$\frac{d}{dx}\left( \int_{a}^{x} f(u)\,du\right)=f(x).$$
```

For the sake of portability between LaTeX and HTML, you should keep the margin content as simple as possible (syntax-wise) in the `marginefigure` blocks. You may use simple Markdown syntax like `**bold**` and `_italic_` text, but please refrain from using footnotes, citations, or block-level elements (e.g. blockquotes and lists) there.

## Full Width Figures

You can arrange for figures to span across the entire page by using the chunk option `fig.fullwidth = TRUE`.

```{r fig-fullwidth, fig.width = 10, fig.height = 2, fig.fullwidth = TRUE, fig.cap = "A full width figure.", warning=FALSE, cache=TRUE}
ggplot(diamonds, aes(carat, price)) + geom_smooth() +
facet_grid(~ cut)
```

Other chunk options related to figures can still be used, such as `fig.width`, `fig.cap`, `out.width`, and so on. For full width figures, usually `fig.width` is large and `fig.height` is small. In the above example, the plot size is $10 \times 2$.

## Main Column Figures

Besides margin and full width figures, you can of course also include figures constrained to the main column. This is the default type of figures in the LaTeX/HTML output.

```{r fig-main, fig.cap = "A figure in the main column.", cache=TRUE}
ggplot(diamonds, aes(cut, price)) + geom_boxplot()
```

# Sidenotes

One of the most prominent and distinctive features of this style is the extensive use of sidenotes. There is a wide margin to provide ample room for sidenotes and small figures. Any use of a footnote will automatically be converted to a sidenote. ^[This is a sidenote that was entered using a footnote.]

If you'd like to place ancillary information in the margin without the sidenote mark (the superscript number), you can use the `margin_note()` function from **tufte** in an inline R expression. `r margin_note("This is a margin note. Notice that there is no number preceding the note.")` This function does not process the text with Pandoc, so Markdown syntax will not work here. If you need to write anything in Markdown syntax, please use the `marginfigure` block described previously.

# References

References can be displayed as margin notes for HTML output. For example, we can cite R here [@R-base]. To enable this feature, you must set `link-citations: yes` in the YAML metadata, and the version of `pandoc-citeproc` should be at least 0.7.2. You can always install your own version of Pandoc from http://pandoc.org/installing.html if the version is not sufficient. To check the version of `pandoc-citeproc` in your system, you may run this in R:

```{r eval=FALSE}
system2('pandoc-citeproc', '--version')
```

If your version of `pandoc-citeproc` is too low, or you did not set `link-citations: yes` in YAML, references in the HTML output will be placed at the end of the output document.

# Tables

You can use the `kable()` function from the **knitr** package to format tables that integrate well with the rest of the Tufte handout style. The table captions are placed in the margin like figures in the HTML output.

```{r}
knitr::kable(
mtcars[1:6, 1:6], caption = 'A subset of mtcars.'
)
```

# Block Quotes

We know from the Markdown syntax that paragraphs that start with `>` are converted to block quotes. If you want to add a right-aligned footer for the quote, you may use the function `quote_footer()` from **tufte** in an inline R expression. Here is an example:

> "If it weren't for my lawyer, I'd still be in prison. It went a lot faster with two people digging."
>
> `r tufte::quote_footer('--- Joe Martin')`
Without using `quote_footer()`, it looks like this (the second line is just a normal paragraph):

> "Great people talk about ideas, average people talk about things, and small people talk about wine."
>
> --- Fran Lebowitz
# Responsiveness

The HTML page is responsive in the sense that when the page width is smaller than 760px, sidenotes and margin notes will be hidden by default. For sidenotes, you can click their numbers (the superscripts) to toggle their visibility. For margin notes, you may click the circled plus signs to toggle visibility.

# More Examples

The rest of this document consists of a few test cases to make sure everything still works well in slightly more complicated scenarios. First we generate two plots in one figure environment with the chunk option `fig.show = 'hold'`:

```{r fig-two-together, fig.cap="Two plots in one figure environment.", fig.show='hold', cache=TRUE}
p <- ggplot(mtcars2, aes(hp, mpg, color = am)) +
geom_point()
p
p + geom_smooth()
```

Then two plots in separate figure environments (the code is identical to the previous code chunk, but the chunk option is the default `fig.show = 'asis'` now):

```{r fig-two-separate, ref.label='fig-two-together', fig.cap=sprintf("Two plots in separate figure environments (the %s plot).", c("first", "second")), cache=TRUE}
```

You may have noticed that the two figures have different captions, and that is because we used a character vector of length 2 for the chunk option `fig.cap` (something like `fig.cap = c('first plot', 'second plot')`).

Next we show multiple plots in margin figures. Similarly, two plots in the same figure environment in the margin:

```{r fig-margin-together, fig.margin=TRUE, fig.show='hold', fig.cap="Two plots in one figure environment in the margin.", fig.width=3.5, fig.height=2.5, cache=TRUE}
p
p + geom_smooth(method = 'lm')
```

Then two plots from the same code chunk placed in different figure environments:

```{r fig-margin-separate, fig.margin=TRUE, fig.cap=sprintf("Two plots in separate figure environments in the margin (the %s plot).", c("first", "second")), fig.width=3.5, fig.height=2.5, cache=TRUE}
knitr::kable(head(iris, 15))
p
knitr::kable(head(iris, 12))
p + geom_smooth(method = 'lm')
knitr::kable(head(iris, 5))
```

We blended some tables in the above code chunk only as _placeholders_ to make sure there is enough vertical space among the margin figures, otherwise they will be stacked tightly together. For a practical document, you should not insert too many margin figures consecutively and make the margin crowded.

You do not have to assign captions to figures. We show three figures with no captions below in the margin, in the main column, and in full width, respectively.

```{r fig-nocap-margin, fig.margin=TRUE, fig.width=3.5, fig.height=2, cache=TRUE}
# a boxplot of weight vs transmission; this figure
# will be placed in the margin
ggplot(mtcars2, aes(am, wt)) + geom_boxplot() +
coord_flip()
```
```{r fig-nocap-main, cache=TRUE}
# a figure in the main column
p <- ggplot(mtcars, aes(wt, hp)) + geom_point()
p
```
```{r fig-nocap-fullwidth, fig.fullwidth=TRUE, fig.width=10, fig.height=3, cache=TRUE}
# a fullwidth figure
p + geom_smooth(method = 'lm') + facet_grid(~ gear)
```

# Some Notes on Tufte CSS

There are a few other things in Tufte CSS that we have not mentioned so far. If you prefer `r sans_serif('sans-serif fonts')`, use the function `sans_serif()` in **tufte**. For epigraphs, you may use a pair of underscores to make the paragraph italic in a block quote, e.g.

> _I can win an argument on any topic, against any opponent. People know this, and steer clear of me at parties. Often, as a sign of their great respect, they don't even invite me._
>
> `r quote_footer('--- Dave Barry')`
We hope you will enjoy the simplicity of R Markdown and this R package, and we sincerely thank the authors of the Tufte-CSS and Tufte-LaTeX projects for developing the beautiful CSS and LaTeX classes. Our **tufte** package would not have been possible without their heavy lifting.

To see the R Markdown source of this example document, you may follow [this link to Github](https://github.com/rstudio/tufte/raw/master/inst/rmarkdown/templates/tufte_html/skeleton/skeleton.Rmd), use the wizard in RStudio IDE (`File -> New File -> R Markdown -> From Template`), or open the Rmd file in the package:

```{r eval=FALSE}
file.edit(
tufte:::template_resources(
'tufte_html', '..', 'skeleton', 'skeleton.Rmd'
)
)
```

```{r bib, include=FALSE}
# create a bib file for the R packages used in this document
knitr::write_bib(c('base', 'rmarkdown'), file = 'skeleton.bib')
```
22 changes: 21 additions & 1 deletion tests/testthat/test-createTrainingProject.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ unlink(project_name, recursive = TRUE, force = TRUE)

test_that("createTrainingProject() creates as expected when using bookdown and revealjs",{

createTrainingProject(project_name,handoutEngine = "bookdown",slideEngine = "revealjs")
createTrainingProject(project_name, handoutEngine = "bookdown", slideEngine = "revealjs")

expect_true(file.exists(file.path(project_name, paste0(project_name, ".Rproj"))))
expect_true(file.exists(file.path(project_name, "DESCRIPTION")))
Expand All @@ -43,3 +43,23 @@ test_that("createTrainingProject() creates as expected when using bookdown and r

unlink(project_name, recursive = TRUE, force = TRUE)

test_that("createTrainingProject() creates as expected when using tufte",{

createTrainingProject(project_name, handoutEngine = "tufte")

expect_true(file.exists(file.path(project_name, paste0(project_name, ".Rproj"))))
expect_true(file.exists(file.path(project_name, "DESCRIPTION")))
expect_true(file.exists(file.path(project_name, "R")))
expect_true(file.exists(file.path(project_name, "README.Rmd")))
expect_true(file.exists(file.path(project_name, "packrat")))
expect_true(file.exists(file.path(project_name, ".git")))
expect_true(file.exists(file.path(project_name, ".gitignore")))
expect_true(file.exists(file.path(project_name, ".travis.yml")))
expect_true(file.exists(file.path(project_name, "data")))
expect_true(file.exists(file.path(project_name, "handouts")))
expect_true(file.exists(file.path(project_name, "handouts", "Tufte_Handout.Rmd")))
expect_true(file.exists(file.path(project_name, "slides")))

})

unlink(project_name, recursive = TRUE, force = TRUE)
2 changes: 1 addition & 1 deletion vignettes/TrainingProjects.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ At the moment, this facility will set up a basic project with some additional fo
## Document packages
If you make a `handouts/` or `slides` directory (both of which are created with the defaults), we will add rmarkdown to the project's DESCRIPTION file.

You can specify an alternative package for your handouts via `handoutEngine`. At present, the only other supported package is [`bookdown`](https://cran.r-project.org/package=bookdown). If you select `bookdown` as the `handoutEngine`, `bookdown` will be added to the DESCRIPTION file and the bookdown-demo files will be added to the `handouts/` directory.
You can specify an alternative package for your handouts via `handoutEngine`. At present, two additional package options are supported. The first is [`bookdown`](https://cran.r-project.org/package=bookdown), and the second is [`tufte`](https://cran.r-project.org/package=tufte). If you select `bookdown` or `tufte` as the `handoutEngine`, the relevant package will be added to the DESCRIPTION file and the demo files for this handout format will be added to the `handouts/` directory.

You can specify an alternative package for your slides via `slideEngine`. At present, the only other supported package is [`revealjs`](https://cran.r-project.org/package=revealjs).

Expand Down

0 comments on commit 57a3605

Please sign in to comment.