javascriptrshinyvis.jsvisnetwork

Draw a circle around nodes groups


In the following vis-network I have 2 groups of nodes. I have separated the 2 groups of nodes into left and right side by accessing the node positions after generating a layput_as_tree. Now would like to draw a circle or ellipse around the node groups. here is a reproducible example

require(shiny)
require(visNetwork)
server <- function(input, output) {
  output$network <- visNetwork::renderVisNetwork({
    edges <- data.frame(
      from = sample(1:10, 8),
      to = sample(1:10, 8),
      label = paste("interaction type", 1:8),
      length = c(100, 500),
      width = c(4, 1),
      arrows = c("to", "from", "middle", "middle;to"),
      dashes = c(TRUE, FALSE),
      title = paste("interaction name", 1:8),
      smooth = c(FALSE, TRUE),
      shadow = c(FALSE, TRUE, FALSE, TRUE)
    )
    nodes <- data.frame(
      id = 1:10,
      group = c("A", "B"),
      label = paste("Node", 1:10),
      shape = "ellipse"
    )

    # save the graph in variable
    g <-
      visNetwork::visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
      visNetwork::visIgraphLayout(layout = "layout_as_tree")

    # access the x and y co-ordinates to arrange the groups
    coords <- g$x$nodes %>%
      dplyr::mutate(x = abs(x)) %>%
      dplyr::mutate(y = abs(y)) %>%
      dplyr::mutate(x = ifelse(group %in% "A", -x, x)) %>%
      dplyr::select(x, y) %>%
      as.matrix()

    #' replot the network with the new co-ordinates
    visNetwork::visNetwork(nodes, edges, height = "500px", width = "100%") %>%
     visNetwork::visIgraphLayout(
      layout = "layout.norm",
      layoutMatrix = coords,
      randomSeed = 1,
      smooth = T
    ) 
  })
}

ui <- shiny::fluidPage(
  visNetwork::visNetworkOutput("network",
    width = "1000px", height = "700px"
  )
)

shiny::shinyApp(ui = ui, server = server)

Solution

  • Using the visEvents and passing a Javascript code was able to generate the circle around the node groups.

    graph %>%
        visNetwork::visEvents(type = "on", beforeDrawing = "function(ctx) {
        ctx.fillStyle = 'rgba(255, 0, 255, 0.1)';
        ctx.ellipse(-180 , 25, 150, 280 , 0, 0, 2 * Math.PI);
        ctx.fill();
        ctx.fillStyle = 'rgba(64, 255, 255,0.1)';
        ctx.ellipse(180 , 25, 150, 280, 0, 0, 2 * Math.PI);
        ctx.fill();
    }")
    

    enter image description here