YacineH
YacineH

Reputation: 63

Knitr - Good pratice for formatting chunks output and creating new chunk options

Before asking anything, I want to apologize for a couple of things : First, I acknowledge that I do not contribute very much to the community. I never answer to questions and I very rarely ask some because I dig through everything first - which means, when I do, it is to ask some long and nifty ones. Second, my question is actually two not-very-related questions, and I do not think this is good practice around here (first time I post anything). If you want me to separate those, let me know and it will be done.

So, addressing the issue :

I am currently writing a report in which I need to display tables.

I have chosen successively several methods to do so over the last months of work, and I ended up with the conclusion that there is no easy and flexible way to display the raw code and the formatted chunk output without displaying the R code formatting the evaluation of the said chunk code (this code is not generic ; it depends uniquely on the variable displayed) - actually there is know, see the EDIT.

Let me explain : I have a simple data.frame. I want to display the code defining the data.frame and the latex table corresponding to the data.frame without showing the code that has produced the latex code (the Hmisc latex function or the xtable with the corresponding options for example). The reason is that it is irrelevant, distracting and sometimes bigger than the interesting code. I have never encountered a satisfying way to do this, so I want to know how you guys manage to do it. For now, the best working solution I have come up with is this one :

<<data>>=
mytable<-data.frame(a=c(1,2),b=c(2,3))
@

<<data.display,results='asis',echo=FALSE,dependson=data>>=
latex(mytable,caption="title",file="",<other options...>)
@

This is quite satisfying given my previous attempts, but the need to define and display the variable mytable annoys me. This, and the fact that I have to use another chunk to pull this off.

I have thought of using a numerical vector for the echo option but it does not marry well with tidy=FALSE and is not flexible at all (any modification to the code can result to the need of modifying the option value as well).

I have also thought of using and displaying simply the latex or xtable function (with a minimal number of arguments) and wrap the chunk with the proper LaTeX code to set up the table environment, but I still needed some options from latex or xtable, and I had to make a reference to the chunk to display it outside of this environment (or it produces an error).

So my first question is : How do you usually present the code that has generated the table you wish to display ? What is your method to hide the unwanted bits of code ? What is considered as good practice in the community regarding this issue ?

Finally, the last solution I am working on right now seems the most promising, but it is technically very difficult (at least to me), so that brings my second question :

How can you navigate an expression tree to recover one of the arguments as it has been put in the console ?

The idea is to create an option that will affect a redefined source hook, which will take the first argument of the latex function and display it instead of the full code.

For example, the code

<<data,results='asis',latex=TRUE>>=
latex(
 data.frame(a=c(1,2),b=c(2,3)),
 caption="title",file="",
 <other options...>)
@

... would be displayed in the document as :

data.frame(a=c(1,2),b=c(2,3))

I came up with this :

opts_chunk$set(latex=FALSE)

default.source<-knit_hooks$get("source")

knit_hooks$set(
 source=function(x,options){
  if(options$latex){
   default.source(TODO(x),options) 
  } else {
   default.source(x,options)   
  }
 }
)

It is not much... The substitute function seems useless as it always returns me "src" (I am not surprised, it takes the first thing it sees). I wish I could take the whole function and extract only the first argument. (minor edit : I have succeeded in doing this by quoting then parsing the expression ; line breaks have been unfortunately lost in the process. I was trying to improve it but changed focus - see the EDIT)

I really do not want to distract the readers with those functions and parameters. What is your method ? What do you think of mine and what do you have in mind to make it work ? Thank you in advance for sharing !

EDIT: Found a way ! The idea is to use the new chunk option named code. When defining a new output hook, options$code stores the code in the form of a character string. One just needs to call the latex function on it and capture the output to use it as the new chunk output. This is how I implemented it (sorry if it is not best practice ; feel free to correct it) :

opts_chunk$set(latex=FALSE)
opts_template$set(latex=(list(results='asis',latex=TRUE)))

default.output<-knit_hooks$get("output")

knit_hooks$set(
  output=function(x,options){
    if(isTRUE(options$latex)){
      if(class(options$latex.args)=="list"){
        args<-options$latex.args
      }
      else {
        args<-NULL
      }
      default.output(
        paste0(
          capture.output(
            do.call("latex",
              append(list(object=eval(parse(text=options$code)),file=""),args)
            ))
          )[-1]
          ,collapse="")
        ,options)
    } else {
      default.output(x,options)
    }
  }
)

Now, this chunk gives me exactly what I want :

<<data,opts.label="latex",latex.args=list(caption="title")>>=
data.frame(a=c(1,2),b=c(2,3))
@

The code option is currently only available in the development version of knitr. It will be a feature in the next stable version according to the NEWS file in Yihui's github.

Upvotes: 0

Views: 1196

Answers (2)

YacineH
YacineH

Reputation: 63

Thanks to an upcoming feature of knitr 1.6 (the 'code' option) I have been able to solve this. I've edited the first post accordingly.

Upvotes: 0

Ramnath
Ramnath

Reputation: 55695

The echo option accepts numbers that allow you to specify which line numbers to display.

<<data, results = 'asis',echo = 1>>=
mytable<-data.frame(a=c(1,2),b=c(2,3))
latex(mytable,caption="title",file="",<other options...>)
@

Only thing to note is that line numbers are NOT based on physical number of lines, but completed expressions. So, for example, the following code will still count as ONE line of code.

mytable <- data.frame(
  a = c(1, 2),
  b = c(2, 3)
)

Upvotes: 4

Related Questions