Introduction to {box}

box packageklmr.me/box
GitHub IconMarEichler/rladies_box_intro
PDF file Icon rladies_box_intro/presentation/presentation.pdf

Martha Yvonne Eichlersmith

R-Ladies Twin Cities
March 10, 2022

Goal of this talk

Introduce the {box} package and show how it can be used to write modularized/organized code and manage the name space.

Disclaimer: I have been using this package for about 6 months and I’m still learning new things everyday! Please ask as many questions as you want, but I may not know the answer.

Packages Used in the Making of this Presentation/Examples

{box}

box package logo

Why use {box}?

Box modules are like mini-packages: help re-use or share code without the much larger hurdle of developing a whole R package

Why use {box}: Name Space

Name space: group of items (data frames, functions, vectors, lists, etc.) that each have a unique name.
Loading Tidyverse
  • {dplyr} and {stats} use the same name for certain functions, CONFLICT in the namespace
  • If want to use the {stats} function, have to refer to the package: stats::filter()
R Environment: Global Environment
New R Session Adding to Namespace

Why use {box}: Modular-ize

Quick Example: Different Ways of Coding

Note: this is a simplified version of the example in the EX_LONG folder of the repository, using mpg data from the {ggplot2}

A: Frequency Bar Plot
Character or Discrete Numeric Variables
Goal A: Table Plot
B: Slope Plot
Mean of Continuous Numeric Variable at Two Points
Goal B: Slope Plot


Option 1: Write Out Code

Option 1 - Write Out all Code for each plot

Create plots with different variables ⇒ more code (write or copy/paste)

More situations/dimensions ⇒ additional unstructured code:

Option 2: Multiple Functions

Option 2 - Multiple functions

Create plots with different variables ⇒ can easily use functions

More situations/dimensions ⇒ more functions:

Option 3: One Long Function

Option 3 - one long functions

Create plots with different variables ⇒ can easily use function

More situations/dimensions ⇒ Longer function

Option 4: 🌟 Box Modules 🌟

Option 4 - box modules

  • Only box modules are in the name space
  • Can use any exported functions
  • Refer to other box modules within a specific modules
Create plots with different variables ⇒ use functions from modules
More situations/dimensions ⇒ add/amend box modules
  • Test within a specific box module
  • Break up long functions into multiple functions but only export the final function
  • Much smaller usage of name space
  • Easier to share with internally/externally

Comparison

Item Option 1
Write Out Code
Option 2
Multiple Functions
Option 3
One Long Function
Option 4
Box Modules
Namespace Usage Red Frown
Constantly have to create unique names for objects
Yellow Meh
Only use name space for specific functions and/or dependencies
Green Smile
Only use name space for specific function
Green Smile
Only use name space for box modules
Testing Code Yellow Meh
Testing code as written but shouldn’t repeat code multiple times
Green Smile
Functions are sectioned so can test at each level
Red Frown
Difficult to test individual sections once function get extremely long
Green Smile
All testing can be done within the module
Share/Re-Use Red Frown
Have to piece through which code to keep and then amend to new program
Red Frown
Put functions together and document dependencies
Yellow Meh
One function but may be challenging to amend to a different situation or different machine
Green Smile
Just send the box modules .R files
Additional Dimensions Red Frown
New code either added to existing code or new section, bad practice if will use multiple times
Red Frown
Manageable to difficult depending on how much each of the functions and their dependencies need to change
Red Frown
Difficult given that the function is so large, adding a new dimension would be challenging
Green Smile
Adjust easily within the box module or create a new box module (depending on situation)

Let’s learn how to use {box}

Box: File/Folder Structure

Examples of folder structures:
EX_LONG  
| 
|---myboxes #folder with modules
|   |  
|   |---Abox.R   
|   |---admin.R   
|   |---Bbox.R  
|   
|---my.Rmd #rmd file using box modules
EX_SHORT  
| 
|---box #folder with module
|   |  
|   |---greet.R   
|   
|---my.R #r file using box module

Box: External Packages/Modules

box::use is a universal import declaration. It works for packages just as well as for modules. In fact, ‘box’ completely replaces the base R library and require functions. box::use is more explicit, more flexible, and less error-prone than library. At its simplest, it provides a direct replacement

- klmr.me/box/#loading-code

Box: box::use()

Use Box Module
box::use(myboxes/Abox)  
Use External Packages
box::use(dplyr[...])
  • Imports {dplyr} and attached all exported names
  • Similar to library(dplyr)
  • Use any {dplyr} functions without specifying the package name
  • If just use box::use(dplyr), would not be able to use functions without calling package (i.e. dplyr::filter)
box::use(dplyr[filter, select])  
  • Imports {dplyr} and attaches the names dplyr::filter and dplyr::select
  • Use filter() and select() from {dplyr}
  • Would not be able to use mutate()
  • Could use dplyr::mutate()

Box: Write Your Functions/Code with Roxygen

  • Can use anything within box modules within functions
  • Only need to export the final functions you want to use outside the module
  • Use Roxygen
    • Roxygen is a way to document code, it’s used in the development of R packages
    • #’: before each line with information on item
    • @param: specifies variable inputs (each input has own line)
    • @return: specify output (if function)
    • @export: export item (REQUIRED if using outside of module)
    • @examples: examples of use
    • can include as many or as few as you want
    • best practice to include all but I often don’t, c’est la vie
Best practices are a journey, not a destination
- When I’m not implementing best practices
Roxygen Skeleton
  • Windows/Linux: Ctrl+Shift+Alt+R
  • Mac: Option+Shift+Command+R
  • Need to have cursor within a function
#' Title  
#' 
#' @param [param] 
#' 
#' @return  
#' @export  
#' 
#' @examples

Box: Use Module Functions (EX_SHORT)

Write Code

File: box/greet.R

box::use(
    glue[glue]
  , stringr[str_to_title]
)

#' not exported, used WITHIN only 
greeting <- "Hello" 

#' Greet Someone when Given a Name  
#' @param name A character string 
#' @return Greeting with input name  
#' @export 
#' @examples 
#' say_hello("Martha")
say_hello <- function(name){
  to_use <- str_to_title(name)
  glue("{greeting}, {to_use}")
}
Import Module

File: my.R
Pathway to module file,
do not include .R extension

box::use(
    box/greet 
  )
Use Module!

File: my.R
Use $ to use exported functions
(similar to :: for packages)

greet$say_hello("Martha")
## Hello, Martha

Box: Tips

Use Module after Changes

If you make changes to box module, need to reload module in order to changes to be in effect

box::reload(Abox) #just include name, not full pathway/folder
Restart R Session (Shift+Ctrl+F10) and then re-run all code (including box::use())

Pathways

Use a box module within the same folder
#within Abox.R file
box::use( ./admin)  
EX_LONG  
| 
|---myboxes #folder with modules
|   |  
|   |---Abox.R   
|   |---admin.R  
|   |---Bbox.R  
|   
|---my.Rmd #rmd file using box modules
Use a box module up a directory
#within reports/my.Rmd file
box::use( ../myboxes/admin)  
EX_LONG_REPORT_FOLDER  
| 
|---myboxes #folder with modules
|   |  
|   |---Abox.R   
|   |---admin.R  
|   |---Bbox.R  
|   
|---reports #rmd file using box modules
    |  
    |---my.Rmd