class: center, middle, inverse, title-slide # Good practice for writing R code and R packages ##
https://jarbel.github.io/Rgoodpractice/rpresentation.html
Slides very closely following
http://style.tidyverse.org/
###
Julyan Arbel
&
Alexis Arnaud
### February 8, 2018 --- class: center, middle, inverse # 1. R coding style --- ## Files --- ### Names ```r # Good fit_models.R utility_functions.R # Bad fit models.R foo.r stuff.r ``` ### Structure ```r # Load data --------------------------- # Plot data --------------------------- ``` --- ## Syntax --- ### Object names Strive for names that are concise and meaningful. ```r # Good day_one day_1 # Bad first_day_of_the_month DayOne dayone djm1 ``` Avoid using already existing names. ```r # Bad T <- FALSE c <- 10 mean <- function(x) sum(x) ``` --- ### Spacing Any style guide is fundamentally opinionated... ```r # Good Hadley average <- mean((feet / 12) + inches, na.rm = TRUE) sqrt(x^2 + y^2) x <- 1:10 base::get # Good Alexis average <- mean( ( feet / 12 ) + inches , na.rm = TRUE ) sqrt( x^2 + y^2 ) x <- 1:10 base::get # Bad average<-mean(feet/12 + inches,na.rm=TRUE) sqrt(x ^ 2 + y ^ 2) x <- 1 : 10 base :: get ``` --- ### Indenting ```r # Good if (y < 0 && debug) { message("y is negative") } # Bad if (y < 0 && debug) message("Y is negative") ``` --- ### Long lines Strive to limit your code to 80 characters per line. ```r # Good do_something_very_complicated( something = "that", requires = many, arguments = "some of which may be long" ) # Bad do_something_very_complicated("that", requires, many, arguments, "some of which may be long" ) ``` --- ### Assignment ```r # Good x <- 5 # Bad x = 5 ``` --- ## Automatic styling You can use `Ctrl + Shift + A` or `Command + Shift + A` <img src="fig/code-menu.png" width="20%" style="display: block; margin: auto;" /> Or `lintr` and `styler` packages ```r install.packages(c("lintr", "styler")) library("lintr") library("styler") ``` --- ### lintr package lintr can be used o a source file, eg `bad_style.R` being the following source: ```r # Spacing average<-mean(feet/12 + inches,na.rm=TRUE) sqrt(x ^ 2 + y ^ 2) x <- 1 : 10 base :: get # Indenting if (y < 0 && debug) message("Y is negative") # Assignment x = 5 ``` Then run ```r lint("bad_style.R") ``` --- ### lintr package <img src="https://camo.githubusercontent.com/20dbcc29a25f1e86dcde02d2056508c322f6ae05/687474703a2f2f692e696d6775722e636f6d2f50494b6e70626e2e706e67" width="90%" style="display: block; margin: auto;" /> --- ### styler package <img src="https://raw.githubusercontent.com/lorenzwalthert/some_raw_data/master/styler_0.1.gif" width="100%" style="display: block; margin: auto;" /> --- ### styler package You can use the `style_text()` function as follows ```r ugly_code <- "a<-function( x){1+1} " style_text(ugly_code) ``` ```r # Bad a<-function( x){1+1} # Good a <- function(x) { 1 + 1 } ``` --- ### styler package As well as the following variants of `style_text()`: * `style_file()` styles .R and/or .Rmd files. * `style_dir()` styles all .R files in a directory. * `style_pkg()` styles the source files of an R package. * RStudio Addins for styling the active file, styling the current package and styling the highlighted code region. --- ## Other tidying packages **Get automatic advice about your package** Install and run `goodpractice` package for *Advice (that) includes functions and syntax to avoid, package structure, code complexity, code formatting, etc.* **Remove typos!** Use the `devtools::spell_check()` function. --- ## References To complete: * http://style.tidyverse.org/ * https://cran.r-project.org/web/packages/rockchalk/vignettes/Rstyle.pdf * https://journal.r-project.org/archive/2012-2/RJournal_2012-2_Baaaath.pdf * https://cran.r-project.org/doc/manuals/R-ints.html * https://google.github.io/styleguide/Rguide.xml * https://www.r-project.org/conferences/useR-2004/Keynotes/Maechler.pdf * https://stat.ethz.ch/Teaching/maechler/R/useR_2014/Maechler-2014-pr.pdf * http://andrewgelman.com/2007/09/18/style_guide_for/ * http://blog.jom.link/ten_rules_reproductible_research.html --- class: center, middle, inverse # 2. Create R packages --- ## System settings - Customization of R profile Create a R profile file `.Rprofile` with the path to your local library if you use local libraries into your code, e.g : ```r .libPaths(new="~/R_libs") ``` See http://gettinggeneticsdone.blogspot.com/2013/06/customize-rprofile.html for more informations. --- ## Package skeleton Create a directory with the name of your package, e.g. `MyPackage`, with inside: * the sub-directory `R` for the R source code * the file `DESCRIPTION` for meta-informations on your package. ```r dir.create( path = "MyPackage" ) dir.create( path = paste( "MyPackage" , "R" , sep = .Platform$file.sep ) ) file.create( path = paste( "MyPackage" , "DESCRIPTION" , sep = .Platform$file.sep ) ) ``` --- ### DESCRIPTION file ```r cat( c( "Package: MyPackage" , "Version: 0.1" , "Date: 2018-02-08" , "Type: Package" , "Title: My nice package" , "Author: A. Arnaud" , "Maintainer: Alexis Arnaud <alexis.arnaud@inria.fr>" , "Description: Basic package to display 2 ggplot2 plots." , "License: GPLv3" , "URL: https://github.com/jarbel/Rgoodpractice.git" ) , file = paste( "MyPackage" , "DESCRIPTION" , sep = .Platform$file.sep ) , sep = "\n" , append = TRUE ) ``` --- ### R code files multiplot : http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/ ```r cat( c( "plot_boxplot <- function(data) { if ( !is.data.frame(x = data) ) data <- as.data.frame(x = data) data_melt <- melt(data = data) plot_pairs <- ggpairs(data = data) plot_boxplot <- ggplot( data = data_melt , aes( x = variable , y = value , fill=variable) ) + geom_boxplot( ) multiplot( plot_pairs , plot_boxplot , cols = 2) }" ) , file = "plot_functions.R" , sep = "\n" , append = TRUE ) ``` --- ## R code documentation Use the Roxygen templates to start the documentation: <img src="RStudio_-_Insert_Roxygen_Skeleton.png" width="75%" style="display: block; margin: auto;" /> --- ## R code documentation And fill the Roxygen fields in order to best describe your function: * Title of the function * @description Some description * @param <parameter name> name of each parameter and a short description (type, default value ...) * @return value of the function output * @author author of the function * @seealso link to other functions or packages, e.g. \code{ \link[GGally]{ggpairs} } * @keywords some keywords for the code indexation * @examples one or several examples on how to use the function * @importFrom <package name> <function name> to import some package or functions during the installation and the loading of the function * @export --- ## Documentation generation with roxygen2 Now, you just need to move your R files to the R directory of your package, and then run Roxygen before building and installing your package. ```r library(package = "roxygen2") for ( file in c( "plot_functions.R", "multiplot.R" ) ) { file.copy( from = file , to = paste( "MyPackage" , "R" , file , sep = .Platform$file.sep ) ) } roxygenize( package.dir = "MyPackage" , clean = TRUE ) library(package = "tools") Rcmd(args = "build MyPackage") ## or with a shell : R CMD build MyPackage install.packages(pkgs = "MyPackage_0.1.tar.gz") library(package = "MyPackage") ``` --- ## Test ```r n_col <- 3 n_row <- 1e3 m_test <- t( x = matrix( data = rnorm( n = n_col * n_row , mean = 0 , sd = 1 ) , nrow = n_col , ncol = n_row , dimnames = list( "Variables" = paste("V ", seq_len(length.out = n_col), sep = "") , "Observations" = NULL ) ) * c(0.1, 1, 3) + c(-1, 1, 0) ) plot_boxplot(data = m_test) ``` --- ## Test <img src="R_plot_-_Example.png" width="75%" style="display: block; margin: auto;" /> --- ## References To complete: * https://cran.r-project.org/doc/contrib/Leisch-CreatingPackages.pdf * http://kbroman.org/pkg_primer/ * https://github.com/klutometis/roxygen * http://r-pkgs.had.co.nz/ * https://support.rstudio.com/hc/en-us/articles/200486488-Developing-Packages-with-RStudio * https://www.r-bloggers.com/how-to-write-and-debug-an-r-function/ * https://nicercode.github.io/guides/functions/ * https://swcarpentry.github.io/r-novice-inflammation/06-best-practices-R/ --- class: center, middle, inverse # Thanks! <br> Presentation available at https://jarbel.github.io/Rgoodpractice/rpresentation.html <br> http://www.julyanarbel.com/ & http://mistis.inrialpes.fr/people/arnaud/ Twitter: [@julyanarbel](https://twitter.com/julyanarbel) GitHub: [@jarbel](https://github.com/jarbel) & [@A-Alexis](https://github.com/A-Alexis) .footnote[Slides created via the R package [**xaringan**](https://github.com/yihui/xaringan).]