Developing R Packages

Gareth Burns

Exploristics

July 17, 2023

Developing an R Package 📦

An R package 📦 is a collection of functions that have a shared purpose. Installing base R comes with existing core packages (e.g. stats), and tens of thousands on additional packages on additional code repositories CRAN, GitHub, Bioconductor.

We’re often using other people packages (every time we use library) - so by replacing source calls within our scripts we’re not changing our workflow, we’re just need new skills and techniques to develop packages.

Aim: The aim of the presentation today is to provide the simplest workflow to take a collection of existing functions and turn them into an R package 📦.

Why develop an R package?

  1. Collects shared code/functions in a single source

  2. Modularises code

    1. Easier to re-use individual components

    2. Easier to maintain

  3. Encourages best practice

    1. Documentation

    2. File Structure

    3. Validation

Why develop an R package?

  1. Easier to share and collaborate

    1. Defined processes and structure
    2. Can store on code repositories
  2. Scale-able

    1. KerusCore is an R package run on AWS

    2. DMB is an R package deployed in a Container on AWS

  3. Allows access to other tools/services

    1. Unit testing

    2. Continuous Integration/ Development

    3. Other packages can build off your packages

What does an R Package 📦 consist of?

Description File

This contains meta-data about the package

Package: mypackage
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R: 
    person("First", "Last", , "first.last@example.com", role = c("aut", "cre"),
           comment = c(ORCID = "YOUR-ORCID-ID"))
Description: What the package does (one paragraph)
License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
    license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.2

See https://r-pkgs.org/description.html#description

Namespace File

Defines the dependencies (what packages it imports/uses) and what is exported from the package (i.e. the functions you create which a user can access).

Using the :: operator is a way of accessing what is in the namespace for a package (e.g. dplyr::filter() ).

The namespace gets more complicated with OOP and C++ but it outside scope of current presentation.

See https://r-pkgs.org/namespace.html#namespace

Example Function

#' @title Get Current Weather Data
#' @description This function retrieves the current weather data for a specified
#'   location using the WeatherAPI.
#' @author Gareth Burns
#' @param location A character string representing the location for which you want
#' to retrieve the weather data. This can be a city name, coordinates (latitude and longitude),
#' or a postal code.
#' @param days Optional. Number of Days to supply forecast. If supplied returned
#'  forecasted weather for those days ahead (an positive integer up to 3)
#' @return A list containing the current weather data for the specified location.
#' If the request fails, it returns an error message.
#'
#' @examples
#' \dontrun{
#' location <- "London"
#' current_weather <- GetCurrentWeather(location)
#' print(current_weather)
#' }


GetCurrentWeather <- function(location, days = NULL, ...) {
  # Base URL for WeatherAPI current weather
 if(is.null(days)) {
   base_url <- "http://api.weatherapi.com/v1/current.json"
 } else {
   base_url <- "http://api.weatherapi.com/v1/forecast.json"
 }


  argg <- compact(list(
    "key" = Sys.getenv("WEATHER_API"),
    "q" = location,
    "days" = days
  ))
  # Create the request
  request <-
    do.call("req_url_query", args = c(list(.req = request(base_url)), argg))

  # Perform the request and check for success
  response <- req_perform(request)

  # Check if the request was successful
  if (resp_status(response) == 200) {
    # Parse the JSON response
    weather_data <- response %>%
      resp_body_json(simplifyVector = TRUE)

    # Return the relevant weather data
    return(weather_data)
  } else {
    # Return an error message if the request failed
    return(paste("Error:", resp_status(response)))
  }
}

Functions

Workflow (1)

  1. Create GitHub repository (optional)

  2. Create New Project in RStudio

    1. Version Controlled Git
    2. Git
    3. Paste in URL from GitHub
  3. Run functions from usethis package

    1. Usethis::createpackage(getwd())
    2. Usethis::usedescription()
  4. Modify Description file as you see fit (https://r-pkgs.org/description.html)))

  5. Check Tools – Project Options – Build Tools

    1. Project build tools should be “Package”
    2. Tick “Generate documentation with Roxygen”
  6. Create a function in R folder (convention is to name R file the function name)

  7. Add Royxen comments to function (see https://r-pkgs.org/man.html))

  8. Create Document file (Crtl + Shift + D)

  9. Build Package (Crtl + Alt + B)

  10. Commit code to GitHub (optional)

How to share package

GitHub

devtools::install_github("GABurns/ShortsWeatheR")

If not public ensure permission has been granted

Share internally

  1. Build the package into a source / tar file. This can be done using RStudio

    1. Build > More > Build Source Package
  2. Put the tar file in a shared network location or email to collaborator. Users can either download the tar file and then install the package, or install the package directly from the compressed folder on the shared drive

    install.packages("path/to/tar/file", source = TRUE, repos = NULL)

Use library(packageName)

Showcase: ExploristicsTheme

ExploristicsTheme GitHub repo

ExploristicsTheme Website

Resources