knitr set Latex definecolor using hooks - r

TL;DR
I want some latex commands (in this case \definecolor) to change in certain cases, so I want to create the text for these commands in R and have them written to the markup file during markup. I can't yet get it working perfectly using knitr hooks.
More Detail:
The number (and style) of colors I want to define in a .rnw file varies so I am avoiding hard-coding the \definecolor calls in the .rnw document.
It seems like I can do this with knitr hooks, and I'm very close. But I'm confused about a couple of things.
Here's a reproducible example. R file first
library(RColorBrewer)
library(knitr)
colNames <- c("one","two","three")
txtColors <- sub("#","",brewer.pal(6, "Dark2")[1:3])
# set the knitr hook to create color definitions within the rnw file
knitr::knit_hooks$set(setColors = function(before, options, envir) {
if (!before){
defs <- vector("list",length(txtColors))
for(i in 1:length(txtColors)){
defs[[i]] <- paste0("\\definecolor{",colNames[[i]],"Color}{HTML}{",txtColors[[i]],"}")
}
return(paste0("\\xglobal",unlist(defs), "\n"))
}
})
setwd(file.path("G:", "my", "working", "dir"))
knit2pdf("testColors_s.rnw")
and here an rnw file to go with it (name it "testColors_s.rnw")
\documentclass{article}
\usepackage{xcolor}
\begin{document}
<<setColorHook, setColors = TRUE>>=
#
\textcolor{oneColor}{The first color}
\textcolor{twoColor}{The second color}
\textcolor{threeColor}{The third color}
\end{document}
Question #1. I have to set the colors globally with \xglobal because (I guess) that knitr is putting these calls inside a kframe. Can I make a hook that avoids the kframe? Or doesn't require the xglobal call?
Question #2. I get this warning on run: Warning message: Package xcolor Warning: Incompatible color definition on input line 57. This is a color definition done by knitr, not me. Here is the offending line in the tex file:
\definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe}
How can I avoid this warning or keep knitr from creating this line?
Any tips on doing any part of this would be greatly appreciated.
Thanks in advance.

This seems like kind of a hack, but I figured out a solution using the document hook instead of a chunk hook. This fixes both problems (xglobal not longer needed and the extra definecolor is not created). Better solutions are welcome.
Reproducible example, R file:
library(RColorBrewer)
library(knitr)
colNames <- c("one","two","three")
txtColors <- sub("#","",brewer.pal(6, "Dark2")[1:3])
defs <- vector("list",length(txtColors))
for(i in 1:length(txtColors)){
defs[[i]] <- paste0("\\\\definecolor{",colNames[[i]],"Color}{HTML}{",txtColors[[i]],"}")
}
knit_hooks$set(document = function(x) {
sub('%CustomColorDefsHere', paste0(unlist(defs), "\n", collapse = ""), x)
})
setwd(file.path("G:", "my", "working", "dir"))
knit2pdf("testColors_s.rnw")
and the rnw file
\documentclass{article}
\usepackage{xcolor}
%CustomColorDefsHere
\begin{document}
\textcolor{oneColor}{The first color}
\textcolor{twoColor}{The second color}
\textcolor{threeColor}{The third color}
\end{document}
I hope this is useful for someone ...

Related

R Sweave: put the whole code of the .Rnw file in Appendix?

I just found this awesome technique to put the code used in the .Rmd file in the appendix (of that same file).
However, I am using R Sweave and not R Markdown and I would like to know if there exists a similar way to put all the code at the end in a unique chunk. The code to do that in Markdown does not work in Sweave. I precise that, unlike this post, I do not have a separate .R file where the calculations are made. Everything is done in the .Rnw file.
Does anybody know how to do it?
Edit : a reproducible example
\documentclass[11pt, twocolumn]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\begin{document}
\SweaveOpts{concordance=TRUE}
<<reg2, echo=FALSE, print=FALSE>>=
head(mtcars)
#
<<reg3, echo=FALSE, print=FALSE>>=
head(iris)
#
\section*{Appendix}
% the place where I could like to put the whole code
\end{document}
This chunk works to include the code:
<<echo=FALSE, eval=TRUE>>=
filename <- tempfile(fileext=".R")
Stangle("test.Rnw", output = filename, quiet = TRUE)
cat(readLines(filename), sep = "\n")
#
When I include that in your example file, I see this:
I think it's possible to modify the format a bit; see ?Rtangle for some details. Similar things are possible with knitr, but it's more flexible. I suspect the best method would be similar to the one you found for RMarkdown.

knitr: why does nothing appear in the "environment" panel when I compile my .Rnw file

I am new to knitr. I have made a practise .Rnw file with some very simple commands. For example:
\documentclass[12pt, a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{hyperref}
\hypersetup{
colorlinks = true, %Colours links instead of ugly boxes
urlcolor = blue, %Colour for external hyperlinks
linkcolor = blue, %Colour of internal links
citecolor = blue %Colour of citations
}
\usepackage{caption}
\captionsetup[figure]{labelfont=bf, labelsep=period}
\captionsetup[table]{labelfont=bf, labelsep=period}
\setlength{\parindent}{0pt}
\title{My very first LaTeX/knitr document!}
\date{April 2019}
\begin{document}
\maketitle
\begingroup
\hypersetup{linkcolor=black} % force independent link colours in table of contents
\tableofcontents
\endgroup
\newpage
\section{Basics}
\subsection{Using no options}
First, let's try and a show a chunk of code along with a plot and print() message.
<<first-chunk>>=
# Make a simple dataframe:
setwd("/home/user/Documents/testing-area/knitr/")
df <- data.frame(A = c(1,2,3), B = c("A", "B", "C"))
plot(df$A,df$B)
print("hello")
#
When I click on "Compile PDF", I get a PDF with all the code (as I expect, since I didn't use echo = FALSE), as well as the plot itself and the print statement.
My question is: why do I not see "df" in Rstudio, in my "Environment" panel, like you "usually" when simply running a .R script in Rstudio? Clearly, R is running the code in the code chunk and producing the PDF. So why is there nothing in the Environment. If I run the R code in the .Rnw file "manually", I do get "df" in the Environment.
Am I missing something? I know it doesn't really matter, since my code still technically runs, but I find unituitive that Rstudio doesn't show anything in the Environment. Is there a reason for this?
Thanks.
The usual way to knit an Rnw file by clicking on Compile PDF in RStudio does it in an independent R process. Your document won't see local variables in your workspace, and variables created in it won't last beyond the processing.
There are ways to change this. If you explicitly knit the process in the R console, e.g.
knitr::knit2pdf("file.Rnw")
then it will be able to see the variables in your local workspace, but changes it makes won't be saved. To also save results, use
knitr::knit2pdf("file.Rnw", envir = globalenv())
which says to evaluate the code in the global environment (i.e. your workspace).

Knitr inline chunk options (no evaluation) or just render highlighted code

I cannot find information on whether it is possible to specify options for inline chunks in knitr. I've just tried specifying them, as in the regular chunk, but this gives an error.
What I need is to include R code with highlighting in a PDF, but without evaluating it. This can only happen with inline chunks due to the format of the context. Or perhaps there is another way to include highlighted code.
To provide an example, I need something in the lines of:
Some text about something with `r eval=FALSE 1+1` inside the sentence.
This particular syntax gives:
Error in parse(text = code, keep.source = FALSE) :
<text>:1:11: unexpected ','
1: eval=FALSE,
Thanks to Yihui you can do,
\documentclass{article}
<<setup, include=FALSE>>=
knit_hooks$set(inline = function(x) {
if (is.numeric(x)) return(knitr:::format_sci(x, 'latex'))
highr::hi_latex(x)
})
#
\begin{document}
the value of $\pi$ is \Sexpr{pi}, and the function to read a table is
\Sexpr{'read.table()'}.
<<test2>>=
rnorm(10)
#
\end{document}

global comment option for R markdown in knitr

To change the leading characters for the output a knitr chunk in .Rmd has a comment option, like
```{r comment = ""}
1:100
```
Is there a way to set this globally, not separately for every chunk?
opts_knit$set(comment = "")
does not work and I cannot find it anywhere in the documentation.
Use opts_chunk$set() because that is a chunk option; opts_knit is for package options (sorry about the similar names which apparently confused you). See http://yihui.name/knitr/options

figure* environment in twocolumn knitr/Sweave document

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*">>=
#

Resources