GithubHelp home page GithubHelp logo

iankloo / sigmanet Goto Github PK

View Code? Open in Web Editor NEW
41.0 7.0 8.0 1.44 MB

Render igraphs from R using Sigma.js

Home Page: https://iankloo.github.io/sigmaNet/

License: Other

R 86.66% JavaScript 13.34%
sigma r graphs visualization

sigmanet's Introduction

sigmaNet

Render igraph networks using Sigma.js - in R - now on CRAN!

Check out the full docs

Why?

This package is an R interface to the Sigma.js javascript library. Sigma.js was built for graph visualization and has significant advantages over other javascript libraries when creating large graph visualizations.

Benefits of this package:

  1. Use familiar, well documented igraph objects to make visualizations
  2. Easy "ggplot-like" syntax
  3. Render things quickly - allowing for faster iterative graph building
  4. Render large networks
  5. Maintain interactivity (click, hover, zoom) with sharable html output
  6. Integrate easily with Shiny applications

How?

First, install this package:

install.packages('sigmaNet')

Or, use the development version:

devtools::install_github('iankloo/sigmaNet')

Then, create an igraph network. Here we'll use the included les Miserables dataset that maps the co-appearances of characters in the novel.

Note, passing an optional layout to the sigmaFromIgraph() function will dramatically improve speed. Layouts are usually the most computationally intensive task when creating network visualizations. This package allows you to separate this computation from the aesthetic changes you will likely want to make to your visualization.

library(sigmaNet)
library(igraph)

data(lesMis)

layout <- layout_with_fr(lesMis)
sig <- sigmaFromIgraph(lesMis, layout = layout)
sig

If you render this at home, you'll see that you can zoom, pan, and get information on-hover for the nodes. This is just a static image to show you the basics.

Options

You have a few options available to change the aesthetics of graphs. Options are applied in a similar way to ggplot, but use the pipe operator instead of the "+". Here is an example showing most of the options you can use:

data(lesMis)

clust <- cluster_edge_betweenness(lesMis)$membership
V(lesMis)$group <- clust

layout <- layout_with_fr(lesMis)

sig <- sigmaFromIgraph(lesMis, layout = layout) %>%
  addNodeLabels(labelAttr = 'label') %>%
  addEdgeSize(sizeAttr = 'value', minSize = .1, maxSize = 2) %>%
  addNodeSize(sizeMetric = 'degree', minSize = 2, maxSize = 8) %>%
  addNodeColors(colorAttr = 'group', colorPal = 'Set1')
sig

Note: there is no opacity/transparency/alpha attribute! That is because webgl doesn't support transparency. To mimic transparency, set your edge size to be small - this works really well. I know this is a big trade off, but it is the only way to render large networks without sacrificing performance.

Larger Networks

This package was built to address the specific challenges of creating compelling visualizations with large networks. Here is an example of a larger network than we've been using (created using a graph-generating function in igraph):

g <- sample_pa(10000)

layout <- layout_with_fr(g)
sig <- sigmaFromIgraph(g, layout = layout)
sig %>%
  addNodeSize(oneSize = .5) %>%
  addEdgeSize(oneSize = .2)

While we can debate the usefulness of a "hairball" graph like this, you can see that sigmaNet has no problem rendering a graph with 10,000 nodes nearly instantly. If you render this at home, you will also see that the graph maintains its interactivity with little to no lag.

Shiny Support

You can use sigmaNet in Shiny using renderSigmaNet() in your server and sigmaNetOutput() in your ui. See the Shiny docs for more general info about Shiny - these functions drop-in just like the basic plotting examples.

Use the addListner() function to specify a Shiny listener. Current options are "clickNode" and "hoverNode". These are pretty self-explanitory - the first returns information about a node on-click and the second does the same on-hover.

Here's a minimal Shiny app that sends the result of an on-click event to a text box:

library(sigmaNet)
library(shiny)
library(magrittr)

data(lesMis)

ui <- fluidPage(
  sigmaNetOutput('network', height = '600px'),
  textOutput('text')
)

server <- function(input, output) {
  output$text <- renderText({
    req(input$node_data)
    paste0('You clicked on: ', input$node_data$label)
  })
  
  output$network <- renderSigmaNet({
    sigmaNet::sigmaFromIgraph(lesMis) %>%
      addNodeLabels(labelAttr = 'label') %>%
      addListener('clickNode')
  })
}

shinyApp(ui, server)

A Note on Browsers

This package uses a renderer that detects whether or not your browser supports webgl. If it does, webgl will be used to render the visualizations. If not, canvas will be used. Webgl is MUCH faster than canvas (especially with large graphs), so if you notice some performance issues, try using a modern browser that supports webgl. All but the most out-of-date browsers support webgl (except maybe Opera?), so this shouldn't be an issue for many.

Features in development

  • GUI to modify aesthetics (Shiny gadget)

Write an "issue" on the github page for this package if you want to see additional features.

sigmanet's People

Contributors

aj2duncan avatar iankloo avatar koalive avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

sigmanet's Issues

Added attribute, coordinates to node using R

Suppose I have below dataframe for nodes:

Node ID xAxis yAxis Name City
1 0 10 20 John New York
2 1 11 21 Peter Paris
3 2 12 22 Tom London
4 3 13 23 Sam Los Angeles
5 4 14 24 Jack Tokyo

for edges

Edge Source Target
1 0 1
2 0 3
3 1 4
4 1 2
5 2 3
6 3 1
7 4 4

In javascript case (I have JSON instead of dataframe in this case), first I will loop through all nodes and create object for each node with attribute and then push same to nodes array, same for edges.

Now want to achive same through R.

Thanks

addNodeSize doesn't keep order of nodes consistent so attributes incorrectly attached

Following on from #11 I found that betweenness was still not being plotted correctly. Upon further investigation it appears that the fix in #10 helped but didn't fix it. The nodes aren't quite being put back in the same order as in the original igraph network.

Actual Behavior

These two graphs should be identical

library(sigmaNet)
library(igraph)

sig = sigmaFromIgraph(lesMis)

size = betweenness(lesMis)

sig %>% addNodeLabels(labelAttr = 'label') %>%
  addNodeSize(sizeMetric = 'betweenness', maxSize = 8)

sig %>% addNodeLabels(labelAttr = 'label') %>%
  addNodeSize(sizeVector = size, maxSize = 8)

and when I dug into the function I found that I wasn't quite getting the behaviour I expected.

library(sigmaNet)
library(igraph)

sig = sigmaFromIgraph(lesMis)

sigmaObj = sig
# code from addNodeSize()
edges <- jsonlite::fromJSON(sigmaObj$x$data)$edges
nodes <- jsonlite::fromJSON(sigmaObj$x$data)$nodes

tmp_graph <- igraph::graph_from_data_frame(sigmaObj$x$graph$edges, directed = FALSE)

nodes$size <- igraph::betweenness(tmp_graph)
graphOut <- list(nodes, edges)
names(graphOut) <- c('nodes','edges')

sigmaObj$x$data <- jsonlite::toJSON(graphOut, pretty = TRUE)

# but if we extract the nodes back again
jsonlite::fromJSON(sigmaObj$x$data)$nodes

# they should be the same as this but the betweenness values 
# are in the wrong order
data.frame(V(lesMis)$label, betweenness(lesMis))

Expected/Desired Behavior

A small change fixes it

library(sigmaNet)
library(igraph)

sig = sigmaFromIgraph(lesMis)

sigmaObj = sig
# code from addNodeSize()
edges <- jsonlite::fromJSON(sigmaObj$x$data)$edges
nodes <- jsonlite::fromJSON(sigmaObj$x$data)$nodes

tmp_graph <- igraph::graph_from_data_frame(sigmaObj$x$graph$edges, directed = FALSE)

nodes_size <- igraph::betweenness(tmp_graph)
nodes_order <- order(as.numeric(names(nodes_size)))

nodes$size <- nodes_size[nodes_order]

graphOut <- list(nodes, edges)
names(graphOut) <- c('nodes','edges')

sigmaObj$x$data <- jsonlite::toJSON(graphOut, pretty = TRUE)

jsonlite::fromJSON(sigmaObj$x$data)$nodes

data.frame(V(lesMis)$label, betweenness(lesMis))

addNodeSize() changes undirected network to directed network

Actual Behavior

addNodeSize() changes undirected network to directed network which means that some of the calculations may be incorrect. I found it from the betweenness values.

Apologies, I somehow forgot to file an issue before filing a pr.

Expected/Desired Behavior

Keep the network as undirected.

How to Reproduce

See #10

Network with isolated nodes

Actual Behavior

Cannot render and apply node size based on degree with a network containing isolated nodes (degree = 0)

Expected/Desired Behavior

Node size based on degree should allow isolated nodes (degree = 0) with min size defined.

How to Reproduce

library(igraph)
library(sigmaNet)

set.seed(123)
g <- erdos.renyi.game(10, 1/5)
sig <- sigmaFromIgraph(g) %>%
addNodeSize(sizeMetric = 'degree')

Does sigmaNet work with directed graphs?

Actual Behavior

I have a directed igraph which I'd like to plot with sigmaFromIgraph.
However, it seems that addEdgeArrows() has been taken out of the package. How would I add arrows to a directed graph?

Expected/Desired Behavior

How to Reproduce

nodes <- read.csv()
edges <- read.csv()
graph1 <- graph_from_data_frame(d=edges, vertices = nodes, directed = TRUE)
sig <- sigmaFromIgraph(graph1)
sig

Shiny click event returning way too much data

Need to modify since accepting the two pull requests that enabled shiny on-click. The idea is good, but it is returning way too much data - even with the attempt to only return certain handlers.

Add mode argument for degree/closeness in directed networks

Actual Behavior

At the moment the sizeMetric() argument of addNodeSize() uses the default values from the available metric calculations that are defined in igraph.

Expected/Desired Behavior

It would be nice to have the ability to add a mode argument to `addNodeSize().

Search function

Hi,

First of all, thank you for this awesome package. I think it would be great if you could add a search option for the nodes (I am not much of a jscript expert myself). With the current config it is impossible to find the node in larger Networks.

Thanks,
Milos

Max no of nodes

Hi,

what is maximum no of nodes that can represented using sigmaNet for network visualization

sigmaNetOutput displays locally but not on server

Hi,

First, thank you for creating this excellent package. I've been working on a Shiny app that uses a graph generated with sigmaNetOutput. The graph displays when Shiny is running locally through RStudio, however, nothing appears when it is run from my server. Further, the shiny-server error logs show no errors. I run into the same problem when trying to host the example from the documentation.

Actual Behavior

This is the code I am running:

library(tidyverse)
library(shiny)
library(sigmaNet)

data(lesMis)

ui <- fluidPage(
  sigmaNetOutput('network', height = '600px'),
  textOutput('text')
)

server <- function(input, output, session) {
  output$text <- renderText({
    req(input$node_data)
    paste0('You clicked on: ', input$node_data$label)
  })
  
  output$network <- renderSigmaNet({
    sigmaNet::sigmaFromIgraph(lesMis) %>%
      addNodeLabels(labelAttr = 'label') %>%
      addListener('clickNode')
  })
}

shinyApp(ui = ui, server = server)

Here is how it displays on the server:

image
http://data.camraynor.io/test/

Expected/Desired Behavior

Here is how the Shiny app displays when running locally:

networkexample

How to Reproduce

When I check my server logs, everything seems to be running fine:

── Attaching packages ─────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 2.2.1     ✔ purrr   0.2.4
✔ tibble  1.4.2     ✔ dplyr   0.7.4
✔ tidyr   0.8.0     ✔ stringr 1.2.0
✔ readr   1.1.1     ✔ forcats 0.3.0
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()

Listening on http://127.0.0.1:35739

shiny-server.log

[2018-05-03T18:27:49.350] [INFO] shiny-server - Starting listener on 127.0.0.1:3838

All packages are up to date, and my server is running on an AWS EC2 t2.xlarge instance, which should have plenty of memory.

Any suggestions would be greatly appreciated.

[Feature request] Retrieve events

Dear Ian Kloo,

First, thanks a lot for your package. So far no htmlwidgets proposed OpenGL graph visualization and therefore none was suitable for big biological networks.
A nice addition would be to offer a way to retrieve nodes hovered or clicked by the user inside of the Shiny environment, in similar way as Plotly's event_data method.
This should be technically doable since Sigma.js allows to bind callbacks to event.
I would be glad to give it a try myself later, but I am by no mean a JavaScript veteran, so it might take some time and I cannot guarantee an optimal solution...

Best regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.