Search code examples
rdictionarynetwork-programmingvisnetwork

How to display text out of color figure and easy to read in visNetwork?


I'm getting a Network Map done using R with visNetwork library, but I hate that displayed legend has text inside the shape, so it's size is defined by how big the name is and I don't want it to be that way to avoid confusion. In library documentation they add shapes that display text outside, but you have to set it group by group with a visGroups piece (shape = "triangle", for example) for each one of the groups and I want it set in a way where I can leave that code set without specifically knowing how many groups they will be, because it won't necesarilly be the same number every time.

Coding below is the one I'm using (way much bigger, made it simple by selecting only some colums & rows):

library(igraph)
library(visNetwork)


twd2 <- structure(c(0.0854374047081175, 0.116200039661793, 0.0289142580616779, 
                    0.12768720590989, 0.273786051264039, 0, 0.000593902599973604, 
                    0, 0.00184397276348455, 0, 0, 0, 0, 0, 0, 0, 0.106048390315551, 
                    0, 0, 0, 0.0142648455772593, 0, 0.0197857551361577, 0.0290239379534046, 
                    0, 0, 0, 0, 0, 0, 0, 0, 0.00197967638677129, 0, 0.000296951299986802, 
                    0, 0.0111915576381184, 0, 0.00111081782587656, 0.0276104933163398, 
                    0, 0, 0.00487220095904272, 0.0149921777316026, 0, 0, 8.79855703664599e-05, 
                    0.00674104365369398, 0, 0, 0.0330935726540847, 0, 0, 0.0362094142674287, 
                    0, 0, 0, 0.00172168238114983, 0.00232061941841538, 0.0248983709144504
), .Dim = c(4L, 15L), .Dimnames = list(NULL, c("water_treatment", 
                                               "waste_water", "utility_model", "water_inlet", "waste_water_treatment", 
                                               "treatment_system", "model_discloses", "utility_model_discloses", 
                                               "water_outlet", "water_treatment_system", "treatment_device", 
                                               "water_tank", "sludge_treatment", "reverse_osmosis", "raw_water")))
twd2_num_col <- ncol(twd2)
twd2_cor <- cor(twd2, method = "pearson")
twd2_cor[ abs(twd2_cor) <  0.75 ] <- 0
twd2_cor[ abs(twd2_cor) >  0.925 ] <- 0
diag(twd2_cor) <- 0
graph <- graph.adjacency(twd2_cor, weighted=TRUE, mode="lower")
E(graph)$edge.width  <- E(graph)$weight
V(graph)$group       <- apply(twd2, 2, which.max)  # Max topic prob for colors
V(graph)$betweenness <- betweenness(graph, v = V(graph), directed = F)
V(graph)$degree      <- degree(graph, v = V(graph))

# Fit data for visNetwork
nm_data <<- toVisNetworkData(graph)
nodes <<- as.data.frame(nm_data[[1]], stringsAsFactors = F)
nodes <<- nodes[nodes$degree != 0,]    # Bye topics that don't have a connection (degree = 0)
nodes$group <<- swap(nodes$group , 1:length(topic_names), topic_names) # Swap long real names
nodes$label <<- rep("")


# Plot
  # Graph
  set.seed(17);visNetwork(as.data.frame(nodes, stringsAsFactors = F), 
                          as.data.frame(nm_data[[2]], stringsAsFactors = F), 
                          main = "Relation between topics")  %>%
    visOptions(highlightNearest = TRUE, selectedBy = "group") %>%
    visInteraction(dragNodes = FALSE) %>%
    visLegend(useGroups = TRUE, main = "Topic")  %>%
    visNodes(shape = "dot",label = NULL) %>%
    visIgraphLayout(randomSeed = 17)

Additionaly, here they make reference to what I said aboud selecting type of shapes, but they don't add any code and I can't figure out if there is a way to do it directly and apply it to all group options or any other choice I could have.


Solution

  • ledges <- data.frame(color = c("lightblue", "red"), 
     label = c("reverse", "depends"), arrows =c("to", "from"), 
     font.align = "top") 
     
    visNetwork(nodes, edges) %>%
      visGroups(groupname = "A", color = "red") %>%
      visGroups(groupname = "B", color = "lightblue") %>%
      visLegend(addNodes = lnodes, addEdges = ledges, useGroups = FALSE)
    

    font.align = "top" must do the job