EGU 2019 | Thu, 11 Apr, 08:30–10:15, Room -2.62
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.
Structuring code and following good practice rules
You are looking for an introduction to R … sorry, bad luck!*
(*) Don't repeat yourself.
By the way, Hadley Wickham's Advanced R is a warm recommendation.
Working with packages simply saves time and brain cells
What do you think? What belongs to an R package?
A working examples (you don't want to rely on the documentation, only)
A set of further stuff that will be covered later
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.
importFrom() in the file NAMESPACE, instead.citation("PACKAGENAME") to see how a package should be citedAuthors@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"))
License: file LICENSE) or a keyword of standard licenses (read more):
They are more than just counters, they define dependency satisfactions
Make use of a NEWS file (e.g., NEWS.md) to announce history & changes.
Omitting it means, nobody will be able to use your package
Additional documentation is covered by vignettes (not covered here)
Documentation in *.Rd-files is formalised, in pseudo LaTeX scheme (short version, long version)
roxygen2inlinedocs (no longer updated)*.rda files (generated with save())datasrc will be compiled during installationinst will be copied to main directoryPffffft, a lot of dense and boring input, right?
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? :)
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.
Further reading: https://git-scm.com/
Confirm and let RStudio restart itself
Click on the tab in the upper right window
That was it! All changes made will now be tracked.
git checkout <SHA> <filename>)Make sure you tick the option "create as git repository".
Go to the Git tab
Close the Git console window
Done! Your first package skeleton is made and Git is set up with it.
The task (time 5 minutes): Modify the DESCRIPTION file that it contains your own information. Modify all the auto generated information.
Stage it (check the box) and click on the Commit button
If ok, write a useful commit message and commit the changes.
A series of (hopefully positively evaluated) checks are run.
Your first R package should be in your project directory.
PACKAGE_VERSION_tar.gz-file in your R directoryThe task (time 5 minutes): Build your first package.
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)
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)
## 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)
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))
}
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))
}
f(a = 10, b = 100, c = 5, plot = FALSE)
## $A ## [1] 1000 ## ## $V ## [1] 5000
FUNCTION_NAME(ARUMENT_1, ARGUMENT_2) {FUNCTION BODY}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}
Another brief function example
f <- function(x, p = 2) {
## calculate the power of x
y <- x^p
## return value
return(y)
}
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)
}
And become something like:
'roxygen2' is a package that parses function source files for tags (e.g., #' @param) and converts them to the structure of a *.Rd-file.
Third and further set of lines becomes details (optional)
Further down follow tagged items
@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\emph{}, \strong{}, \code{})\code{\link{}}, \href{}{})\enumerate{}, \itemize{})\eqn{}, \deqn{})\tabular{}{\tab \cr})Luminescence::analyse_baSAR.RPffffft, no more details please!
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.
#' 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)
}
DO NOT abandon your package!
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!
'Platform tests': Can your package be checked and built without errors on other platforms, such as Windows, Linux, and MacOS
Unit tests: testing your code using dedicated test scenarios (we will cover that later)
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:
If you fail to address errors within a certain period of time, your package may be removed from CRAN.
… 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.
Fig: Kreutzer et al., 2017
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:
For a more elaborated explanation see: http://r-pkgs.had.co.nz/tests.html
EGU19/testsEGU19/tests/testthatEGU19/tests/testdataEGU19/tests/testthat.RFill it with the following lines to make sure that the tests will be run automatically
library(testthat)
library(EGU19)
test_check("EGU19")
DESCRIPTION fileAdd the following line: Suggests: testthat
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
Check stops with an error? See where the error happened:
The course materials are available at
www.micha-dietze.de/pages/r_courses.html