options(htmltools.dir.version = FALSE)
library(xaringanthemer)
style_mono_accent(
  base_color = "#09274B",
  base_font_size = "32px", 
  header_h1_font_size = "2.0rem",
  header_h2_font_size = "1.5rem",
  header_h3_font_size = "1.25rem", 
  header_background_content_padding_top = "2rem", 
  header_font_google = google_font("Lato"),
  text_font_google   = google_font("Montserrat", "300", "300i", "500"),
  code_font_google   = google_font("Source Code Pro", "300", "500"), 
  extra_css = list("p" = list("margin-block-start" = "0.5em", 
                              "margin-block-end" = "0.5em"), 
                   "ul" = list("margin-block-start" = "0.5em", 
                              "margin-block-end" = "0.5em"), 
                   "li" = list("margin-block-start" = "0.5em", 
                              "margin-block-end" = "0.5em"), 
                   "pre" = list("margin-top" = "0.5em", 
                              "margin-bottom" = "0.5em"), 
                   ".small" = list("font-size" = "80%"), 
                   ".tiny" = list("font-size" = "50%")), 
  link_color = "#339944"
)

class: inverse, center, middle

r desc::desc_get('Title', '..')

r rmarkdown::metadata$author

r rmarkdown::metadata$institute

(updated: 2021-01-28)


class: inverse, center, middle

"Any fool can write code that a computer can understand.
Good programmers write code that humans can understand."

from "Refactoring: Improving the Design of Existing Code" by Martin Fowler


Motivations


Learning Outcomes

By the end of the workshop, participants will be able to:


Disclaimer


class: inverse, center, middle

Breaking Code into Functions


What are functions?

  mean()
  # computes arithmetic mean of input
  celsius_to_fahrenheit <- function(x) {
    9/5 * x + 32
  }

Why write your own functions?

-- * BUT, it enables: - repeating the same operation on different inputs (e.g. datasets, variables, parameter values, etc.) - clarifying the larger organizational structure of the code


Duplication

df <- data.frame( a = rnorm(10),
                  b = rnorm(10),
                  c = rnorm(10))

# rescale all the columns of df
df$a <- (df$a - min(df$a)) / 
  (max(df$a) - min(df$a))
df$b <- (df$b - min(df$b)) / 
  (max(df$b) - min(df$a))
df$c <- (df$c - min(df$c)) / 
  (max(df$c) - min(df$c))

Define a function!

rescale01 <- function(x) {
  (x - min(x)) / (max(x) - min(x))
}

# rescale all the columns of df
df$a <- rescale01(df$a)
df$b <- rescale01(df$b)
df$c <- rescale01(df$c)

# or with dplyr
df <- df %>% mutate_at(c("a", "b", "c"), 
                       rescale01)

Notes


Workflow structure

knitr::include_graphics("project-diagram.svg")

.tiny[modified from "Reproducible research best practices @JupyterCon" (version 18) by Rachael Tatman, https://www.kaggle.com/rtatman/reproducible-research-best-practices-jupytercon]


Example Code

data_raw <- readRDS("readings.dat")
data_proc <- preprocess_data(data_raw)

fitted_model <- run_model(data_proc)

plot_model_forecasts(fitted_model,
    "figure-1_abundance-forecasts.pdf")
plot_abundance_residuals(fitted_model,
    "figure-2_abundance-residuals.pdf")
plot_abundance_histogram(data_proc, 
    "figure-3_abundance-residuals.pdf")

Notes


Tips for writing functions


Tip 1: Naming Things

# bad
row_adder()
permutation()

# good
add_row()
permute()

.small[examples from https://style.tidyverse.org/functions.html#naming]

Tip 2: Plan for flexibility

plot_abundance_histogram <- 
  function(data_proc, filename, 
           width = 6, height = 6) { 
    # {{code}} 
  }

Tip 3: Function size


Tip 3 (cont'd)

# bad
if (class(x)[[1]]) == "numeric" || 
    class(x)[[1]] == "integer")

# good
if (is.numeric(x))

.small[examples from https://speakerdeck.com/jennybc/code-smells-and-feels?slide=36]

class: inverse, center, middle

Code Smells


What are "code smells"


Example (code smell)



Solution



Comments


Thanks



ha0ye/RMDconverter documentation built on Feb. 4, 2021, 8:55 p.m.