Search code examples
rlatexknitrsweave

Splitting knitr Chunk code and output into two different knitrouts


The knitr Chunk option results = "hold" can put the output after the Chunk Code. I wonder how to split knitr Chunk code and output into two different knitrouts possibly with heading of Code and Output. Thanks in advance for your help.

\documentclass{article} 
\begin{document}

<< label=Test, results = "hold" >>=
1:100
args(lm)
@ 
\end{document}

Desired Output


Code

1:100
args(lm)

and


Output

 [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
 [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
 [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
 [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
 [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
 [91]  91  92  93  94  95  96  97  98  99 100
function (formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ...) 

Edited

I know this can be done by putting two chunks one showing only code and other showing only code. For long document this is an extra hassle. I wonder if this can be obtained with some hook.


Solution

  • You'll have to play around with formatting, but you can achieve this by modifying the source code hook. What I show below is actually a very simple modification of the basic render_latex hook that adds \\noindent\\textbf{Code:} before the code and \\noindent\\textbf{Output:} after it:

    \documentclass{article} 
    \begin{document}
    
    <<setup, include=FALSE>>=
    knit_hooks$set(
    source = function(x, options) {
          x = knitr:::hilight_source(x, 'latex', options)
          if (options$highlight) {
            if (options$engine == 'R' || x[1] != '\\noindent') {
              paste(c('\\noindent\\textbf{Code:}\\begin{alltt}', x, '\\end{alltt}', '','\\noindent\\textbf{Output:}'),
                    collapse = '\n')
            } else {
              if ((n <- length(x)) > 5) x[n - 3] = sub('\\\\\\\\$', '', x[n - 3])
              paste(c('\\noindent\\textbf{Code:}',x, '','\\noindent\\textbf{Output:}'),
                    collapse = '\n')
            }
          } else .verb.hook(x)
        }
    )
    @
    
    Here's your first chunk.
    
    <<chunk1, results = "hold" >>=
    1:100
    args(lm)
    @ 
    
    And here's another.
    
    <<chunk2, results = "hold">>=
    1:5
    6:10
    @ 
    
    That seems to be it.
    
    \end{document}
    

    Here's the result:

    enter image description here

    Thanks to a slight modification suggested by @mrbcuda in comments means you can separate the code and output frames:

    Here's the modification of the setup chunk:

    <<setup, include=FALSE>>=
    knit_hooks$set(
    source = function(x, options) {
          x = knitr:::hilight_source(x, 'latex', options)
          if (options$highlight) {
            if (options$engine == 'R' || x[1] != '\\noindent') {
              paste(c('\\noindent\\textbf{Code:}\\begin{alltt}', x, '\\end{alltt}', '','\\end{kframe}\\begin{kframe}\\noindent\\textbf{Output:}'),
                    collapse = '\n')
            } else {
              if ((n <- length(x)) > 5) x[n - 3] = sub('\\\\\\\\$', '', x[n - 3])
              paste(c('\\noindent\\textbf{Code:}',x, '','\\noindent\\textbf{Output:}'),
                    collapse = '\n')
            }
          } else .verb.hook(x)
        }
    )
    @
    

    And the resulting output:

    enter image description here