---
title: "Mutating and filtering"
author: "Your name here"
format: pdf
---

We start with a "setup" block of code, that loads our libraries and initializes our settings. This block should work for basically all of our assignments this semester, so you can just copy and paste it.

```{r setup, warning=FALSE, message=FALSE}
knitr::opts_chunk$set(echo = T)
knitr::opts_knit$set(root.dir = './')
library(tidyverse)
library(igraph)
library(tidygraph)
library(ggraph)
set_graph_style(family='sans') # This sets the default style to the graph style
```


R has a lot of great tools for working with tables (also called dataframes or tibbles). One really powerful and relatively intuitive set of tools is called the "tidyverse". Tools in the tidyverse make assumptions about what data will look like---rows represent observations and columns represent variables that describe that observation.

The [tidygraph](https://tidygraph.data-imaginist.com/index.html) package extends that paradigm to networks, by representing networks as two tables: 1) a table of nodes and node attributes and 2) a table of edges and edge attributes.

This lets you work with networks using many of the same tools that have been developed for working on other types of data.

Just to make things simple, we'll use the Zachary Karate club data for most of this tutorial. Let's load it, and save it as `G`

```{r}
G <- create_notable('Zachary')
```

If we look at `G` we can see that it's already a `tbl_graph` object. It has 34 nodes and 78 edges.

```{r}
G
```

## Getting to the data

### Activating a table

Because a network object is really composed of two tables, we have to let R know which table we want to manipulate. This is done using `activate(nodes)` or `activate(edges)`. You will see lots of examples of this later in this tutorial.

## Mutate

`mutate` is a function that creates a new column in a spreadsheet/dataframe (in our case, either the spreadsheet for the nodes or the one for the edges). 

Often, we will want to calculate some network statistic about the nodes or edges. However, you can also create other kinds of columns. For example, you could use `mutate` to give names to each of the nodes. The code below creates a small network and adds names to it. (The `c` is how we create a list of things in R)

(Note that the code throughout this tutorial uses "[pipes](https://r4ds.had.co.nz/pipes.html?q=pipe#pipes)". Pipes (`|>`) let you express a sequence of operations, by taking the output of the previous operation and using it as the input of the next operation.)

```{r}
play_gnp(5, .5) |>
activate(nodes) |>
  mutate(names = c('Alfred','Bonnie', 'Clyde', 'Doug','Enola'))
```

The example below also uses mutate, but this time it calculates the degree of each node in the network and saves it in a new column called `degree`.

```{r}
G |>
  activate(nodes) |>
  mutate(degree = centrality_degree())
  
```

However, note that if we look at `G` again, the `degree` column that we created no longer appears.

```{r}
G
```

This is because we didn't save it; by default mutate will just produce a temporary version of the new column. But don't worry---saving it is super easy; we can just re-save it as G like this.

```{r}
G <- G |>
  activate(nodes) |>
  mutate(degree = centrality_degree())
```

The `<-` means take whatever is on the right side, and save it to the variable name on the left side. So, this takes all of the output of the `mutate` operation and saves it. Now, when we look at `G`, we'll see the `degree` column.

```{r}
G
```


## Filtering

The one other thing we're going to learn about today is filtering. Sometimes we may want to know about some subset of the nodes or edges in a network.

Usually, we would do this based on some attribute of the nodes---for example, looking just at the network of the older (or younger) members of the group.

Let's load in a richer network from the `networkdata` library. (See R Lab 2 for instructions on how to install it if this code doesn't work.)

This code loads the `networkdata` library and loads the `ht_advice` network. It then changes it from an `igraph` network to a `tbl_graph` network object.

```{r}
library(networkdata)
ht_advice <- ht_advice |> as_tbl_graph()

ht_advice
```

We can see that there are 21 nodes with four attributes: `age`, `tenure`, `level`, and `dept`. These nodes have 190 edges. Let's plot the network.

```{r}
plot(ht_advice)
```


Now we're going to filter the graph. Maybe we just want to see the network from the Sales department. Let's pretend like that's department two, and filter to just those nodes.

Remember, we first `activate` the `nodes`. Then, we use `filter` to write a condition or set of conditions that will evaluate to True for each of the nodes that we want to keep. Usually, this will involve one node attribute (like `dept`) and a comparison, like `<`, `>`, or `==`. Note that when we are testing _if_ things are equal, we use two equal signs in R. This is because one equals sign can be used to assign something to a variable.

```{r}
ht_advice |>
  activate(nodes) |>
  filter(dept == 2) |> # Filter to just nodes in dept 2
  print() |> # We can throw in print() and it will print the output of the last step. In this case, the filtered graph object.
  plot()
```


## Chaining Filtering and Mutating

Finally, we can use `mutate` and `filter` together in powerful ways.

For example, we may want to get the betweenness centrality of just the Sales department.

```{r}
ht_advice |>
  activate(nodes) |>
  filter(dept == 2) |>
  mutate(betweenness = centrality_betweenness())
```

Remember that the order matters - if we ran `mutate` before `filter` then it would calculate the betweenness centrality _before_ filtering.

### Excercises

1. Modify the code on lines 49-53 to calculate the betweenness centrality instead of the degree of `G`. Name the column `betweenness` (Hint: use the `centrality_betweenness()` function. ([Here is the list of all centrality functions](https://tidygraph.data-imaginist.com/reference/centrality.html).)

```{r}
# Your code here
  
```

2. Now, modify your code above to save the `betweenness` column to `G`. When you're done, the nodes spreadsheet of `G` should have two new columns - `degree` and `betweenness`. Display G (by just typing `G` at the end of the code block) to make sure it worked.

```{r}
# Your code here
```

3. It's more common that we mutate the nodes, but sometimes we want to mutate the edges. For example, `centrality_edge_betweenness()` is one measure of how important each edge in a network is. Use `mutate` to calculate the edge betweenness of each edge in `G`.

```{r}

# Your code here
```

4. Filter the `ht_advice` network to just the people who are older than 35. How many nodes are there? How many edges? (Hint: you can use `print` like I do in the example above to print information about the graph before you plot it)

```{r}
# Your code here
```

5. Filter the `ht_advice` network to only those nodes whose `tenure` is less than the median value for `tenure`. Plot the graph.

```{r}
## Your code here
```

6. Sometimes we want to filter before calculating statistics, and sometimes we want to calculate statistics first. Calculate the degree centrality for `ht_advice`, save it in a column called `degree`, and then filter to just the nodes with `degree` of at least 2, and plot the network.

```{r}

## Your code here
```


7. Let's go crazy. Take the `ht_advice` network, filter to just the nodes with `dept` equal to 2, and then calculate the degree centrality. Then, filter to just the nodes with a degree centrality of at least 3. Finally, plot the network.

```{r}
## Your code here
```