schochastics / graphlayouts

new layout algorithms for network visualizations in R
https://schochastics.github.io/graphlayouts/
Other
274 stars 16 forks source link

Prevent Node and Edge Overlaps for Radial Layout with Focal Node #31

Closed tusharmajhi9 closed 4 years ago

tusharmajhi9 commented 4 years ago

Hi,

I am trying to plot a Radial Layout with Focal Node with my data that contains ~3000 Nodes. How do I make sure that none of the nodes and edges overlap and are spaced out clearly even if I increase the node size. I was wondering if the radii of the concentric circles could be controlled in order to prevent overlapping of nodes, but I am also looking have non-overlapping edges.

Below id my code and attached is the .RData:

layout<-layout_with_focus(df.g,v = 1383) max(distances(df.g,1383))

ggraph(df.g,layout = "focus",focus = 1383)+ draw_circle(use = "focus", max.circle = max(distances(df.g,1383)))+ geom_edge_link()+ geom_node_point(shape = 21,fill = "grey25",size = 1)+ theme_graph()+ coord_fixed()

graph_rdata.zip

schochastics commented 4 years ago

preventing node/edge overlap is unfortunately not that easy, especially for such a large graph. You may be better off using a tree layout, since your graph is actually a tree.

ggraph(df.g,"dendrogram",circular=TRUE)+
  geom_edge_elbow0(edge_colour="grey66",edge_width=0.3)+
  geom_node_point(shape = 21,fill = "grey25",size = 1)+
  theme_graph()+
  coord_fixed()

tree

The node in the center is 1383. Advantage is that you do not have any overlapping edges. Disadvantage is that the nodes are no longer on concentric circles.

I have already been playing around with non-equidistant circles and this will probably be implemented in the next version.

tusharmajhi9 commented 4 years ago

Thanks a lot! Really appreciate your quick reply. This is really helpful and solves the purpose. Your package is great!

MaxKerney commented 4 years ago

Hi, I'm having the same issue, though with a much smaller graph (~30 nodes). Do you still have plans to implement a possible solution in the near future, like you mentioned above?

schochastics commented 4 years ago

I am planing to implement some overlap removal algorithm soon(ish). So the feature will hopeful come eventually

MaxKerney commented 4 years ago

It's a bit of a hack, but I've put this function together which does well at preventing node overlaps in my case. I haven't tested how well it scales though. It leverages the ability to supply a custom layout function to ggraph and uses force field simulation to repel the coordinates of overlapping nodes.


repelled_focus_layout <- function(graph, focus, weights = NULL,
                                  draw.circle = FALSE, circle_col = "#08306B",
                                  rep.fact = 20, rep.dist.lmt = 0.4, attr.fact = 0.2,
                                  adj.max = 0.1, adj.lmt = 0.5, iter.max = 10000) {

  # Create initial focus layout
  g <- ggraph::ggraph(graph, layout = "focus", focus = focus, weights = weights) +
    ggplot2::coord_fixed()

  if (draw.circle == TRUE) {

    g <- g + graphlayouts::draw_circle(use = "focus", max.circle = max(igraph::distances(graph, v = focus, weights = NA)), col = circle_col)   # Will automatically determine correct number of circles to draw.

  }  

  # Extract plotting coordinates from plot object
  focus_coords <- g$data[focus, c("x", "y")]   # Separate out coordinates of focus node to ensure that they are not changed. 
  other_coords <- g$data[-focus, c("x", "y")]

  # Modify coordinates so that overlapping nodes are repelled
  repelled_coords <- FField::FFieldPtRep(coords = other_coords,
                                         rep.fact = rep.fact,             # Repulsion force factor. 
                                         rep.dist.lmt = rep.dist.lmt,     # Repulsion distance limit.
                                         attr.fact = attr.fact,           # Attraction force factor.
                                         adj.max = adj.max,               # Maximum position adjustment at each iteration
                                         adj.lmt = adj.lmt,               # Position adjustment limit at which the simulation stops.
                                         iter.max = iter.max)             # The maximum number of iterations beyond which simulation will end and a warning will be reported. 

  # Add coordinates of focus node back in
  repelled_coords <- as.data.frame(miscTools::insertRow(as.matrix(repelled_coords), focus, as.numeric(focus_coords)))   # Using insertRow rather than rbind to ensure coordinates are added back in the right position.
  rownames(repelled_coords) <- 1:nrow(repelled_coords)   # Fix row indexing.

  return(repelled_coords)

}

Then the dataframe output by the function can be supplied as the layout argument in a ggraph call:

focus_repel <- repelled_focus_layout(graph, focus = 1)
ggraph(graph, layout = focus_repel)

Here's the effect:

repelled-focus-layout-final.png

The arguments to the force field function can be played around with on a case-by-case basis to get a good result, though the only argument I had to change from its default value was rep.dist.lmt.

schochastics commented 4 years ago

This looks promising! but there needs to be a constrained on the radius of nodes. They shouldn't be moved from their concentric circle. Still, this is a good start, thanks for that

MaxKerney commented 4 years ago

Thanks! Yes, as I said this was just a bit of a hack to get it working for me. I just thought I'd leave it here in case it's useful for other people coming across this issue in the meantime until a proper solution is developed.

The rep.dist.lmt can be reduced so that there's only a minimal deviation of nodes from their original starting positions on the circles. I just specified a larger value so that I could better see the edges between nodes on the same circle. This is with rep.dist.lmt = 0.2:

repelled-focus-layout-AFTER.png

I suppose the spacing between the circles could also be increased so that the nodes can be repelled slightly away from their circles but it's still clear what distance "band" they are in? In fact, maybe concentric bands could be plotted rather than concentric circles to provide a zone for each set of nodes that they can spread out in so you can better see them and their edges, rather than being on a single line.