R package development

Lancaster University, 22 May 2013

Markus Gesmann
Maintainer of the googleVis and ChainLadder packages

Download

Disclaimer

  1. I am an autodidact
  2. What I present here works for me
  3. Read and follow the official R Manuals for the truth

Agenda

  1. Motivation
  2. The basics of R package development
  3. Automated package development with roxyPackage

Why I started to develop packages

  1. I was fed up with copy and paste, or even source
  2. I wanted to share my code with others
  3. My R files were a mess
  4. I needed structure, a guiding framework

The challenges I had to face

  1. I had lots of R files, mixing scripts and functions
  2. Very little documentation
  3. Few examples
  4. No tests
  5. Hence, it took ages to prepare my code for CRAN

When I start today

  1. I write small functions
  2. Name them properly
  3. Document them immediately
  4. Include self contained examples
  5. Use a version control system
  6. Start writing a vignette
  7. Consider test scenarios
  8. Prepare longer examples in demo files
  9. Well, I try to do 1 to 8

But, what if you don't want to share your code?

  1. Big mistake!
  2. You do want to share your code
  3. At least with yourself - in years to come
  4. As you get older, you will turn into someone else
  5. You will value your past documentation and discipline

What is R package development about?

  1. A structured framework for R development
  2. Best practice
  3. Minimum checks and testing
  4. A cycle of
    • R CMD BUILD myPackage
    • R CMD CHECK myPackage_Version.tar.gz
    • R CMD INSTALL

What is an R package?

  1. A collection of files
  2. Installed packages live in a folder called library
  3. library(myPackage) will load package functions into memory
  4. Auto-completion for package functions becomes available

What do you need to get started?

Test your setup with googleVis

  1. Download the source code archive of googleVis
  2. Open a command line window
  3. Check if R is in your programme path
  4. Navigate to the download file
  5. Extract the archive:
    • gunzip googleVis_0.x.y.tar.gz
    • tar xvf googleVis_0.x.y.tar
  6. Run R CMD BUILD googleVis
  7. Run R CMD CHECK googleVis_0.4.2.tar.gz
  8. Run R CMD INSTALL googleVis_0.4.2.tar.gz

R package structure

  • DESCRIPTION
  • NAMESPACE
  • sub-directories:
    • mandatory: R, man
    • optional: data, demo, vignettes, po, exec, inst, tests
  • Structure can be generated by
    • package.skeleton from R

Minimal DESCRIPTION file

Package: HelloWorld
Type: Package
Title: What the package does (short line)
Version: 1.0
Date: 2013-05-05
Author: Who wrote it
Maintainer: Who to complain to <yourfault@somewhere.net>
Description: More about what it does (maybe more than one line)
License: What license is it under?

Extract of googleVis DESCRIPTION

Package: googleVis
Type: Package
Title: Interface between R and the Google Chart Tools
Version: 0.4.2
Date: 2013-03-16
Authors@R: c(person("Markus", "Gesmann", role = c("aut", "cre"),
                     email = "markus.gesmann@gmail.com"),
            person("Diego", "de Castillo", role = "aut",
                     email = "decastillo@gmail.com"),
                   person("Joe", "Cheng", role = "ctb",
                    email = "joe@rstudio.com"))
Description:  The googleVis package provides ...  
Depends: R (>= 2.11.0)
Imports: methods,RJSONIO,utils 
Suggests: shiny (>= 0.4.0)
License: GPL (>= 2)

NAMESPACE

  • R has a namespace management system for code in packages
  • This system allows the package writer to specify
    • which variables in the package should be exported to make them available to package users,
    • which variables should be imported from other packages.

googleVis NAMESPACE

importFrom(grDevices)     
importFrom(methods, setMethod)       
importFrom(utils, packageDescription)        
importFrom("RJSONIO", "toJSON")
# User functions
export(gvisMotionChart, gvisTable, gvisGeoMap,gvisTreeMap,gvisMap, gvisAnnotatedTimeLine)        
export(gvisScatterChart, gvisPieChart, gvisOrgChart, gvisIntensityMap)       
export(gvisLineChart, gvisAreaChart, gvisBarChart, gvisColumnChart, gvisGauge)       
export(gvisGeoChart, gvisComboChart, gvisBubbleChart)        
export(gvisCandlestickChart, gvisSteppedAreaChart)       
export(gvisMerge, createGoogleGadget)        
export(plot.gvis, renderGvis)
# Methods        
S3method(plot, gvis)         
S3method(print, gvis)

R files

  • Should only contain R functions
  • Of course, they should have plenty of inline comments
  • Every function, which is exported to the user needs to be documented in a help file
  • prompt(myfunction) generates template help file for you

Writing R help files

  • Rd-help files live in the man directory
  • Format is a mixture of LaTeX and HTML
  • Structure is always the same, only some sections are mandatory
  • Functions are categorised by R keywords
  • R CMD CHECK checks that
    • all user functions are documented
    • all arguments are listed
    • all examples work
    • Rd-format is valid

Hello World Example

hello <- function(name){paste("Hello", name)}
hello('World')
[1] "Hello World"

prompt(hello)
# Created file named ‘hello.Rd’.
# Edit the file and move it to the appropriate directory.

hello.Rd - part 1/3

\name{hello}
\alias{hello}
%- Also NEED an '\alias' for EACH other topic documented here.
\title{
%%  ~~function to do ... ~~
}
\description{
%%  ~~ A concise (1-5 lines) description of what the function does. ~~
}
\usage{
hello(name)
}
%- maybe also 'usage' for other objects documented here.
\arguments{
  \item{name}{
%%     ~~Describe \code{name} here~~
}
}

hello.Rd - part 2/3

\details{
%%  ~~ If necessary, more details than the description above ~~
}
\value{
%%  ~Describe the value returned
%%  If it is a LIST, use
%%  \item{comp1 }{Description of 'comp1'}
%%  \item{comp2 }{Description of 'comp2'}
%% ...
}
\references{
%% ~put references to the literature/web site here ~
}
\author{
%%  ~~who you are~~
}
\note{
%%  ~~further notes~~
}

hello.Rd - part 3/3

%% ~Make other sections like Warning with \section{Warning }{....} ~
\seealso{
%% ~~objects to See Also as \code{\link{help}}, ~~~
}
\examples{
##---- Should be DIRECTLY executable !! ----
##-- ==>  Define data, use random,
##--  or do  help(data=index)  for the standard data sets.
## The function is currently defined as
function (name) 
{
    paste("Hello", name)
  }
}
% Add one or more standard keywords, see file 'KEYWORDS' in the
% R documentation directory.
\keyword{ ~kwd1 }
\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line

Exercise 1

  • Create a HelloWorld package
  • Run a cycle of
    • R CMD BUILD
    • R CMD CHECK
    • R CMD INSTALL

Simplify package development

  1. Maintaining R and Rd files separately requires discipline
  2. Instead, write documentation into R file, on top of your function
  3. Let roxygen2 extract the documentation and generate the Rd-files
  4. Even better, roxyPackage can generate a whole package from your R files

Case study with roxyPackage

  • Create a folder called HelloWorld
  • Create a sub-folder called R
  • Create the file hello.R in the R folder

hello.R

#' Hello World function
#'
#' Say Hello
#' 
#' This function is a basic Hello World function in R. It uses the
#' \code{\link{paste}} function to say hello to someone.
#' 
#' @param name. Default is set to 'World'.
#' @author Markus Gesmann 
#' @keywords print
#' @seealso \code{\link{paste}} 
#' @export
#' @examples
#'  hello()
#'  hello(c("Alice", "Bob")

hello <- function(name="World"){
  paste("Hello", name)
}

Define DESCRIPTION in data

myDescription <- data.frame(
  Package="HelloWorld",
  Type="Package",
  Title="Hello World",
  Author="Markus Gesmann <markus.gesmann@gmail.com>",
  Maintainer="Markus Gesmann <markus.gesmann@gmail.com>",
  Depends="R (>= 2.10.0)",
  Description="Hello World package",
  License="GPL (>= 3)"
)

Create package with roxy.package

library(roxyPackage)
roxy.package(
  pck.source.dir="~/Desktop/HelloWorld/",
  R.libs="/Library/Frameworks/R.framework/Resources/library/",
  repo.root="~/Desktop/repo",
  pck.version="0.1",
  pck.description=myDescription, 
  actions=c("roxy", "doc", "html", "package", "check")
)

Advantages of roxyPackage

Exercise 2:

  • Create HelloWorld package with roxyPackage

Package demos

  • Demos are plain R files in the demo sub-directory
  • Additionally a file 00Index is required, which lists the R files with a short description

00Index file of googleVis

googleVis   Examples of various googleVis functions and plots
AnimatedGeoMap      Prototype of an animate a geo map with JavaScript
EventListener       Examples of basic JavaScript event handlers
WorldBank       Visualising country level data sourced from the World Bank
Rrsp            Demo showing how googleVis can work with the R.rsp package

Vignettes

  • Sweave Rnw-files in the vignettes folder are build automatically
  • Since R-3.0.0 Markdown files are also accepted

Some further notes

  • Data
  • zzz.R
  • inst\shiny
  • inst\rsp

What I haven't covered ...

  • Version control software, e.g.
    • Git, SVN, ...
    • Poor man solution: Dropbox, Google Drive, Time Machine
  • How to Include C, C++, Fortran code into your package
  • How to upload your package to CRAN

Useful R development links

The End. So what ...?

  • You always programme for someone else and it could be your future you
  • Package development provides you a good framework for dicipline
  • There is no excuse. It isn't that hard.

How I created these slides

library(slidify)
setwd("~/Dropbox/Lancaster/")
author("PackageDevelopment")
## Edit the file index.Rmd file and then
slidify("index.Rmd")

Thanks

  • R Core for their hard work and support
  • Hadley Wickham, Peter Danenberg and Manuel Eugster for roxygen2
  • Meik Michalke for roxyPackage
  • Ramnath Vaidyanathan for slidify
  • Rebecca and Idris for their invitation to Lancaster

Contact

Session Info

sessionInfo()
## R version 3.0.1 (2013-05-16)
## Platform: x86_64-apple-darwin10.8.0 (64-bit)
## 
## locale:
## [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] slidify_0.3.3
## 
## loaded via a namespace (and not attached):
## [1] digest_0.6.3   evaluate_0.4.3 formatR_0.7    knitr_1.2     
## [5] markdown_0.5.4 stringr_0.6.2  tools_3.0.1    whisker_0.3-2 
## [9] yaml_2.1.7