---
title: "Practical 1"
author: "James Hollway"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Practical 1}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

# Working with network data

While `{migraph}` includes a number of datasets (see [here](https://snlab-ch.github.io/migraph/reference/index.html#section-data)),
and there are several packages in R that already include
a range of social network data,
there often comes a time when it is necessary to import and analyse data
from other sources.
Fortunately, `{migraph}` has a range of tools you can employ to import your data and manipulate it.

# Import data

`{migraph}` includes several functions that help 
read from (import) and write to (export) network data 
in a growing number of formats.

One format most users are long familiar with is Excel.
In Excel, users are typically collecting network data as edgelists, nodelists, or both.
Edgelists are typically the main object to be imported,
and we can import them from an Excel file or a `.csv` file.^[Note that if you import from a .csv file, please specify whether the separation value should be commas (`sv = "comma"`) or semi-colons (`sv = "semi-colon"`).]

```{r importedges, include = TRUE, eval = FALSE}
library(migraph)
g1 <- read_edgelist("~Downloads/mynetworkdata.xlsx")
g1 <- read_edgelist("~Downloads/mynetworkdata.csv")
g1 <- read_edgelist()
n1 <- read_nodelist()
```

If you do not specify a particular file name, 
a helpful popup will open that assists you with locating and importing a file
from your operating system.
Importing a nodelist of nodal attributes operates very similarly.

In some cases, users will be faced with having to collect data themselves,
or wish to first manipulate the data in Excel before importing it,
but may be uncertain about the expected format of an edgelist.
Here it may be useful to try exporting one of the built-in datasets
in `{migraph}` to see how complete network data looks.
If this is potentially complex, 
calling `write_edgelist()` without any arguments will export a test
file with a barebones structure that you can overwrite with your own data.

```{r exportdata, include = FALSE, eval = FALSE}
write_edgelist(ison_southern_women)
write_edgelist()
write_nodelist(ison_southern_women)
write_nodelist()
```

There are other functions here too that help import from or export to
common external network data formats.
Here are some examples:

```{r otherimports, include = TRUE, eval = FALSE}
# for importing .net or .paj files
read_pajek()
write_pajek()
# for importing .##h files 
# (.##d files are automatically imported alongside)
read_ucinet()
write_ucinet()
```

# Converting between formats

By default, `read_` and `write_` `edgelist` and `nodelist` will import objects
into a data frame or tibble format or 'class' object,
and `read_` and `write_` `pajek` or `ucinet` will import objects into a
tidygraph class format.

These can be already useful, as `{migraph}` functions recognise and 
work with most main classes of network/graph objects in R: 
edgelists, matrices, igraph, tidygraph, and network objects.

However it is sometimes necessary to convert a given object 
from one class to another.
Here we can use any of a collection of coercion functions, 
all prefixed by `as_`, to move from any of those objects
that `{migraph}` recognises to any other.
  
Let's use one of the built in datasets in `{migraph}` to demonstrate this.
Davis, Gardner and Gardner's (1941) `ison_southern_women` dataset is a classic
two-mode network, so let's use this to start with.
`{migraph}` stores this dataset as an 'igraph' object,
though other included datasets are in 'tidygraph' or sometimes 'network' formats.
  
```{r as}
library(migraph)
ison_southern_women # this is in igraph format
as_tidygraph(ison_southern_women) # now let's make it a tidygraph tbl_graph object
as_network(ison_southern_women) # a network object
as_matrix(ison_southern_women) # a matrix object
# this is an incidence matrix since it is a two-mode network
# if it were a one-mode network, the function would return an adjacency matrix
as_edgelist(ison_southern_women) # an edgelist data frame/tibble
```
  
<!-- Note that for converting into edgelist, matrix, or igraph objects, you can specify if you want to keep it as a weighted network (if your original data included this property) using the argument `weight = TRUE` or `weight = FALSE`. -->
<!-- For converting into igraph and tidygraph objects, there is the option of retaining the network as a two-mode network (keeping different types of nodes) or simplifying it into a one-mode network.  -->
<!-- Just specify it using the argument `twomode = TRUE` or `twomode = FALSE` respectively. -->

# Transforming network data
  
Generally, `{migraph}` attempts to retain as much information as possible when converting objects between different classes.
The presumption is that users should explicitly decide to reduce or simplify
their data.
`{migraph}` includes [a number of functions](https://snlab-ch.github.io/migraph/reference/to.html) 
for transforming (or removing) certain properties of network objects.
For example: 

- `to_unnamed()` removes/anonymises all vertex/node labels
- `to_undirected()` replaces directed ties with an undirected tie (if an arc in either direction is present)
- `to_unweighted()` binarises or dichotomises a network around a particular threshold (by default `1`)
- `to_unsigned()` returns just the "positive" or "negative" ties from a signed network, respectively
- `to_uniplex()` reduces a multigraph or multiplex network to one with a single set of edges or ties
- `to_simplex()` removes all loops or self-ties from a complex network

Then there are a few more special functions included here too:

- `to_multilevel()` extends objects to more than two modes and sets of interlocking ties
- `to_onemode()` converts multimodal networks into networks with only one type of node 
- `to_main_component()` identifies and returns only the main component of a network
- `to_named()` adds random names to an anonymous network, which can be useful for pedagogical purposes

```{r combine}
to_unnamed(ison_marvel_relationships)
to_named(ison_algebra)
to_undirected(ison_algebra)
to_unsigned(ison_marvel_relationships, keep = "positive")
```

Note that for two-mode networks, there are also functions for converting or 'projecting' two-mode networks into one-mode networks.

```{r project}
to_mode1(ison_southern_women)
to_mode2(ison_southern_women)
```

# Adding data

If you import one or more edgelists and nodelists, 
it can be useful to bind these together in an igraph, tidygraph, or network class object.

Adding nodal attributes to a given network is relatively straightforward.
One can bind a single new attribute to the nodes with `add_node_attribute()`
or copy a set of attributes from one network/graph to another with `copy_node_attributes()`.
But often the easiest way to do this is to take a network/graph,
make sure it is first coerced into a tidygraph object,
and then add any additional nodal attributes (including measures from `{migraph}`)
as follows:

```{r mutate}
as_tidygraph(mpn_elite_mex) %>% 
  mutate(order = 1:35,
         color = "red",
         degree = node_degree(mpn_elite_mex))
```

Adding edge attributes or new edges is not quite so straightforward,
in part because you will need to decide which it is that you want to do.
If you would like to just add a new edge attribute to an existing set of edges,
without adding any new edges, then `add_edge_attributes()` operates similarly
to `add_node_attributes()` above.
But if the result should be a multiplex network in the ties in the different
component networks only partially overlap,
then you will need to use `join_edges()`:

```{r mutateedges}
generate_random(10, .3) %>% 
  join_edges(generate_random(10, .3), "next")
```

# Retrieving data

Lastly, sometimes we want to extract certain information from a network or graph object.
Here too `{migraph}` has you covered.

```{r grab}
node_names(mpn_elite_mex) # gets the names of the nodes
node_attribute(ison_marvel_relationships, "Gender") # gets any named nodal attribute
edge_attribute(ison_marvel_relationships, "sign") # gets any named edge attribute
edge_weights(mpn_elite_mex)
```

We can describe the data using similar functions.
How many nodes in the network, or how many edges?

```{r dims}
graph_nodes(mpn_elite_mex)
graph_edges(mpn_elite_mex)
graph_dims(mpn_elite_mex)
```
