Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/evamaerey/ggedgelist

Use edgelist flat files as inputs to start building network visualizations with ggraph
https://github.com/evamaerey/ggedgelist

Last synced: 11 days ago
JSON representation

Use edgelist flat files as inputs to start building network visualizations with ggraph

Awesome Lists containing this project

README

        

---
output: github_document
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```

## Intro {ggedgelist} idea

Here we think about a shortcut to a first looks at networks using a flat, edgelist input that leads straight to a ggplot2 plot (ggraph) space; this uses {tidygraph} and {ggraph} under the hood...

## Step 00 Before getting into it, create an 'interesting' edge list

```{r cars, message=F, warning=F}
library(tidyverse)
library(tidygraph)
library(ggraph)

set.seed(12345)

edge_list <-
data.frame(node_to = sample(rep(LETTERS[1:10], 50),
replace = T),
node_from = sample(rep(LETTERS[1:10], 50),
replace = T)) %>%
arrange(node_to, node_from) %>%
count(node_to, node_from) %>%
sample_n(18)

head(edge_list)
```

## Step 0. Whats the status quo edgelist -> network viz

```{r}
edge_list %>%
as_tbl_graph() %>%
ggraph() +
geom_edge_link(color = "orange") +
geom_node_point(size = 9,
color = "steelblue",
alpha = .8) +
geom_node_text(aes(label = name))

# aesthetic mapping for edge characteristics
last_plot() +
geom_edge_link(color = "red",
alpha = .5 ,
aes(edge_width = n))
```

## Step 0.a And to also vizualize node atributes

```{r}
node_info <- data.frame(my_nodes = LETTERS[1:10],
ind_child = sample(c(T,F), 10,
replace = T))

edge_list %>%
as_tbl_graph() %>%
left_join(node_info %>%
rename(name = my_nodes)) %>%
ggraph() +
geom_edge_link(color = "orange") +
geom_node_point(size = 9,
color = "steelblue",
alpha = .8) +
geom_node_text(aes(label = name))

```

# Proposed functions, edgelist -> plotspace feel

```{r ggedgelist}
# get into ggplot2 plot space from edge list data frame
ggedgelist <- function(edgelist, nodelist = NULL, ...)(

# message("'name' a variable created in the 'nodes' dataframe")

if(is.null(nodelist)){
edgelist %>%
tidygraph::as_tbl_graph() %>%
ggraph::ggraph(...)

}else{ # join on nodes attributes if they are available

names(nodelist)[1] <- "name"

edgelist %>%
tidygraph::as_tbl_graph() %>%
dplyr::full_join(nodelist) %>%
ggraph::ggraph(...)

}

)

# get a fill viz w edgelist dataframe only
ggedgelist_quick <- function(edgelist, nodelist = NULL, include_names = F, ...){

p <- ggedgelist(edgelist = edgelist,
nodelist = nodelist, ...) +
ggraph::geom_edge_link(color = "orange") +
ggraph::geom_node_point(size = 9,
color = "steelblue",
alpha = .8)

if(include_names){p + ggraph::geom_node_label(aes(label = name))}else{p}

}

geom_node_label_auto <- function(...){

ggraph::geom_node_label(aes(label = name), ...)

}

geom_node_text_auto <- function(...){

ggraph::geom_node_text(aes(label = name), ...)

}
```

# examples w/ proposed functions

## `ggedgelist_quick()`

```{r, out.width="33%", fig.show='hold', message=F}
head(edge_list)
head(node_info)
edge_list %>%
ggedgelist_quick()

edge_list %>%
ggedgelist_quick(include_names = T)

edge_list %>%
ggedgelist_quick(nodelist = node_info) +
geom_node_point(aes(color = ind_child), size = 10)
```

## `ggedgelist()` + `geom_node_label_auto()`

```{r}
edge_list %>%
ggedgelist(layout = "kk") +
geom_edge_link(arrow = arrow(), linetype = "dashed") +
geom_node_tile(width = .18, height = .5) +
geom_node_label_auto()
```

# using the ggflowchart example (100% inspiration)

```{r}
# flowcharter example
ggflowchart_example <- tribble(~from, ~to,
"A", "B",
"A", "C",
"A", "D",
"B", "E",
"C", "F",
"F", "G")

ggflowchart_example %>%
as_tbl_graph()
```

## Start by using quick plot function 'qedgelist2ggraph'

```{r, out.width="33%", fig.show='hold', message=F}
ggflowchart_example %>%
ggedgelist_quick(layout = "stress",
include_names = T)

ggflowchart_example %>%
ggedgelist_quick(layout = "tree",
include_names = T)

# auto which is default also produces three in this case
ggflowchart_example %>%
ggedgelist_quick(layout = "auto")

layer_data(last_plot(), i = 2)
```

## Use ggedgelist and geom_edge_* and geom_node_* functions to customize

```{r}
ggflowchart_example %>%
ggedgelist() +
geom_edge_link(linetype = "dashed") +
geom_node_point(size = 12, alpha = .2) +
geom_node_label_auto(fill = "magenta")

```

## Capabilities end here. If you need to access powerful network calculation capabilities, step back into the tidygraph world!

```{r}
ggflowchart_example %>%
as_tbl_graph() %>%
mutate(dg_cent = centrality_degree()) %>%
ggraph("stress") +
geom_edge_link(linetype = "dashed") +
geom_node_point(alpha = .2, aes(size = dg_cent)) +
scale_size(range = c(8, 15)) +
geom_node_label_auto(fill = "magenta")

```

# Part II. Packaging and documentation 🚧 ✅

## Phase 1. Minimal working package

### Created files for package archetecture with `devtools::create(".")` ✅

### Moved functions R folder? ✅

```{r}
knitr::knit_code$get() |> names()
```

Use new {readme2pkg} function to do this from readme... ✅

```{r}
readme2pkg::chunk_to_r("ggedgelist")
```

### Added roxygen skeleton? ✅

Use a roxygen skeleton for auto documentation and making sure proposed functions are *exported*.

### Managed dependencies ? ✅

Package dependencies managed, i.e. `depend::function()` in proposed functions and declared in the DESCRIPTION

```{r pkg_dependencies}
usethis::use_package("ggplot2")
usethis::use_package("ggraph")
usethis::use_package("tidygraph")
usethis::use_package("dplyr")
```

### Chosen a license? ✅

```{r pkg_license}
usethis::use_mit_license()
```

### Run `devtools::check()` and addressed errors? 🚧

```{r pkg_check, results='hide', error=T}
devtools::check(pkg = ".")
```

### Build package 🚧

```{r pkg_build}
devtools::build()
```

You need to do this before library(mynewpackage) will work.

### Make aspirational part of readme real. 🚧

At this point, you could change eval chunk options to TRUE. You can remove the 🦄 emoji and perhaps replace it with construction site if you are still uncertain of the API, and want to highlight that it is subject to change.

### Add lifecycle badge (experimental)✅

```{r pkg_lifecycle_badge}
usethis::use_lifecycle_badge("experimental")
```

## Phase 2: Listen & iterate 🚧

Try to get feedback from experts on API, implementation, default decisions. Is there already work that solves this problem?

## Phase 3: Let things settle

### Settled on examples. Put them in the roxygen skeleton and readme. 🚧

### Written formal tests of functions? 🚧

That would look like this...

```{r test_calc_frequency_works, eval = F}
library(testthat)

test_that("calc frequency works", {
expect_equal(calc_frequency("A", 0), 440)
expect_equal(calc_frequency("A", -1), 220)
})
```

```{r send_tests, eval = F}
readme2pkg::chunk_to_tests_testthat("test_calc_frequency_works")
```

### Have you worked added a description and author information in the DESCRIPTION file? 🚧

### Addressed *all* notes, warnings and errors. 🚧

## Promote to wider audience...

### Package website built? 🚧

### Package website deployed? 🚧

## Phase 3: Harden/commit

### Submit to CRAN? Or don't. 🚧

# Appendix: Reports, Environment

## Description file extract

```{r}

```

## Environment

Here I just want to print the packages and the versions

```{r session_pkgs}
all <- sessionInfo() |> print() |> capture.output()
all[11:17]
```

## `devtools::check()` report

```{r report_check, error = T, results="hide", warning=F}
devtools::check(pkg = ".")
```