EGU 2019 | Thu, 11 Apr, 08:30–10:15, Room -2.62

Before we start

Before we start

Who we are

  • Sebastian Kreutzer is a Post-doc at Université Bordeaux Montaigne, working on landscape evolution, luminescence dating and data science.

  • Michael Dietze is a Post-doc at the GFZ Potsdam, working on the seismic signals emitted by Earth surface processes.

Before we start

And who are you?

  • Your first task: Introduce yourself to the others
    • What is your educational background and your career stage?
    • For what purpose do you want to build R packages?
    • What do you expect from this course?

Before we start

Today's schedule

  • R packages – an introduction (15 min)
  • Structure and contents of R packages (20 min)
  • Git and how it works together with R (10 min)
  • Initiating an R package with RStudio (20 min)
  • Writing a function with 'roxygen2' (20 min)
  • Unit tests of package functionality (15 min)
  • Wrap up, feedback and resources (5 min)

R packages – What?

R packages – What?

  • This course covers
    • a brief idea of the concept of R packages
    • a discussion/justification of package contents
    • hands-on work to build a package
  • You are looking for an introduction to R … sorry, bad luck!

R packages – What?

What you should be already familiar with

  • R and RStudio
  • Installing and using R packages
  • Writing scripts (and functions)
  • Structuring code and following good practice rules

  • You are looking for an introduction to R … sorry, bad luck!*

(*) Don't repeat yourself.

R packages

Further resources

R packages

Prerequisites and computational minions

  • Git, a versioning tool for all kinds of software source code (and beyond)
  • RStudio: The skin for R, a proper developer (and user) environment
    • Auto completion, syntax highlighting, context help
    • Version control and project management
  • The R package 'devtools' by H. Wickham, J. Hester & W. Chang
  • The R package 'roxygen2' by H. Wickham, P. Danenberg & M. Eugster
  • The R package 'testhat' by H. Wickham, R Core Team

R packages

Concepts

  • R lives from sharing code, packages are the vehicles carrying this idea
  • Packages can be the pillars for open and reproducible science
  • Packages comprise the full set of self-contained components

R packages

Some illusions

  • R packages have to go to the Comprehensive R Archive Network (CRAN)
  • Writing R packages is a lot of boring effort
  • You can start easy and add further details later
  • People will use your package in the way you designed it

R packages

Why writing packages

  • You want to share your code with others
  • The code is organised in a coherent way
  • You want to distribute only a single file
  • Bundling code makes keeping track much easier than collecting scripts
  • The code is automatically tested (by your examples and other routines)

Working with packages simply saves time and brain cells

R packages – Contents

R package contents

An overview


What do you think? What belongs to an R package?

R package contents

An overview of obvious material

  • A name (yes, a package name)
  • A description (the meta information)
  • A function (yes, there are packages with only one function)
  • A documentation (you want to understand what the function does)
  • A working examples (you don't want to rely on the documentation, only)

  • A set of further stuff that will be covered later

R package contents

An overview

R package contents

The package name

  • This is (or should be) the hardest job when creating a package
  • Requirements
    • Only letters, numbers and periods are allowed
    • Start with a letter, do not end with a period
  • Advice
    • Pick a unique name you can google, best describing your package
    • Check if the name already exists beforehand

R package contents

The DESCRIPTION file

  • The mandatory file that defines all the metadata of the package: name & short title, version & date, author & contact, license & dependencies:

R package contents

The DESCRIPTION file - Title and description

  • Title must be capitalised, only one line, not ending with a period
  • Description can be several sentences, but only one paragraph. Lines can only contain 80 characters and must be indented by 4 spaces.
Title: Environmental seismology toolbox
Description: A collection of functions to handle seismic data for the
    purpose of investigating the seismic signals emitted by Earth surface
    processes. The package supports inporting standard formats, data 
    preparation and analysis techniques and data visualisation.
  • Both elements are important. They will be indexed and Google has learned a lot to spot R packages.

R package contents

The DESCRIPTION file – Dependencies

  • Dependency options in short (read more):
    • Depends: all packages your package essentially needs to run
    • Imports: will be covered by the namespace section
    • Suggests: optionally needed packages
    • LinkingTo: needed to reference C++/C libraries
  • CRAN became strict with the number entries in 'Depends'. Use importFrom() in the file NAMESPACE, instead.

R package contents

The DESCRIPTION file – Author information and roles

  • Essential for correct citation of packages! Nota bene: Type citation("PACKAGENAME") to see how a package should be cited
  • Don't use fake mails. CRAN and users cannot communicate with you.
  • Author information can be defined more comprehensively (read more):
Authors@R: person("First", "Last", email = "first.last@example.com",
                  role = c("aut", "cre"))

CRAN supports ORCID

Authors@R: person(...,
                  comment = c(ORCID = "0000-0002-9079-593X"))

R package contents

The DESCRIPTION file – License issues

  • The key element to inform who can use the package for which purpose!
  • Either a link to a license file (License: file LICENSE) or a keyword of standard licenses (read more):
    • GPL-2 or GPL-3: copy-left license , other users must license code GPL-compatile. Common for CRAN-submission.
    • CC0: give away all rights, anything can be done with the code
    • BSD or MIT: permissive licenses, require additional file LICENSE.

R package contents

The DESCRIPTION file – Version patterns

  • Version numbers must be numeric and separated by a period.
  • They are more than just counters, they define dependency satisfactions

  • Format: MAJOR.MINOR.PATCH (start a released package with 0.1.0)
    • MAJOR releases should be rare
    • MINOR releases should keep the package up to date
    • PATCH releases may be frequent (but think of CRAN team time budget)
  • Make use of a NEWS file (e.g., NEWS.md) to announce history & changes.

R package contents

Further contents

R package contents

R code

  • The actual function definitions
  • Will be covered by the next section

R package contents

Code documentation

  • The (second) most important part of a reasonable package
  • Omitting it means, nobody will be able to use your package

  • Documentation in R is reference documentation (dictionary like)
  • Additional documentation is covered by vignettes (not covered here)

  • Documentation in *.Rd-files is formalised, in pseudo LaTeX scheme (short version, long version)

R package contents

Code documentation - code example

R package contents

Code documentation - what does it look like

R package contents

Code documentation

  • Why should you not attempt to build documentation files manually?
    • Tedious, clumsy, not intuitive
    • Prone to forget updating after changing the function
  • Alternative, write documentation in function definitions
    • roxygen2
    • inlinedocs (no longer updated)
  • Application see next section

R package contents

Examples and example data

  • Working (and worked) examples are mandatory documentation items
  • Serve two things
    • Explain usage of the function
    • Creates a test, executed every time the package is built
  • Typically useful to include example data sets
    • Must be provided as *.rda files (generated with save())
    • Must be stored in directory data
    • Must be documented individually

R package contents

Further contents

  • Namespace (will be dealt with automatically, read more)
    • Defines function name assignments to packages
  • Compiled code (not covered here)
    • C++ code present in src will be compiled during installation
  • Shiny apps and other installed software (not covered here)
    • further files/software in inst will be copied to main directory

Time for a short brainstorming break!

Pffffft, a lot of dense and boring input, right?

Brainstorming break

The task: Think about and collect the essential items for your own package. Note the results in a plain text document for later use. Time: about 5 minutes.

We will need this material soon to build a package, … an empty one, … which will finally only have one function.

Already need a short reminder? :)

Brainstorming break

  • package name
  • package title
  • package description
  • version and date
  • author(s)
  • maintainer (plus email address)
  • license

and versioning your R package

  What are possible reasons making us think about it?

  • Software is an organism, it lives, it evolves, it ages and it gets constantly kicked by changed hardware … eventually it even dies.

  • Thus, software needs to be maintained and updated. But by more than just fixing a bug and raising the version number.

  • Coding and maintenance work should be handled as open, transparent and coherent as possible.

 This is where versioning software comes into play

  

  • is a powerful versioning tool (software), and R and RStudio perfectly align with it.

  • The process tracks all code changes on your computer

  • can be run locally but the full power is revealed through online platforms such as GitHub or GitLab where you can maintain your code.

  • To interact with these platforms, you can either use the terminal or GUI based clients such as SmartGit or GitHub Desktop

RStudio is also shipped with a basic client, which we will use in the following.

Versioning and - concepts

  Some keywords in the context of

  • stage: mark a step in the development process
  • revert: revert recently made changes
  • ignore: exclude a particular file from getting monitored by the process
  • commit: make your code changes part of the entire project (along with a comment)
  • push: move your code changes to an online platform
  • pull: grab your new changes from an online platform

Converting a package to a local repository

Back to RStudio

  • Menu > Tools > Project Options > Git/SVN
  • Select as version control option
  • Confirm and let RStudio restart itself

  • Note the changes in the restarted version
    • A new icon in the menu bar (green plus, red minus, grey circle)
    • A new tab in the upper right window of RStudio
  • Click on the tab in the upper right window

Converting a package to a local repository

The pane in RStudio

Converting a package to a local repository

The pane

  • The pane shows all items (files) that have experienced a change
  • There are three categories:
    • Untracked (yellow ?)
    • Modified (blue M)
    • Deleted (red D)
  • Click on icon Diff shows in-depth view on changes to a file

Converting a package to a local repository

  • That was it! All changes made will now be tracked.

  • First things first: account for untracked items
    • Mark all untracked files and check them
    • Then click "Commit"
    • In the new window, you need to add a comment to the commit (don't comment silly things, commits will be there for eternity)
  • After clicking on "Commit" explore the Commit History (click on "History")
    • All changes are listed (green = added, red = deleted)

Converting a package to a local repository

  • So let us make some changes.
    • Add a new function.
    • Modify the silly "Hello World" function.
    • Build the package.
  • Explore the Git pane
    • Which files are there?
    • Commit the changes.
    • Explore the history.

Some more details about

Commits

  • Commits are the fundamental unit of version control in (like saving a file under a different name)
  • Commit whenever you have solved an isolated issue but not before it is done properly
  • Commit comments should allow understanding what was done and why it was done, after years

Some more details about

Traceback and correct mistakes

  • Before you committed a change (but after saving the file), right-click on the file to restore and choose "Revert"
  • Use the history to trace back when something was changed longer ago
    • Copy the SHA (secure hash algorithm, i.e. unique commit ID)
    • Use the console for restoring this commit (git checkout <SHA> <filename>)
    • Looks clumsy, right? See SmartGit slide for an alternative.

Creating a package in RStudio

Creating a package in RStudio

Start with a new project: Menu > File > New Project…

Make sure you tick the option "create as git repository".

Creating a package in RStudio

Start with a new project: Menu File > New Project…

Creating a package in RStudio

The template as overview

  • A new RStudio-project is started (file PACKAGE_NAME.Rproj)
  • Close and delete the template function and its documentation straight away.
  • Next jobs
    • Configure the Build tools: Allow 'roxygen2' to build the documentation
    • Inspect the Environment window, do you see the tabs "Build" and "Git"?

Creating a package in RStudio

Configure the package building process

  • Configure the Build tools: Menu > Tools > Project Options > Build Tools
    • make sure to check "Generate documentation with 'roxygen2'".

Creating a package in RStudio

Preparing the Git work flow

  • Go to the Git tab

  • Check all "untracked" items (yellow ? tags)
  • They will turn green, i.e., they are now "staged".
  • Make your first commit for these files, naming it "Package initiation"
  • Close the Git console window

  • Done! Your first package skeleton is made and Git is set up with it.

Action time

The task (time 5 minutes): Modify the DESCRIPTION file that it contains your own information. Modify all the auto generated information.

Creating a package in RStudio

Update your work and changes in Git

  • Inspect the Git tab in the Environment window
  • Any changes occurring? The file DESCRIPTION in modified (blue M flag).
  • Stage it (check the box) and click on the Commit button

  • Inspect the red and green lines, this documents your changes.
  • If ok, write a useful commit message and commit the changes.

Creating a package in RStudio

Everything ready? Let's check and build the package

  • We have a clean package skeleton and an updated Description file, right?
  • Let R check the package for integrity: Click on the "Check" button
  • A series of (hopefully positively evaluated) checks are run.

  • If everything is ok, click on "More" > "Build Source Package".
  • Your first R package should be in your project directory.

Creating a package in RStudio

Build a source version hardcopy

  • To share the package, you need to build a source version of it
    • Menu Build > Build Source Package
    • You find a PACKAGE_VERSION_tar.gz-file in your R directory
  • Packages for Windows-users need to be compiled in a different way
  • These packages are ready, they can be freely distributed and installed locally.

Action time

The task (time 5 minutes): Build your first package.

  • Commit the Description file changes
  • Check the package
  • Build the package

From scripts to functions

From scripts to functions

An unfortunate start …

a <- 10:50
print(a)
plot(a)
b <- 210:250
plot(a, b)
A <- a * b
c <- 5
V <- A * c
print(A)
print(V)
plot(a,V)

From scripts to functions

… ok …

a <- 10:50
b <- 210:250
c <- 5

A <- a * b
V <- A * c

plot(a)
plot(a, b)
plot(a,V)

print(a)
print(A)
print(V)

From scripts to functions

… better …

## define object geometry
a <- 10:50
b <- 210:250
c <- 5

## calculate area and volume
A <- a * b
V <- A * c

## plot object dimensions
plot(a)
plot(a, b)
plot(a, V)

## print values
print(a)
print(A)
print(V)

From scripts to functions

Wrapping code to functions

f <- function(a, b, c) {
  
  ## calculate area and volume
  A <- a * b
  V <- A * c

  ## plot object dimensions
  plot(a)
  plot(a, b)
  plot(a, V)

  ## return values
  return(list(A = A,
              V = V))
}

From scripts to functions

Wrapping code to functions

f <- function(a, b, c, plot = TRUE) {
  
  ## calculate area and volume
  A <- a * b
  V <- A * c

  ## optionally plot object dimensions
  if(plot == TRUE) {
    
    plot(a)
    plot(a, b)
    plot(a, V)
  }

  ## return values
  return(list(A = A,
              V = V))
}

From scripts to functions

Wrapping code to functions

f(a = 10, b = 100, c = 5, plot = FALSE)
## $A
## [1] 1000
## 
## $V
## [1] 5000

From scripts to functions

In words

  • Structure your script
    • Variable/object/argument definitions
    • Data checks and automatic assignments (remember these as TESTS)
    • Data manipulation/evaluation
    • Optional further outputs
    • Return object creation
  • Wrap it into a function definition
    • FUNCTION_NAME(ARUMENT_1, ARGUMENT_2) {FUNCTION BODY}

From scripts to functions

In words

  • Ooops, what did we forget?

From scripts to functions

In words

  • Ooops, what did we forget?

  • Function documentation (in a separate file)

\name{f}
\alias{f}
\title{Calculate and plot cuboid areas and volumes.}
\usage{f(a, b, c, plot = TRUE)}
\arguments{
\item{a}{\code{Numeric} vector, length of the cuboid.}
\item{b}{\code{Numeric} vector, width of the cuboid.}
\item{c}{\code{Numeric} vector, height of the cuboid.}}
\value{A list with cuboid area and volume.}
\description{The function takes numeric vectors of the cardinal 
  dimensions of a cuboid object and calculates area and volume. The results can optionally be plotted.}
\examples{f(a = 10, b = 100, c = 5, plot = FALSE)}
\author{Michael Dietze}

From scripts to functions

Documentation using 'roxygen2'

  • So why not writing documentation into the function definition file?

Another brief function example

f <- function(x, p = 2) {
  ## calculate the power of x
  y <- x^p

  ## return value
  return(y)
}

From scripts to functions

Documentation using roxygen2

Can be rewritten like this:

#' @title Calculate the power of a vector               # TITLE
#' 
#' @description The function calculates something       # DESCRIPTION
#' 
#' @details The function simply combines the arguments. # DETAILS 
#'
#' @param x input vector                                # ARGUMENTS
#' @param p power exponent                              # ARGUMENTS
#' @return vector of the power p of x.                  # VALUE
#' @author Michael Dietze                               # AUTHOR(S)
#' @examples
#' f(x = 10, p = 3)                                     # EXAMPLES
f <- function(x, p = 2) {                               # USAGE
  return(x^p)
}

From scripts to functions

Documentation using roxygen2

And become something like:

From scripts to functions

Documentation using roxygen2

  • 'roxygen2' is a package that parses function source files for tags (e.g., #' @param) and converts them to the structure of a *.Rd-file.

  • First line becomes the title (thus, keep it to one line)
  • Second set of lines becomes becomes description
  • Third and further set of lines becomes details (optional)

  • Further down follow tagged items

From scripts to functions

Documentation using roxygen2

  • @param - Function arguments, note argument and then description
  • @return - Function value
  • @examples - Examples section
  • @export - Namespace export, usually the function name
  • @seealso - Related functions to link to
  • @keywords - Well, keywords
  • @section - Arbitrary sections to further structure the documentation

From scripts to functions

Documentation using roxygen2

  • Further LaTeX-like tags to structure the text can be
    • Text formatting (\emph{}, \strong{}, \code{})
    • Links (\code{\link{}}, \href{}{})
    • Lists (\enumerate{}, \itemize{})
    • Equations (\eqn{}, \deqn{})
    • Tables (\tabular{}{\tab \cr})
  • Details see here, Example see source of Luminescence::analyse_baSAR.R

Time to move the fingers!

Pffffft, no more details please!

Action time

The task (time 10 minutes): Write a function that can multiply a numeric vector (x) by a constant (c, default is 1) and return the result. Document the function using 'roxygen2' tags.

Hands-on session

#' Multiply a vector by a constant
#' 
#' The function uses simple R functionalities to multiply a numeric 
#' vector x by a constant c and returns the resulting vector.
#' 
#' @param x Numeric vector to be multiplied
#' @param c Numeric value multiplicator, default is \code{1}
#' @return Numeric vector, product of \code{x} and \code{c}
#' @author Michael Dietze
#' @examples
#' data(x)
#' mtp(x = x, c = 2)
#' @export mtp
mtp <- function(x, c = 1) {
  return(x * c)
}

Hands-on session

  • WELL DONE! You have built your first package containing a fully documented function!

  Maintaining a package

  Maintenance

What does it mean?

  • DO NOT abandon your package!

  • Bug-fixing (your code is never perfect)
  • Feature enhancements (for yourself or for your users)
  • Code refactoring, package structure changes
  • Reacting to changes in R, package dependencies or on CRAN

But how do you spot bugs and how do you ensure that your code is still doing what you intended in the first place? Manual testing? Good luck!

  What kind automated tests exist

  1. 'Platform tests': Can your package be checked and built without errors on other platforms, such as Windows, Linux, and MacOS

  2. Unit tests: testing your code using dedicated test scenarios (we will cover that later)

  Standard tests on CRAN

Once you have submitted a package to CRAN, it becomes subject to regular tests using different platforms and old, stable and development versions of R. CRAN knows three status flags:

  • NOTE (take it into account if possible)
  • WARNING (you should consider to do something about it)
  • ERROR (you must act)

If you fail to address errors within a certain period of time, your package may be removed from CRAN.

  My most recent experience

… or you simply receive a message out of the blue …

Date 2019-04-10
From CRAN Team
To Package maintainers
Subject CRAN packages stripping unconditionally


> Please remove unconditional stripping ASAP and before Apr 24 to safely retain the package on CRAN.

  Standard tests on CRAN

Example R package 'Luminescence'

  Common other test environments AppVeyor

Example R package 'Luminescence'

  Common other test environments Travis

Example R package 'Luminescence'

  The full test process - an example

Fig: Kreutzer et al., 2017

  Unit tests using the R package 'testthat'

Even if your package is still small and not complex, it makes sense to think about automated tests that are run every time you check and build it:

  • You spot bugs and unwanted side effects introduced by new code
  • You actually have to think about the allowed input and output of a function
  • Your package becomes more stable … potential users get happy.

For a more elaborated explanation see: http://r-pkgs.had.co.nz/tests.html

  How to use 'testthat' with your 'EGU19' package?

(1) Create needed folders

  • EGU19/tests
  • EGU19/tests/testthat
  • EGU19/tests/testdata

  How to use 'testthat' with your 'EGU19' package?

(2) Create a file named EGU19/tests/testthat.R

Fill it with the following lines to make sure that the tests will be run automatically

library(testthat)
library(EGU19)

test_check("EGU19")


  How to use 'testthat' with your 'EGU19' package?

(3) Adjust your package DESCRIPTION file

Add the following line: Suggests: testthat

  How to use 'testthat' with your 'EGU19' package?

(4) Write a test

context("f")

test_that("base_check", {
  ##testthat::skip_on_cran()

  expect_equal(object = f(x = 1, p = 2), expected = 1)
  expect_is(f(x = "a", p = 2), class = "numeric")

})


Save the file under tests/testthat/test_f.R

  How to use 'testthat' with your 'EGU19' package?

(5) Finally, how does it look once you check your package?

  Finally: Monitoring tests coverages

Example R package 'Luminescence'

   The deliberately omitted points

  • Test your functions
  • What if Check stops with an error? See where the error happened:
    • If in the examples, then check the respective function
    • If in the overhead tests before, well, … google for it
  • What if a package user reports an error?
    • Fix it, update package version and notify all relevant persons
    • Thus, use a versioning system

Summary

Wrapping up, apart from "R is great"

This course covered…

  • What packages are and why they are like they are
  • Structure/contents of a package
  • Using Git via RStudio to keep track of the package evolution
  • Creating a package from scratch
  • How to turn a script into a function
  • Adding function(s) and their documentation
  • Code testing

What did we (deliberately) forget?

  • How to write "good" R-code for functions
  • Including low level code and Shiny-apps
  • How to submit a package to CRAN and GitHub
  • Writing Vignettes
  • Debugging strategies

Before you run out

We need your feedback on this course, to know what to improve and tweak for next year

Resources

Finding information and materials