R networkD3 package: node coloring in simpleNetwork()
Asked Answered
S

4

13

The networkD3 package (see here and here) allows a user to create simple interactive networks:

# Load package
library(networkD3)

# Create fake data
src <- c("A", "A", "A", "A",
        "B", "B", "C", "C", "D")
target <- c("B", "C", "D", "J",
            "E", "F", "G", "H", "I")
networkData <- data.frame(src, target)

# Plot
simpleNetwork(networkData)

Is there a way to specify that I want all elements in the src vector to be a certain color, while allowing all the elements in the target vector to be a different color? This would allow me to visually distinguish src nodes from target nodes in the network.

This functionality doesn't seem to be currently supported in simpleNetwork() (but I'm hoping somebody could help me out with a homebrew script):

enter image description here

A similar but not related question was asked here.

Schoolmate answered 8/2, 2016 at 22:2 Comment(3)
Is it ok to use forceNetwork(), in the same package? you can control colour through Group, and a JavaScript scale. I can do a full answer if you're keen.Meyeroff
@PeterEllis Yes, that would be very helpful.Schoolmate
possibly a related question whereby one must colour the nodes with pre designated colours: #38794447Compliancy
M
14

Here's how to control colour of nodes with forceNetwork. Notice this still won't tell you the direction of the links because some nodes are source for some links and target for others - so you'll need to rethink that logic somehow. But anyway, here's controlling colour of nodes.

# Load package
library(networkD3)
library(dplyr) # to make the joins easier

# Create fake data
src <- c("A", "A", "A", "A",
         "B", "B", "C", "C", "D")
target <- c("B", "C", "D", "J",
            "E", "F", "G", "H", "I")
networkData <- data.frame(src, target, stringsAsFactors = FALSE)

nodes <- data.frame(name = unique(c(src, target)), stringsAsFactors = FALSE)
nodes$id <- 0:(nrow(nodes) - 1)


# create a data frame of the edges that uses id 0:9 instead of their names
edges <- networkData %>%
   left_join(nodes, by = c("src" = "name")) %>%
   select(-src) %>%
   rename(source = id) %>%
   left_join(nodes, by = c("target" = "name")) %>%
   select(-target) %>%
   rename(target = id)

edges$width <- 1

# make a grouping variable that will match to colours
nodes$group <- ifelse(nodes$name %in% src, "lions", "tigers")

# simple with default colours
forceNetwork(Links = edges, Nodes = nodes, 
             Source = "source",
             Target = "target",
             NodeID ="name",
             Group = "group",
             Value = "width",
             opacity = 0.9,
             zoom = TRUE)

# control colours with a JS ordinal scale
# edited 20 May 2017 with updated code from Renal Chesak's answer:
ColourScale <- 'd3.scaleOrdinal()
            .domain(["lions", "tigers"])
           .range(["#FF6900", "#694489"]);'

forceNetwork(Links = edges, Nodes = nodes, 
             Source = "source",
             Target = "target",
             NodeID ="name",
             Group = "group",
             Value = "width",
             opacity = 0.9,
             zoom = TRUE,
             colourScale = JS(ColourScale))

enter image description here

Meyeroff answered 12/2, 2016 at 19:55 Comment(2)
It would be nice to have the nodes all labeled. Could you please expand your answer to show how to make the nodes (for both src and target) have their names be automatically displayed instead of on-hover accessibility only?Schoolmate
There is an argument called opacityNoHover for this. Use opacityNoHover = 1 to always show the node labels.Flirtation
M
5

Peter Ellis's answer above might have worked at one time, but it seems the code has been updated in a new release. Instead of d3.scale.ordinal().range([]), you will have to use d3.scaleOrdinal().range([])

Machinery answered 14/4, 2017 at 14:55 Comment(1)
Thanks. I don't use this combination very often and only saw the change three years after your answer here, when wondering in my own work why this doesn't work any more! I've edited my original answer in response.Meyeroff
T
2

Peter Ellis' answer does the job, but this is an alternate approach, which imho is bit more concise and easier to understand...

(Also, it should be noted that nodes can be in both the source and the target vectors at the same time, in which case, which color they should be, given your specification, is uncertain.)

library(networkD3)

src <- c("A", "A", "A", "A", "B", "B", "C", "C", "D")
target <- c("B", "C", "D", "J", "E", "F", "G", "H", "I")
networkData <- data.frame(src, target, stringsAsFactors = FALSE)

# make a nodes data frame out of all unique nodes in networkData
nodes <- data.frame(name = unique(c(networkData$src, networkData$target)))

# make a group variable where nodes in networkData$src are identified
nodes$group <- nodes$name %in% networkData$src

# make a links data frame using the indexes (0-based) of nodes in 'nodes'
links <- data.frame(source = match(networkData$src, nodes$name) - 1,
                    target = match(networkData$target, nodes$name) - 1)

forceNetwork(Links = links, Nodes = nodes, Source = "source",
             Target = "target", NodeID ="name", Group = "group",
             opacity = 1, opacityNoHover = 1)

enter image description here

Tremaine answered 24/12, 2017 at 15:17 Comment(0)
O
1

You could do a similar thing as in the linked post, but here is an example using the visNetwork package. This package interfaces with vis.js, and makes really nice interactive graphs.

library(visNetwork)
id <- unique(c(src, target))                                  # node ids
nodes <- data.frame(id, group=+(id %in% src),                 # add a grouping for src/target
  label=id, title=sprintf('<p>Node %s</p>', id))              # add some labels
g <- visNetwork(nodes=nodes, edges=networkData, width="75%")  # make graph
visExport(visHierarchicalLayout(g))                           # make it tree-like

enter image description here

Oloughlin answered 9/2, 2016 at 3:7 Comment(1)
Very cool. I sure hope you find something similar in networkD3 :-) +1Schoolmate

© 2022 - 2024 — McMap. All rights reserved.