1
votes

I'm having lots of fun with Knitr but noticed I am reusing code in a bad way - cut and paste. In my example I want to load a dataset, calculate some statistics and print those, and plot the dataset -- easy to do with a few chunks, but if I want to do the same thing with another dataset I have to copy and paste the chunks and change only the name of the dataset.

Suppose I have something like this :

<p>Load the dataset <tt>dataset01</tt></p>
<!--begin.rcode load-dataset01
# Create an alias so there is no need to change it several times in the
# chunks
myDataset <- dataset01
a <- calcSomeStats(myDataset)
input <- myDataset[,1:2]
ideal <- class.ind(myDataset$label)
end.rcode-->

<p>Now let's plot it</p>
<!--begin.rcode plot-dataset01, fig.width=10, fig.height=10
neurons <- 1
NNET = nnet(input, ideal, size=neurons,softmax=TRUE)
plotnet(NNET)
par(pty="s",xpd=T, mar=par()$mar+c(0,0,0,2))
axis(1, at = seq(bbox[1],bbox[2], by = 2), las=1)
axis(2, at = seq(bbox[1],bbox[2], by = 2), las=2)     
points(myDataset$x,myDataset$y, 
       col=myPal[unclass(myDataset$label)],cex=2,pch=16) 
legend("topright", levels(factor(myDataset$label)),fill=myPal,inset=c(-0.1,0))
end.rcode-->

Code is not really complete, there are other parts that I am still developing, but it is working.

My question is, considering the two chunks shown as code above, which is the best (or Riest) way to reuse it? Suppose I have a list of dozens of datasets and I want to run the same chunks on them, is possible even substituting the non-R, HTML parts. Is it possible?

I've naively tried to create a function but since it starts with this:

<!--begin.rcode
abc <- function(n)
  {
  <!--begin.rcode howdoInamethischunkwithanuniquename
  n <- n*2
  end.rcode-->
  }
end.rcode-->

it did not work (error: unexpected end of input)

thanks Rafael

Edit: there are similar questions with answers in Using loops with knitr to produce multiple pdf reports... need a little help to get me over the hump and https://github.com/yihui/knitr/issues/435 but they cover LaTeX and/or R markdown, not HTML.

Another edit: things I've tried after @Yuhui comment:

Using the same label for both chunks

<!--begin.rcode chunkA, echo=TRUE, results='hide'
x <- rnorm(100)
end.rcode-->

<p>Plot it?</p>

<!--begin.rcode chunkA, echo=FALSE, results='markup'
mean(x)
end.rcode-->

With this I get the "Error in parse_block(g[-1], g[1], params.src) : duplicate label 'chunkA'" message.

Using chunk option ref.label

<!--begin.rcode chunkA, echo=TRUE, results='hide'
x <- rnorm(100)
end.rcode-->

<p>Plot it?</p>

<!--begin.rcode chunkB, ref.label='chunkA', echo=FALSE, results='markup'
mean(x)
end.rcode-->

With this I get the R code (x <- rnorm(100)), "Plot it?" and then nothing. Changing echo to TRUE just repeat (x <- rnorm(100)).

More information

My scenario is having several small data frames that have the same structure (x,y,label) and I want to process them in a chunk "A" and plot them with similar parameters in another chunk "B". If I do this without reusing code, I have to copy-and-paste chunks "A" and "B" several times, which is not a really good idea.

I know I cannot pass a parameter to a HTML chunk, and the recipes at http://yihui.name/knitr/demo/reference/ seems close to what I need, but I cannot figure out how to do them in R+HTML.

2
See if yihui.name/knitr/demo/reference helps (<<>>).Yihui Xie
Thanks for the help, but I am still confused and cannot get the results I'm looking for. Please see the edited question for more examples and information.Rafael Santos

2 Answers

1
votes

OK, I got it, and am posting this to serve as an example.

From what I understand, it is not possible to create a knitr chunk that works as a function. So, this is not possible:

<!--begin.rcode fakeFunction
# do something with myData, assume it is defined!
end.rcode-->

<!--begin.rcode myPlot1 ref.label='fakeFunction'
myData <- iris
# Assume fakeFunction will be executed somehow with iris
end.rcode-->

<!--begin.rcode myPlot2 ref.label='fakeFunction'
myData <- cars
# Assume fakeFunction will be executed somehow with cars
end.rcode-->

What will work is something like this:

<!--begin.rcode
myData <- iris
end.rcode-->

<!--begin.rcode plot
summary(myData)
end.rcode-->

<!--begin.rcode
myData <- cars
end.rcode-->

<!--begin.rcode plot2, ref.label='plot'
end.rcode-->

Basically we're saying that chunk plot2 will "paste" the code from chunk plot. We don't need to define anything else in plot2, and I guess it will be ignored anyway.

I haven't figured out a detail, though. Suppose I have the chunk plot working OK (imagine dozens of lines of R code) and want a slight different behavior in plot2, that would impact a single line of code. From what I understand I won't be able to do this with knitr -- anyone knows how to reuse code by writing chunks as procedures or functions?

1
votes

I got similar ERRORs. What I did was to name the chunk differently or not name them at all.

For example {r, echo=F } some code here this is an example of a default code chunk without a name

{r setup, echo=F } some code here this is a chunk with name "setup."

Basically, if you have all chunk unnamed, or have all different named chunk, youll be fine.