Customising your R experience

James Laird-Smith

Intro

  • R
    • Is already a fantastic environment for interactive programming.
    • Already has a fantastic IDE in RStudio.
  • Most people use only the default workflows of these tools.

In this webinar, I’ll be teaching you about customising your R experience using ‘workflow shortcuts’.

What is a workflow shortcut?

It’s my collective term for a set of things that already exist:

  • Keyboard shortcuts (hotkeys)
  • Interactive convenience functions (or snippets)
  • IDE options
  • Start-up scripts

Some of these things you already know, but some will be new (and life changing).

Motivation: workflow

  • Problem: learning new things is hard. So why should you spend time investing in your workflow experience?
  • Think about ctrl + c and ctrl + v.
    • How frustrating would it be to have to go back to selecting Edit > Copy/Paste from a menu item every single time?
    • Now that we’ve invested time in practicing the hotkeys, we don’t want to go back to the less efficient way.
  • My solution: Let frustration be your guide.

Source: https://www.smbc-comics.com/comic/punishment

RStudio

  • It’s a surprisingly extensible IDE.

  • I’m focusing on it because I know a lot of people use it.

Other magical editors:

  • Emacs! (Using the ESS package)
  • VS Code (R extension).
  • Vim

RStudio (2)

  • Everyday interaction:
    • You can use the rstudoapi package for low-level control like openProject() or applyTheme() or even setCursorPosition()
    • More likely, you will use packages that wrap this functionality into an add-in.

RStudio add-in example 1: datapasta

Source: https://github.com/MilesMcBain/datapasta

RStudio add-in example 2: WrapRmd

Wrap your Markdown to a fixed width.

Source: https://github.com/tjmahr/WrapRmd

RStudio add-in example 3: styler

Style your R code.

Source: https://github.com/r-lib/styler

RStudio add-in example 4: shrtcts

Allows you to to save and automatically set your own keyboard shortcuts.

#' Restart RStudio
#' @shortcut Ctrl+Alt+Shift+R
function() rstudioapi::executeCommand("restartR")

#' Go to definition
#' @shortcut Ctrl+.
function() rstudioapi::executeCommand("goToDefinition")

#' Wrap markdown text
#' @shortcut Ctrl+Alt+Shift+W
WrapRmd::wrap_rmd_addin


Source: https://github.com/gadenbuie/shrtcts

Customising R

  • R has an “.Rprofile” file.
    • It contains the R code that will run every time R starts up.
    • It’s found in R’s home directory. You can open and edit it with usethis::edit_r_profile().
  • I’m going to walk you through some things in my .Rprofile1.
    • Jim Hester’s dotfiles are also great2.

.Rprofile caution

There are two main things you want to bear in mind.

  1. You don’t want to compromise the reproducibility of your scripts,

    • For example, setting options(max.print = 40) is acceptable, because it only affects the output that you see at the console.
    • Including library(tidyverse) is not acceptable, because readers of your script then won’t know that you’ve loaded the package.
  1. You don’t want to unconditionally load packages.

    • This can cause problems for package installs.
    • The best way to do this is to wrap code in functions and only call them when you need them.

My .Rprofile (1): preferences

options(max.print = 40)
options(connectionObserver = NULL)
# ^ connectionObserver at work just gets in the way.
options(tidyverse.quiet = TRUE)
options(styler.cache_root = "styler-perm")

Also includes packages options, which are fine to set.

My .Rprofile (2): logic

Work out whether I am on RStudio or not.


on_rstudio <- function() {
  if (commandArgs()[[1L]] == "RStudio") {
    return(TRUE)
  }
  FALSE
}


I have a whole Twitter thread about how this is the best way to do this and other methods are wrong.

This code then enables you to write other code more easily like if(on_rstudio()) etc.

My .Rprofile (3): helpers

Helper functions at_work() and my_email().

at_work <- function() {
  if(Sys.info()["user"] == "jameslaird-smith") return(FALSE)
  TRUE
}

my_email <- function() {
  if(at_work()) return("James.Laird-Smith@bankofengland.co.uk")
  "jameslairdsmith@gmail.com"
}

My .Rprofile (4): package dev options

options(
  usethis.full_name = "James Laird-Smith",
  usethis.description = list(
    "Authors@R" = utils::person(
      "James", "Laird-Smith",
      email = my_email(),
      role = c("aut", "cre"),
      comment = c(ORCID = "0000-0003-1175-4046")
    ),
    Version = "0.0.0.9000"
  ),
  usethis.overwrite = TRUE
)

This way my email changes depending on whether I’m at work or at home.

My .Rprofile (6): RStudio preferences

setHook("rstudio.sessionInit", function(newSession) {
  rstudioapi::writeRStudioPreference("editor_keybindings", "vim")
  rstudioapi::writeRStudioPreference("save_workspace", "never")
  rstudioapi::writeRStudioPreference("always_save_history", FALSE)
  rstudioapi::writeRStudioPreference("save_files_before_build", TRUE)
}, action = "append")

My .Rprofile (7): Setting keyboard shortcuts

I don’t want to load the shrtcts package every session, so I wrap it in a function instead.

jls_set_shrtcts <- function() {
  shrtcts::add_rstudio_shortcuts(set_keyboard_shortcuts = TRUE)
}

Tip: you can start all your convenience functions with your initials so you get auto-complete.

The customiser package

I’ve created an R Markdown template called customiser1.

  • It’s very new. Not (yet?) on CRAN.
  • Allows you to create an R Markdown document where you can put the content you want to go in your .Rprofile.
  • When you click “Knit” in RStudio, it writes the content to the correct .Rprofile location.
  • Helpful if you want to version control your config and then use it on different systems.
---
title: "JLS .Rprofile"
knit: customiser::customiser
allow_overwrite: TRUE
---

This is the file I use for compiling my .Rprofile.

Conclusion

  • R is already a fantastic interactive programming environment.
  • RStudio is already a fantastic IDE.

  • Both R and RStudio are also highly configurable and so allow you to cusomise your experience of using them.
  • The R community could benefit from more config sharing.
  • I’ve created the customiser package to make this easier.

Thank you!

Questions?