I'd like to add a TikZ figure to a bookdown document in order to include some fancy graphics.
My primary output format is LaTeX which means that I could essentially just include the TikZ graphics verbatim in the Rmarkdown file and it would render fine. However, two problems are haunting me:
I'd like for the TikZ graphics to be part of a figure environment (for the numbering, caption etc).
I'd like to be able to render the same code to both PDF (LaTeX) and Gitbook (HTML).
Right now I have the following chunk which nicely produces the relevant graph as a figure when I render to pdf.
```{r, echo=FALSE, engine='tikz', out.width='90%', fig.ext='pdf', fig.cap='Some caption.'}
\begin{tikzpicture}[scale=.7]
\draw [fill=gray!30,very thick] (0,-1) rectangle (5,1);
\draw [very thick] (5, 0) -- (13,0);
\node [below] at (2,-1) {\large Hello};
\node [below, align=center] at (0,-1) {\large Two\\ lines};
\end{tikzpicture}
```
However, there are two problems with the code:
I do not get any output when rendering to gitbook (using knitr and bookdown). I do get the figure caption, however, and if I render to html_document then it works too and I can see the graph.
For PDF the text is rendered using the computer modern font. I'd really like to change this, and the main font in the LaTeX document has already been set to something else. However, because the code is rendered locally by the TikZ engine and then inserted, it is not part of the full LaTeX document. Can I add some LaTeX options, packages etc. that are included by the TikZ engine before the code is rendered?
If there are other ways to include the TikZ code as part of a figure environment then I'd be happy to know.
Update: I guess the second point could be fixed by setting engine.opts = list(template = "latex/tikz2pdf.tex") where the necessary setup for LaTeX is included in the tikz2pdf.tex file. That file is read using LaTeX but I'd like to use xelatex to parse the file since I'm using the fontspec LaTex package. Can that be changed anyway?
I think I found an answer to both of my questions. It did take - as Yihui pointed out - quite some time. I'm including the answer here in case someone else turns out to need this (or myself at a later point).
Re 1) Render TikZ code to both pdf and gitbook
This turned out to be easier than I anticipated. Setting the argument fig.ext=if (knitr:::is_latex_output()) 'pdf' else 'png' as part of the chunk arguments helps this along. If I'm not knitting to PDF then imagemagick or some other software automatically converts it to PNG.
Re 2) Modifying the font
As listed in my updated question this can be set by tweaking the file tikz2pdf.tex that is part of knitr. A copy of it is included below so you don't have to search for it yourself. Setting the chunk argument engine.opts = list(template = "latex/tikz2pdf.tex") enables you to put any desired fonts, LaTeX packages etc in preamble before the TikZ code is rendered.
Looking through the knitr code, you can see that texi2dvi is used to parse the tikz2pdf.tex file with the TikZ code inserted. texi2dvi calls pdflatex which messes things up in case you need to use XeLaTeX or LuaLaTeX to include TrueType fonts using fontspec.
I'm sure it would be possible to fix that somehow in the texi2dvi code but a much simpler solution (at least for me) was to change the environment. If I set the two environmental variable before starting R and rendering the book then xelatex is automatically used for compiling all the code. In my bash terminal this is done using
export LATEX="xelatex"
export PDFLATEX="xelatex"
Voila!
The chunk becomes
```{r, echo=FALSE, engine='tikz', out.width='90%', fig.ext=if (knitr:::is_latex_output()) 'pdf' else 'png', fig.cap='Some caption.', engine.opts = list(template = "latex/tikz2pdf.tex")
}
\begin{tikzpicture}[scale=.7]
\draw [fill=gray!30,very thick] (0,-1) rectangle (5,1);
\draw [very thick] (5, 0) -- (13,0);
\node [below] at (2,-1) {\large Hello};
\node [below, align=center] at (0,-1) {\large Two\\ lines};
\end{tikzpicture}
```
and tikz2pdf.tex is
\documentclass{article}
\include{preview}
\usepackage[pdftex,active,tightpage]{preview}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{matrix}
%% INSERT YOUR OWN CODE HERE
\begin{document}
\begin{preview}
%% TIKZ_CODE %%
\end{preview}
\end{document}
I'm still surprised at the whole flexibility of knitr and related packages. Nice work Yihui!
I had problems compiling plots with The pgfplots and bookdown. Using engine='tikz', gave the error message: 'axis environment does not exist'. I fixed it by changing \usepackage{tikz} to \usepackage{pgfplots} in the tikz2pdf.tex file and using engine.opts = list(template ="Tikz2pdf.tex") as suggested.
Related
I want to use tikz as graphics device in RMarkdown and I want it to include the generated LaTeX preamble.
In the past, I already used tikzDevice within knitr documents. The tex file generated by tikzDevice usually included the whole preamble from my knitr/LaTeX document. When I use it with RMarkdown, I get the standard preamble (see below).
RMarkdown file:
---
title: "Title"
author: "Me"
fontsize: 12pt
documentclass: scrartcl
output:
bookdown::pdf_document2:
toc: true
fig_caption: true
keep_tex: true
---
# Introduction
```{r plot, dev="tikz"}
plot(rnorm(50))
``
Beginning of generated tex file (plot-1.tex):
% Created by tikzDevice version 0.12.3 on 2019-06-16 16:09:40
% !TEX encoding = UTF-8 Unicode
\documentclass[10pt]{article}
Desired/expected beginning of plot-1.tex:
% Created by tikzDevice version 0.12.3 on 2019-06-16 16:09:40
% !TEX encoding = UTF-8 Unicode
\documentclass[12pt]{scrartcl}
I'm not sure you really want what you're asking for. The figure will be produced as a separate document containing nothing except the figure, which will be rendered as a PDF. The differences between scrartcl and article shouldn't matter for the figure, they matter for the document as a whole.
But if you really do need that document class, you get it by specifying options(tikzDocumentDeclaration = "\\documentclass[12pt]{scrartcl}") in an R chunk early in your document. When I do that I can see in the source that it worked, but the output looks pretty much the same as it did with the default class. It's also possible to specify this using chunk options, but there's unlikely to be any advantage to doing that.
I think I figured it out:
My problem was that while using RMarkdown the options tikzDocumentDeclaration, tikzLatexPackages ... (nearly all options for tikzDevice) were not set automatically. When you use knitr the options for tikzDevice get set up in the process of splitting up markup and code chunks from the source file. With RMarkdown there is no LaTeX code to extract and use with tikz because pandoc generates it after the graphic is rendered. So one can either define the tikz... options manually or use the chunk option external=FALSE like user2554330 suggested.
Example minimal_knitr.Rnw:
\documentclass[fontsize=12pt]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\begin{document}
<<r plot, dev='tikz', echo=FALSE>>=
plot(rnorm(50))
#
\end{document}
I'm writing mainly in LaTeX, but some co-authors prefer MS Word. To facilitate their work a bit, I would like to convert the .tex file (or the .pdf) to a .docx. The formatting does not need to be perfect, but all of the text, equations, figures etc should be perfectly readable.
I'm currently thinking to take the .tex document, replace all the essential stuff and then let Pandoc do it's magic. For this I would preferably implement my additions as a Pandoc filter. E.g., my tikz pictures would be converted to png using the tikz.py filter provided with Pandoc. The problem I'm facing with this approach is that Pandoc tries to interpret the tikz environment upon conversion from tex into it's internal language and the filters take this internal language as an input. The result is that the tikz code is lost. Is there a way to tell Pandoc to leave any tikzpicture environments alone?
Edit:
See the MWE below:
MWE.tex contents:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (2,2);
\end{tikzpicture}
\end{document}
Output of pandoc -t native MWE.tex
[Para [Str "(0,0)",Space,Str "\8211",Space,Str "(2,2);"]]
The \draw command has completely disappeared as you can see.
I found that pandoc does not skip code encapsulated in \iffalse ... \fi, so you can redefine the tikpicture environment as such (or in any other way you might like):
\documentclass{article}
\usepackage{tikz}
\iffalse
\renewenvironment{tikzpicture}%
{\par---start tikzpicture---\\}%
{\\---end tikzpicture---\par}
\renewcommand{\node}{node:}
\fi
\begin{document}
\begin{tikzpicture}
\node {foo};
\end{tikzpicture}
\end{document}
With pandoc 2.5 this results in a docx file containing:
—start tikzpicture—
node:foo;
—end tikzpicture—
This feels very wrong, and I wish I knew a nicer way.
Question: Is there a way to use tikz notation within an Rmarkdown document without having to compile the document to a pdf?
And (sort of in the same direction):
Question: What is the best way to add mutiple tikz graphics in an RMarkdown document that I want to compile to html (while keeping the flexibilty to compile the file to pdf or word in a later stage as well)?
I've read many answers to posts (like TikZ in R Markdown or How can I use TikZ to make standalone (SVG) graphics?) that ask similar questions but I am still not completely sure, hence the questions.
I basically want to run this piece of code
---
output: pdf_document
header-includes:
- \usepackage{tikz}
---
## TikZ picture
Some picture
\begin{tikzpicture}
\draw (0,0) circle (2cm);
\end{tikzpicture}
Instead of pdf_document I'd like to have html_document + some magic that automatically converts the tikz graphic to something that can be understood by html. Any suggestions?
I've just discovered that you can add tikz code in the code chunk of Rmarkdown when you modify the engine option :
---
output: html_document
---
Some picture
```{r,engine='tikz'}
\begin{tikzpicture}
\draw (0,0) circle (2cm);
\end{tikzpicture}
```
The problem is that the figure is pixelized and the scale is not respected. One way to solve this may be to change the extension of the figure output (to pdf) and the width and the height with the chunk options (e.g. equals to 3 inches) :
```{r,engine='tikz',fig.ext='pdf',fig.width=3}
\begin{tikzpicture}
\draw (0,0) circle (2cm);
\end{tikzpicture}
```
I'm sure there are better solutions but it's an easy way to use tikz code for an html output.
Sounds like it should be a common problem, but I didn't find an obvious trick.
Consider the knitr Rnw file below,
\documentclass[twocolumn, 12pt]{article}
\usepackage{graphicx}
\begin{document}
%\SweaveOpts{dev=pdf, fig.align=center}
\begin{figure*}
<<aaa, fig.width=8, fig.height=5, fig.show=hold>>=
plot(1,1)
#
\end{figure*}
\end{document}
I would like this wide figure to span two columns, using a {figure*} LaTeX environment. Is there a hook for that?
EDIT: wrapping the chunk in figure* gives the following output.
Two facts:
knitr makes everything accessible for you, so LaTeX tricks are often unnecessary;
there is a chunk hook with which you can wrap your chunk results;
A simple-minded solutions is:
knit_hooks$set(chunk = function(x, options) {
sprintf('\\begin{figure*}\n%s\n\\end{figure*}', x)
})
I leave the rest of work to you to take care of more details in options (e.g. when options$fig.keep == 'none', you should not wrap the output in figure*). You may want to see how the default chunk hook for LaTeX is defined in knitr to know better how the chunk hook works.
However, in this case, I tend to write the LaTeX code by myself in the document instead of automatically creating it. After you have got figure*, you may start to think about \caption{} and \label{} (not hard, but I still want to see them in LaTeX).
Not sure about how knitr but for Sweave (and basic latex) there is in fact a trick: have the R code produce a pdf file, and then use standard \includegraphics to pull it in.
So with this:
\documentclass[twocolumn, 12pt]{article}
\usepackage{graphicx}
\begin{document}
%\SweaveOpts{dev=pdf}
<<aaa,fig=FALSE,print=FALSE,echo=FALSE>>=
pdf("mychart.pdf", width=6, height=3)
set.seed(42)
plot(cumsum(rnorm(100)), type='l', main="yet another random walk")
invisible(dev.off())
#
\begin{figure*}
\includegraphics{mychart.pdf}
\end{figure*}
\end{document}
I got the document below (which I then converted from pdf to png):
I also had a similar problem while preparing a figure that should span two columns in a IEEE two-column conference paper.
Setting the chunk hook caused some strange error in my setup.
Even this simple hook: knit_hooks$set(chunk = function(x, options) x)
But after looking into knitr::opts_chunk$get(), I realized that simply setting fig.env="figure*" solves the problem in an elegant way.
Here is how my chunk looks like in an Rnw file:
<<fig1, fig.width=18, fig.height=6, fig.env="figure*">>=
#
I would like to make an R code chunk (in Sweave) printed inside a framed box in the resulting pdf.
Is there an easy solution for doing that?
The short answer is that yes, there is an easy way. Just add the following lines, or something like them to the preamble of your Sweave document:
\DefineVerbatimEnvironment{Sinput}{Verbatim} {xleftmargin=2em,
frame=single}
\DefineVerbatimEnvironment{Soutput}{Verbatim}{xleftmargin=2em,
frame=single}
This works because the appearance of code (and output) chunks is controlled by the definition of the Sinput and Soutput environments. These are both Verbatim environments as provided by the LaTeX package fancyvrb. (Click here for a 73 page pdf describing the numerous options that fancyvrb provides).
A quick look in the file Sweave.sty reveals the default definition of those two environments:
\DefineVerbatimEnvironment{Sinput}{Verbatim}{fontshape=sl}
\DefineVerbatimEnvironment{Soutput}{Verbatim}{}
\DefineVerbatimEnvironment{Scode}{Verbatim}{fontshape=sl}
To change those definitions, just add \DefineVerbatimEnvironment statements of your own devising either: (a) at the end of the Sweave.sty file; or (b) at the start of your *.Snw document.
Finally, here's an example to show what this looks like in practice:
\documentclass[a4paper]{article}
\usepackage{Sweave}
\DefineVerbatimEnvironment{Sinput}{Verbatim} {xleftmargin=2em,
frame=single}
\DefineVerbatimEnvironment{Soutput}{Verbatim}{xleftmargin=2em,
frame=single}
\title{Sweave with boxes}
\begin{document}
\maketitle
<<echo=FALSE>>=
options(width=60)
#
Here is an example of a code chunk followed by an output chunk,
both enclosed in boxes.
<<>>=
print(rnorm(99))
#
\end{document}
knitr, a successor of Sweave, by default outputs all echoed R code in boxes, and also formats it to the margins. Other nice features include syntax coloring and PGF integration.
Sweave code of average complexity needs only minor if any adaptions to run with knitr.