<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/documenting-r-packages-roxygen2-vs-direct-rd-input/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://www.enchufa2.es/archives/documenting-r-packages-roxygen2-vs-direct-rd-input.html"> R – Enchufa2</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a rel="nofollow" href="https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Rd-format" target="_blank">As the reader may know</a>,</p>
<blockquote>
<p>R objects are documented in files written in “R documentation” (Rd) format, a simple markup language much of which closely resembles (La)TeX, which can be processed into a variety of formats, including LaTeX, HTML and plain text.</p>
</blockquote>
<p>This LaTeX-like syntax, combined with the fact that the actual R objects live in a separate place, feels burdensome for many developers. As a consequence, there are a handful of tools aimed at improving the documentation process, one of which is <code>roxygen2</code>. We may say that the R community nowadays is divided between those who use <code>roxygen2</code> and those who don’t.</p>
<p>The <code>roxygen2</code> package allows us to write documentation right next to the code that is being described with decorated comments. The <a rel="nofollow" href="https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html" target="_blank">advantages</a> are the following:</p>
<blockquote>
<ul>
<li>Code and documentation are adjacent so when you modify your code, it’s easy to remember that you need to update the documentation.</li>
<li>Roxygen2 dynamically inspects the objects that it’s documenting, so it can automatically add data that you’d otherwise have to write by hand.</li>
<li>It abstracts over the differences in documenting S3 and S4 methods, generics and classes so you need to learn fewer details.</li>
</ul>
</blockquote>
<p>Although both <em>roxygenists</em> and <em>non-roxygenists</em> surely agree that <em>documentation is one of the most important aspects of good code</em>, the alleged benefits of <em>roxygen2</em> could turn into a disadvantage. <a rel="nofollow" href="https://stat.ethz.ch/pipermail/r-devel/2018-January/075463.html" target="_blank">In the words of Duncan Murdoch</a>,</p>
<blockquote>
<p>This isn’t the fashionable point of view, but I think it is easier to get good documentation [by directly editing Rd files] than using Roxygen. […]</p>
<p>The reason I think this is that good documentation requires work and thought. You need to think about the markup that will get your point across, you need to think about putting together good examples, etc. This is <em>harder</em> in Roxygen than if you are writing Rd files, because Roxygen is a thin front end to produce Rd files from comments in your .R files. To get good stuff in the help page, you need just as much work as in writing the .Rd file directly, but then you need to add another layer on top to put in in a comment. Most people don’t bother.</p>
</blockquote>
<p>Basically, <code>roxygen2</code>’s point is that you don’t need to work in the syntax, so that you can use that time to write actual documentation. Duncan’s point, instead, is that, if you don’t put effort in the writing process, there’s a chance that you won’t put any effort at all. Although I’m a happy <code>roxygen2</code> user, I can see there’s a point in there, and an interesting analysis to be done.</p>
<p>In fact, <em>if you happen to have an uncompressed copy of CRAN</em> under, let’s say, <code>~/cran</code>, you can execute the following script:</p>
<pre><code><span>## Requires: r-lib/pkgdown, readr</span>
setwd(<span>&quot;~/cran&quot;</span>)

get_lines &lt;- <span>function</span>(Rd) {
  <span># render as txt</span>
  txt &lt;- <span>try</span>(capture.output(tools::Rd2txt(Rd)), silent=<span>TRUE</span>)
  <span>if</span> (inherits(txt, <span>&quot;try-error&quot;</span>)) <span># &quot;rcqp&quot; throws an error, why?</span>
    <span>return</span>(c(documentation=<span>NA</span>, examples=<span>NA</span>))
  <span># remove blank lines</span>
  txt &lt;- txt[!grepl(<span>&quot;^[[:space:]]*$&quot;</span>, txt)]
  <span># split documentation and examples</span>
  examples &lt;- grep(<span>&quot;_\bE_\bx_\ba_\bm_\bp_\bl_\be_\bs:&quot;</span>, txt)
  <span>if</span> (length(examples)) {
    doc &lt;- txt[<span>1</span>:(examples-<span>1</span>)]
    exm &lt;- txt[(examples+<span>1</span>):length(txt)]
  } <span>else</span> {
    doc &lt;- txt
    exm &lt;- <span>NULL</span>
  }
  <span># remove titles</span>
  doc &lt;- doc[!grepl(<span>&quot;_\b&quot;</span>, doc)]
  <span># output</span>
  c(documentation=length(doc), examples=length(exm))
}

do.call(rbind, parallel::mclapply(Sys.glob(<span>&quot;*&quot;</span>), <span>function</span>(pkg) {
  message(<span>&quot;Parsing &quot;</span>, pkg, <span>&quot;...&quot;</span>)
  rds &lt;- Sys.glob(file.path(pkg, <span>&quot;man&quot;</span>, <span>&quot;*.[R|r]d&quot;</span>))
  <span>if</span> (!length(rds))
    df &lt;- data.frame(documentation=<span>0</span>, examples=<span>0</span>, functions=<span>0</span>)
  <span>else</span> {
    <span># get no. lines for documentation &amp; examples</span>
    df &lt;- as.data.frame(t(rowSums(sapply(rds, get_lines), na.rm=<span>TRUE</span>)))
    <span># get no. exported functions</span>
    df$functions &lt;- sum(sapply(rds, <span>function</span>(rd) {
      rd &lt;- pkgdown:::rd_file(rd)
      length(pkgdown:::usage_funs(pkgdown:::topic_usage(rd)))
    }))
  }
  <span># RoxygenNote present?</span>
  desc &lt;- file.path(pkg, <span>&quot;DESCRIPTION&quot;</span>)
  df$roxygen &lt;- !is.na(read.dcf(desc, fields=<span>&quot;RoxygenNote&quot;</span>)[[<span>1</span>]])
  df$pkg &lt;- pkg
  df
}, mc.cores=parallel::detectCores())) -> docLines

readr::write_csv(docLines, <span>&quot;docLines.csv&quot;</span>)</code></pre>
<p>to get <a rel="nofollow" href="https://www.enchufa2.es/wp-content/uploads/2018/02/docLines.csv" target="_blank">this data frame</a>. For each package on CRAN, we extract the number of lines of documentation and examples under the <code>man</code> directory, as rendered by <code>tools::Rd2txt</code>. We also count how many functions are documented, and we scan the <code>DESCRIPTION</code> file looking for the <code>RoxygenNote</code>, to tell which packages use <code>roxygen2</code>. This is all I need to see what I was looking for:</p>
<pre><code><span>library</span>(ggplot2)
<span>library</span>(dplyr)
<span>library</span>(tidyr)

docLines &lt;- read.csv(<span>&quot;docLines.csv&quot;</span>) %>%
  filter(functions > <span>0</span>) %>%
  gather(<span>&quot;type&quot;</span>, <span>&quot;lines&quot;</span>, documentation, examples)

ggplot(docLines, aes(lines/functions, color=roxygen, fill=roxygen)) + theme_bw() + 
  geom_density(alpha=<span>.3</span>) + facet_wrap(~type) + scale_x_log10()</code></pre>
<pre><code>## Warning: Transformation introduced infinite values in continuous x-axis</code></pre>
<pre><code>## Warning: Removed 221 rows containing non-finite values (stat_density).</code></pre>
<p><img sizes="(max-width: 739px) 100vw, 739px" src="https://i1.wp.com/www.enchufa2.es/wp-content/uploads/2018/02/unnamed-chunk-2-1-739x528.png?w=450&ssl=1" alt="" class="wp-image-65485" data-recalc-dims="1"></p>
<p>Limitations:</p>
<ul>
<li>This talks about <em>quantity</em>, but not about <em>quality</em>.</li>
<li>The method of extraction of documentation and examples is very coarse. For sure there are better ways.</li>
<li>The amount of documentation must be weighted in some way. Just dividing it by the number of exported functions and methods may not be the best way.</li>
<li><code>roxygen2</code> appeared in 2011, but I think it became more popular in recent years. It may be interesting to restrict the analysis to recent packages.</li>
<li>Some developers prioritise vignettes over examples. It may be another interesting factor to analyse.</li>
</ul>
<p>But all in all, I believe that this simple analysis proves Duncan right to some extent. And as a <code>roxygen2</code> user that very much cares about documentation, this warns me against my own biases. If you care too, make sure that you really take advantage of the time you save with <code>roxygen2</code>.</p>
<p><em>Article originally published in Enchufa2.es: <a rel="nofollow" href="https://www.enchufa2.es/archives/documenting-r-packages-roxygen2-vs-direct-rd-input.html" target="_blank">Documenting R packages: roxygen2 vs. direct Rd input</a></em>.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.enchufa2.es/archives/documenting-r-packages-roxygen2-vs-direct-rd-input.html"> R – Enchufa2</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/STLr7XayjAo" height="1"></a></div>