---
title: "Functions and scripts"
author: "Sebastian DiLorenzo, Markus Mayrhofer"
image: "assets/featured.webp"
format: revealjs
---

## {visibility="hidden"}

```{r}
#| echo: false
library(optparse)
library(emo)
```

## Structure Your Code

Decompose the problem `r emo::ji('puzzle')` `r emo::ji('puzzle')`!

[
  ![](assets/Philip-ii-of-macedon.webp){height="300px"}
  ![](assets/Julius_Ceasar.webp){height="300px"}
  ![](assets/Napoleon_Bonaparte.webp){height="300px"}  
  [source: Wikimedia Commons]{.smaller}  
]{.center}

. . .

- *divide et impera* / top-down approach &mdash; split your BIG problem into a number of small sub-problems recursively and, **at some level**, encapsulate your code in functional blocks (functions)

## R Functions

<br>

- What is exported from R packages
- Perform a set task, preferably that task is not "this whole analysis"
- Any code that will be repeated
- "One screen rule"
- Add less objects to workspace

## R Functions

:::: {.columns}
::: {.column width="50%"}

[**Without a function**]{style="background-color: #f2d7d5; padding: 5px;"}

```{r}
#| code-line-numbers: "1|2"
a <- 5
a + a
```

```{r}
b <- 3
b + b
```

- User is performing the operation each time

::: {.notes}
An R function is something you have probably used many times already.. Functions perform a set task within R. Lets looks at a quick example.
:::
:::

::: {.column width="50%"}

[**With a function**]{style="background-color: #d0ece7; padding: 5px;"}

```{r}
#| code-line-numbers: "1-3|5-6|9"
doubleUp <- function(x) {
  x + x
}

a <- 5
doubleUp(a)
b <- 3
doubleUp(b)
z <- doubleUp(3)
```

- Function is performing the operation each time

:::
::::

## R Functions

The pieces that make a function

```{r}
function_name <- function(param1, param2 = 20, ...) {
  param1 * 2 # Operational space
  param1 + param2 # What is returned. Alt, use return(param1+param2)
}
```

- `function_name` : Name of the function
- `function()` : Parameters. User input
  - `param1` : No default value. Required.
  - `param2 = 20` : Default value
  - `...`  : ellipses pass other arguments into function
- `function(){}` : The function body
- `return` : the last line or invoked with `return()` function.

::: {.notes}
A parameter is a variable in the declaration of the function.
An argument is the actual value of the variable that gets passed to the function.
:::

. . .

::: {.callout-tip}
How to add a function to your workspace

- copy paste
- `source()` / `library()`
:::

## R Functions

- use **data** as the **very first** parameter for `%>%` pipes sake:
  - `myfun <- function(x, param)` `r emo::ji('yes')`
  - `myfun <- function(param, x)` `r emo::ji('no')`

. . .

- set parameters to defaults &mdash; better too many parameters than too few:
  - `myfun <- function(x, seed = 42)` `r emo::ji('yes')`
  - `myfun <- function(x, ...)` `r emo::ji('no')`

. . .

<br>

- remember that global defaults can be changed with `options`

::: {.notes}
Global options can influence how functions behave, for example the default number of digits printed in the console.
:::

## Wrapper function

If you are re-using functions written by someone else &mdash; write a wrapper function around them and use the power of the `...`

:::{.columns}
:::{.column width="50%"}

```{r wrapper-fn1}
my_awesome_plot <- function(x, ...) {
  plot(x,
       col = "red",
       pch = 19,
       cex.axis = .7,
       ...)
}
```

:::
:::{.column width="50%"}

```{r wrapper-fn-plot}
#| fig-height: 3
#| fig-width: 4
#| error: true

my_awesome_plot(1:5, col = "blue")
my_awesome_plot(1:5, las = 1)
```

:::
:::

## R scripts as standalone tools

::::{.columns}
:::{.column width="50%"}

<br>
<br>

- Data analysis with R is usually performed interactively using e.g. RStudio, VSCode, Positron
- Tasks can be executed from the terminal using R scripts
- R scripts can form powerful standalone tools
- Useful for putting R into a pipeline of tools <br> `tool1 | Rscript | tool2 > output`

:::
:::{.column width="50%"}

![](assets/pipes.webp)

:::
::::

::: {.notes}
Usually when you are **analyzing data** you will use the **interactive view** and try different things going forward. But say that you have figured out something that you want to **do** for **multiple numbers** of datasets?

An Rscript should do **one** thing and do it well. Because of the **power** in that an **R script** can contain **multiple functions**, or "programs", this one thing can be quite **simple**, or quite **advanced**.

In this case it might be **efficient** to use an **Rscript**. Often Rscripts are used in pipes, which is what I am referencing in this image. Note code is unix commandline.

So USUALLY an rscript is something that is executable, can take some inputs and arguments, and returns something.

Now lets look at those pieces starting with how an rscript can be executed.
:::

## Executing an R script

- Interactively: `source("myscript.R")` in R console 

::: {.notes}
One way to execute an Rscript is to use "source myscript.R" from an interactive session which **runs** whatever code is in the R script. So if it has **functions** or wether it **reads** a separate file and creates some new **object**, these will be in your **R environment** after sourcing the script.
:::

. . .

- Command-line: `Rscript myscript.R`

::: {.notes}
You can also run the Rscript from the command line, or terminal. Then we use the command **Rscript**. It used to be not long ago that people used **R CMD batch**, but nowadays people usually use Rscript.
Like the source, this will **execute** whichever code is in **myscript.R** but there is **no environment** for the **objects or functions** to pop into so the **code** in this Rscript is probably **different** than one that is intended for **source**.
:::

. . .

- As executable file: `path/myscript.R` if:
  - Script is executable: `chmod +x myscript.R`
  - First line in script is a hashbang e.g. `#!/usr/bin/env Rscript`
  - Script's path is included in call or `$PATH`

::: {.notes}
You can also execute the Rscript **itself**, from terminal.
To execute an R script it must *meet three requirements*.
It must be **executable**.
It must start with this **special line**, specifying how it is executed if run on its own.
If you want to run it without giving path, its folder must be in you $PATH variable.
:::

## Providing arguments to an R script

- Passing arguments to the script allows for flexibility in settings and input data

::: {.notes}

**Often** when we use an R script, like I mentioned in the **beginning**, we want to **pass multiple files/samples** through it for efficiency reasons. It **doesnt** just have to be **files**, like **functions** it can also be **argument settings.**

:::

. . .

`./myscript.R inputfile.vcf outputfile.vcf`

::: {.notes}

Here for example we are using the Rscript as an **executable** file, giving it an **inputfile** and specifying what we want the **outputfile** to be named. Notice that the only way the R script knows what is what is positionally.
:::

. . .

- Packages are available that support long and short flags

`./myscript.R -i inputfile.vcf -o outputfile.vcf`

::: {.notes}

**Short flags** are when you give a single dash and usually a shortened version of the keyword, here *i for input* and *o for output* for example.
:::

. . .

`./myscript.R --input inputfile.vcf --output outputfile.vcf`

::: {.notes}

And here **long flags** with *two dashes*
:::

. . .

`./myscript.R --output inputfile.vcf --input outputfile.vcf`

::: {.notes}

A part of the **flexibility** of this is that you can give the flags in **any order**.
:::

. . .

`./myscript.R --output inputfile.vcf -i inputfile.vcf`

::: {.notes}

And you can also *mix* the *long/short flag order and styles*. It is the coding in the script that determines how it handles this input.
:::

## Parsing arguments - Positional

Example: `./myscript.R inputfile.vcf outputfile.vcf`


- `commandArgs()`

Use **commandArgs()** to capture whatever was **passed** into R as it was **executed**. To be **clear**; this is a command that is **within the Rscript file.**

. . .

- `trailingOnly = TRUE`

Add `trailingOnly = TRUE` to suppress the first few items and get the arguments **you** passed to the script.

::: {.notes}
A **standard arg**, but **not default**, that you can use when invoking `commandArgs()` is `trailingOnly = TRUE`, which basically tells it to start counting the input from **after** the **Rscript arguments**. As you can see here when we invoke it without this parameter it returns the script itself, in this case R studio. But with it the invocation is clear, there were no trailing command line arguments.
:::

. . .

```{r}
commandArgs()
```

```{r}
commandArgs(trailingOnly = TRUE)
```

## Parsing arguments - Flags

Example: `./myscript.R --input inputfile.vcf --output outputfile.vcf`

::: {.notes}
So how do we do it with **flags**?
:::

. . .

- Several packages are available: `getopt`, `optparse`, `argparser`, ...

. . .

Define set of possible arguments at start of script:

```{r}
library(optparse)
my_options <- list(
  make_option(c("-i", "--inputfile"), default = "variants.vcf"),
  make_option(c("-o", "--outputfile"), default = "variants_filtered.vcf")
)
```

::: {.notes}
If we use **optparse** as an example you **create** your options using the **make_option** command, and can set default values. We see also that you can give both long and short form here.
:::

. . .

Parse arguments using your definition:

```{r}
parse_args(OptionParser(option_list = my_options))
```

::: {.notes}
And then you use the **my_options** object we defined together with **parse_args and OptionParser** to **check our input** for those **flags** We also see an option, **help**, that we did not make, this is a **standard flag** that optparse always looks for and can generate what arguments it is looking for.
:::

## Text streams

- Text streams allow for piping of data through a set of applications without writing intermediate files.

::: {.notes}
What I am sure most of you will think of when you read this is the bash pipe sign.
:::

. . .

`samtools mpileup -uf ref.fa aln.bam | bcftools call -mv | myPythonscript.py | myRscript.R > variants.vcf`

::: {.notes}
So how does R handle taking input piped to it. And the answer is that we have to write some special code if this is the use case.
:::

. . .

### Reading

- To define and open a connection, read one line, and close it:

```{r}
#| eval: false
input_con  <- file("stdin")
open(input_con)
oneline=readLines(input_con, n = 1)
close(input_con)
```

- Tidyverse can read a `tibble` from text stream: `read_csv(file("stdin"))`

::: {.notes}
What we do is **open** a connection from **standard input** and then read this **text stream** for **n** number of lines at a time. It is also good to close this connection afterwards.

Alternatively you can read a text stream into a **tibble** from tidyverse by using **read_csv**, note that it isnt **read.csv** the generic R command, which can take our **input connection** and create the tibble in R.
:::

## Text streams

#### Writing

- Any `stdout` produced by the code (`print()`, `cat()`, etc) can be piped to a new process: `./myRscript.R | myNewScript`

- or written to a file: `./myRscript.R > output.csv`

- To write a `tibble` as a text stream: `cat(format_csv(my_tibble))`

::: {.notes}
What about **piping from** your R script to something else? Continuing the stream? So just writing these commands. print, cat etc, can be piped to a new process.

If you already have a tibble, you can stream it out of R using this command.
:::

## Summary

<!-- ![](http://www.azquotes.com/picture-quotes/quote-this-is-the-unix-philosophy-write-programs-that-do-one-thing-and-do-it-well-write-programs-douglas-mcilroy-81-95-07.jpg) -->

- Functions are great for organizing code and repeating tasks
- R scripts are great for performing tasks from command-line
- R scripts can be built in different ways to take arguments or text streams

::: {.notes}

So to summarize, R scripts are powerful tools to solve a specific problem that you define, and often fit well together with other tools. And now you have learned to execute them in different ways, with inputs and outputs and with other programs. All that is left is to actually write the content.
:::

## {background-image="/assets/images/network.svg"}

::: {.v-center .center}
::: {}

[Thank you!]{.largest}

[Questions?]{.larger}

[{{< meta current_year >}} • [SciLifeLab](https://www.scilifelab.se/) • [NBIS](https://nbis.se/) • [RaukR](https://nbisweden.github.io/raukr-2026)]{.smaller}

:::
:::
