---
title: "Basic Usage of **NetworkDistance** Package"
author: "Kisung You"
output:
  pdf_document:
    fig_caption: true
vignette: >
  %\VignetteIndexEntry{Basic Usage of NetworkDistance Package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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


## 1. Load
Surely, the first thing we are always bound to do is to load the package,
```{r call}
library(NetworkDistance)
```

## 2. Computing Distances
Suppose you have $N$ network objects represented as square adjacency matrices. All the functions in the package require your data to be in a form of `list` whose elements are your adjacency matrices. Let's load example data `graph20`.
```{r load}
data(graph20)     # use `help(graph20)' to see more details.
typeof(graph20)   # needs to be a list
```

Before proceeding any further, since we have two types of graphs - densely and sparsely connected with $p=0.8$ and $p=0.2$ - we know that the distance matrix should show block-like pattern. Below is two example graphs from the dataset.

```{r showgraph, echo=FALSE, fig.align='center'}
suppressMessages(library(igraph))
par(mfrow=c(1,2),pty="s")
plot(graph_from_adjacency_matrix(graph20[[7]], mode="undirected"), vertex.size=7, vertex.label=NA, main="graph No.7", edge.arrow.size=.5)
plot(graph_from_adjacency_matrix(graph20[[18]], mode="undirected"), vertex.size=7, vertex.label=NA, main="graph No.18", edge.arrow.size=.5)
```

Once you have your data in such a form, all you've got is to run a single-line code to acquire distance numerics, resulting in either a `dist` class object or a square matrix. For example, let's compute *graph diffusion distance* by Hammond et al. (2013) on our example set.

```{r run}
dist.gdd <- nd.gdd(graph20)  # return as a 'dist' object
```

and you can see the discriminating pattern from the distance matrix `dist.gdd$D` with black represents $0$ and white represents the largest positive number, indicating large deviation from 0.

```{r run_vis1, echo=FALSE, fig.align='center'}
par(pty="s")
dmat = as.matrix(dist.gdd$D)
image(dmat[,20:1],main="pairwise distance matrix",axes=FALSE,col=gray(0:100/100)) 
```

Finally, let's compare different methods as well.

```{r compare}
dist.wsd <- nd.wsd(graph20)              # spectrum-weighted distance
dist.dsd <- nd.dsd(graph20, type="SLap") # discrete spectral measure
dist.nfd <- nd.nfd(graph20)              # network flow distance
```
```{r run_vis2, echo=FALSE}
par(mfrow=c(1,3),pty="s")
image(as.matrix(dist.wsd$D)[,20:1],main="nd.wsd",axes=FALSE,col=gray(0:100/100)) 
image(as.matrix(dist.dsd$D)[,20:1],main="nd.dsd",axes=FALSE,col=gray(0:100/100)) 
image(as.matrix(dist.nfd$D)[,20:1],main="nd.nfd",axes=FALSE,col=gray(0:100/100)) 
```


## 3. One Application : Embedding Networks, Not Network Embedding

Our interest is focused on dealing with a collection of networks, **not** a single network. Therefore, the example we cover here is to **embed** multiple networks, not an embedding of single network and its nodes as points. We will use multidimensional scaling to embed 20 graphs we did before.

```{r embed}
gdd2 = stats::cmdscale(dist.gdd$D, k=2)  # 2-d embedding from 'gdd' distance
wsd2 = stats::cmdscale(dist.wsd$D, k=2)  #                    'wsd'
dsd2 = stats::cmdscale(dist.dsd$D, k=2)  #                    'dsd'
nfd2 = stats::cmdscale(dist.nfd$D, k=2)  #                    'nfd'
```

```{r embed_vis, echo=FALSE, fig.align="center"}
par(mfrow=c(2,2))
plot(gdd2, main="embedding with 'gdd'", pch=19, xlab="x", ylab="y", cex=0.25)
plot(wsd2, main="embedding with 'wsd'", pch=19, xlab="x", ylab="y", cex=0.25)
plot(dsd2, main="embedding with 'dsd'", pch=19, xlab="x", ylab="y", cex=0.25)
plot(nfd2, main="embedding with 'nfd'", pch=19, xlab="x", ylab="y", cex=0.25)
```

From the figure above, we can see that different measures/metrics reveal a variety of topological or network features. This necessitates the very existence of a package like ours to provide a set of tools for diverse perspectives on the space networks.