background-image: url(https://i.imgur.com/CVIZGyY.jpg) background-position: top background-size: 100% class: inverse, shadow # My Organization's First R package ## Write R Code ## `rstudio::conf(2020L)` --- class: middle, center <img src="img/where_are_we_02.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- class: middle, center, inverse # **Writing Functions: Review** --- ## Writing functions <img src="img/writing_functions.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/writing_functions_args.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/writing_functions_body_name.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/writing_functions_inputs_output.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- ## Your Turn 1 #### Re-write this ggplot2 theme as a function. Call it `theme_avalanche_h()`. #### Run this code to test that your function works --- ## Your Turn 1 .small[ ```r *theme_avalanche_h <- function() { * theme_minimal(base_size = 14) + * theme(panel.grid.minor = element_blank(), panel.grid.major.y = element_blank()) *} residents_per_sector <- data.frame( sector = as.factor(1:8), residents = c(1000, 2034, 4594, 2304, 8093, 1200, 300, 2398) ) ggplot(residents_per_sector, aes(forcats::fct_reorder(sector, residents), residents)) + geom_col() + coord_flip() + xlab("sector") + theme_avalanche_h() ``` ] --- <img src="r_packages_write_code_files/figure-html/yourturn1_sol-1.png" style="display: block; margin: auto;" /> --- class: center, middle, inverse # **We're going to start writing functions to our package, not the global environment. This will require a change in workflow!** --- # `use_r("file_name")` -- ## Write a new file to `R/` --- <img src="img/use_r.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- class: center, middle <img src="img/workflow_alert.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- # devtools: loading vs. building ## **`load_all()`**: fast, all functions available ## **`build()`**: builds and installs the package --- # ~~devtools: loading vs. building~~ ## ~~`load_all()`: fast, all functions available~~ ## ~~`build()`: builds and installs the package~~ <br> # *Keyboard shortcuts* ## `load_all()`: **`CMD/CTRL + Shift + L`** ## `build()`: **`CMD/CTRL + Shift + B`** --- class: center, middle <img src="img/build_tab.png" width="60%" height="60%" style="display: block; margin: auto;" /> --- class: center, middle ## Our new workflow <img src="img/flow_write_load.png" width="60%" height="60%" style="display: block; margin: auto;" /> --- ## Your Turn 2 #### Create a new file with `use_r()` called "db_con" #### Put this function in the file and save it #### Use `load_all()` to load the package function. #### Run this code to make sure it works: --- ## Your Turn 2 ```r use_r("db_con") ``` -- ### in `R/db_con.R`: ```r db_con <- function(dbname = "residents_per_sector") { dbname <- match.arg(dbname) # We will set up real database connections later. For now, # we'll just return some hard-coded data instead. data.frame( sector = as.factor(1:8), residents = c(1000, 2034, 4594, 2304, 8093, 1200, 300, 2398) ) } ``` --- ## Your Turn 2 <img src="r_packages_write_code_files/figure-html/unnamed-chunk-12-1.png" style="display: block; margin: auto;" /> --- class: inverse # Using other packages 1. Import a package with `use_package()` 2. Use the package with `pkg::fun()` 3. **DO NOT** use `library()`. Avoid it completely while developing. --- class: center <img src="img/workflow_alert_pkgs.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/use_package.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/description_imports.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/description_minversion.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/description_dev_pkg.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/description_suggests.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- # Testing for suggested packages ```r if (requireNamespace("shiny", quietly = TRUE)) { # ... shiny code } ``` --- <img src="img/description_depends.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- <img src="img/description_tidy.png" width="100%" height="100%" style="display: block; margin: auto;" /> --- ## Your Turn 3 #### Fix the code in `R/themes.R` to use `ggplot2::` instead of `library(ggplot2)` #### Run `use_package("ggplot")` to add ggplot2 to `Imports` #### Re-load the package (`Cmd/Ctrl+Shift+L`) and run this code to make sure it works --- ## Your Turn 3 ```r use_package("ggplot2") ``` -- ### in `R/themes.R`: ```r theme_avalanche <- function() { * ggplot2::theme_minimal(base_size = 14) + * ggplot2::theme(panel.grid.minor = ggplot2::element_blank()) } ``` --- ## Your Turn 3 <img src="r_packages_write_code_files/figure-html/unnamed-chunk-24-1.png" style="display: block; margin: auto;" /> --- # Packages so good they get their own functions --- # Packages so good they get their own functions ## `use_tibble()` ## `use_data_table()` ## `use_pipe()` ## `use_rcpp*()` --- ## Your Turn 4 #### We need roxygen2 for this exercise. We'll learn more about it in the next module. For now, just run `use_roxygen_md()` #### Run `use_tibble()` and `use_data_table()` #### In `R/get_data.R`, edit the function to be able to return a data table: Add the argument `data_table = FALSE`. If `data_table` is `TRUE`, convert the data frame with `data.table::as.data.table()` #### Run this code to make sure it works --- ## Your Turn 4 ```r use_roxygen_md() use_tibble() use_data_table() ``` ```r *get_resident_data <- function(data_table = FALSE) { residents_per_sector <- db_con("residents_per_sector") * if (data_table) * return(data.table::as.data.table(residents_per_sector)) tibble::as_tibble(residents_per_sector) } ``` --- ## Your Turn 4 ``` ## sector residents ## 1: 1 1000 ## 2: 2 2034 ## 3: 3 4594 ## 4: 4 2304 ## 5: 5 8093 ## 6: 6 1200 ## 7: 7 300 ## 8: 8 2398 ``` ```r data.table::is.data.table(res_data) ``` ``` ## [1] TRUE ``` --- ## Your Turn 4: Stretch goal #### Run `use_pipe()` to add the magrittr pipe to your package. What changed? --- ## Organizing `.R` files --- ## Organizing `.R` files ## *Less than 1:1, more than all:1* --- ## Organizing `.R` files ## ~~Less than 1:1, more than all:1~~ ## *`utils.R`* --- ## Organizing `.R` files ## ~~Less than 1:1, more than all:1~~ ## ~~`utils.R`~~ ## *`zzz.R`*, *`.onLoad`* See [R Packages, ed. 2](https://r-pkgs.org/r.html#when-you-do-need-side-effects) for more.