Chapter 22 A Note On Piping {-} {piping-note}

As mentioned, throughout this guide the examples will be using the piping operator, which you will see as either **|>** (native R) or **%>%** (dplyr package). If you are unfamiliar with it, a little more detail may be helpful.

What is the difference between the native R pipe and the dplyr pipe? Not much.. For the purposes of using ArabBarometR, they are essentially identical. This guide will use them interchangeably.

TL;DR: The piping operator does puts something (whatever is on the left) into a function (on the right) as the first input.

Piping puts the object on the left into the function on the right.

First, at the most basic level, the piping operator points to where the input should go. Here’s a small example, checking if the number 2 is a character.

# Using base R traditionally
is.character(2) ## We are asking R is 2 is a character
## [1] FALSE
is.character("2") ## We are asking R is "2" is a character
## [1] TRUE
# Using the piping operator |>
2 |> is.character() ## The piping operator is taking our input, 2, and pointing out the function it belongs in, is.character()
## [1] FALSE
"2" |> is.character() ## The piping operator is taking our input, "2", and pointing out the function it belongs in, is.character()
## [1] TRUE
# Using the piping operator %>%
2 %>% is.character() ## The piping operator is taking our input, 2, and pointing out the function it belongs in, is.character()
## [1] FALSE
"2" %>% is.character() ## The piping operator is taking our input, "2", and pointing out the function it belongs in, is.character()
## [1] TRUE

The code using base R and the code using the piping operator are equivalent. The piping operator is telling R that 2 or “2” go inside the function it is pointing to.

“OK,” you think. “The first one is way easier to understand. Why would I ever use the second one?”

Often that’s the correct thought process. Computers are tricky enough on their own without us complicating the way we type things in. It’s the next element of a piping operator that makes it convenient more often than not.

Piping operators can chain code together.

Instead of saving object after object, you can use a piping operator to get straight to the point.

Say you want to change that 2 into a character and make sure that it changed. In base R, this is done in two steps. First, use the as.character() function with 2 as the input and save the output as something. Second, use the output from the first step as the input for the function is.character().

# Base R:

## Step 1:
chr <- as.character(2)
## Step 2:
is.character(chr)
## [1] TRUE

Using the piping function, you can combine these two steps.

# Using piping operator:

## Chain Ex. 1a
2 |> as.character() %>% is.character()
## [1] TRUE
## Chain Ex. 1b
2 %>% as.character() %>% is.character()
## [1] TRUE

Here, the piping operator tells R to put 2 into the as.character() function and then put the output of that into the is.character() function.

Writing out all the operations in a single line can be visually confusing. Luckily, R can (usually) tell when you are or are not finished with an operation. It is convention to start a new line after using the piping operator. Visually, this makes the code much more clear.

# Following stylistic convention:

## Chain Ex. 2a
2 |>
  as.character() |>
  is.character()
## [1] TRUE
## Chain Ex. 2b
2 %>%
  as.character() %>%
  is.character()
## [1] TRUE

So far the functions we have piped input into are empty. This is because these functions only take one input.

If a function takes more than one input, you can still use the piping operator. But make note, you can only pipe in one argument at a time.

Let’s look at an example using a simple addition function. The function will take two inputs. When we use it, we will pipe one in.

# Define an addition function:
add_this <- function(x,y){
  x + y
}

# Pipe in x:
## a)
2 |>
  add_this(3)
## [1] 5
## b)
2 %>%
  add_this(3)
## [1] 5

Remember chaining? This is a good function to give another example of that.

# Add more things:
## Chain Ex. 3a
2 |>
  add_this(3) |>
  add_this(7)
## [1] 12
## Chain Ex. 3b
2 %>%
  add_this(3) %>%
  add_this(7)
## [1] 12

First, R adds 2 to 3. Second, R adds 7 to 5. In traditional order of operations notation, the problem would look like: (2 + 3) + 7.

The piping operator takes everything that has already been calculated on its left and uses that as the first input on its right. To put this as explicitly as possible while using work-appropriate language:

  1. The 2 on the left of the first **|>**/**%>%** is used as the x input for **add_this()** and 3 is the y input.
  2. The outcome of 2 as the x input and 3 as the y input in **add_this()** is used as the x input for the next **add_this()** and 7 is the y input.

That means we could also write the following to get the same answer:

# No piping operator:
## Chain Ex. 4:
add_this(add_this(2,3),7)
## [1] 12

Even though Chain Ex. 4 is fewer lines than Chain Ex. 3, visually it is much more confusing.

The most important take away from this section, however, is that Chain Ex. 3 and Chain Ex. 4 are exactly the same. The piping operator transforms Chain Ex. 4 into Chain Ex. 3.

The order matters.

The object you are piping is the first variable in the function. In the **add_this()** function, the 2 we piped in was **x** and the 3 used in the function was **y**. Another example with a subtraction function will emphasize this.

# Define a subtraction function:
sub_this <- function(x,y){
  x - y
}

# a)
## Pipe in x:
2 |>
  sub_this(3)
## [1] -1
## Change the order:
3 |>
  sub_this(2)
## [1] 1
# b)
## Pipe in x:
2 %>%
  sub_this(3)
## [1] -1
## Change the order:
3 %>%
  sub_this(2)
## [1] 1

The piping operator is most frequently used with functions where the first input is a data frame, and the function then does something to the variables in that data frame. That is certainly the case in 99% of the examples in this guide. In words, code is saying “I want you to use information from this data frame to complete this function.”

These are simple examples, but the concepts are important. No matter what is going on with the functions, or how long the chain is, at the end of the day all the piping operator does is put something in a function as the first input. The end.