Displaying an updating network graph without reloading wireframe

27 views Asked by At

Problem: Iterating across network display algorithms provides updates to each nodes' XYZ coordinate. Trying to graph this in a smooth way does not seem to be able to avoid the wireframe reloading, leading to a strobing effect. Codebase and video attached.

Description:

Current example is a ring network, meaning an adjacency matrix where each node is connected to the two nodes ahead and behind. Nodes begin in a random XYZ coordinate of consistent radius from (0,0,0), and then undergo the sorting algorithm that updates each nodes' xyz location.

Current best solution:

Using the RGL package, the network_plot3d function is careful to only open one RGL object and to not clear3d the whole graph. Options are to either use [rgl.pop3d(type="shapes") to try to clear the graph without the wireframe reloading, or to use the deprecated rgl.clear() and to suppress the warnings.

Is there a way to smoothly update only the objects on the screen and not the wireframe? is there another package

Attached is code and video.

Video - https://youtu.be/0EAFZiIyRXg

    • Network_Plot3d - trying to update the graph without clearing the whole graph.
    • Sort.surface.sort - the updater.

Network_plot3d<-function(attr, edgelist, layout.par = "layout.par") {
  # This function will use 'plot3d' to display networks.
  # First, it plots the points as spheres. Radius of 
  # spheres can be related to the number of links (hubs are big)
  # The 'natural' sphere size is '3' or 1/20th of the plot.
  # df<-update_vertex_count(df,layout.par) #sets size according to degree distribution
  lines <- layout.par["lines"]
  
  if (rgl.cur() == 0) {
    open3d()  # opens the rgl window the first time.
  } else {
    if (nrow(rgl.ids()) > 0) {
      #print("deleting stuff")
      rgl.clear()
      #print(nrow(rgl.ids(type="shapes")))
      }
  }
  
  plot3d(attr[, 1:3],
         col = attr[, 7],
         type = "s",
         size = attr[, 8],
         xlim = c(-layout.par["xlim"], layout.par["xlim"]),
         ylim = c(-layout.par["ylim"], layout.par["ylim"]),
         zlim = c(-layout.par["zlim"], layout.par["zlim"])
  )
  
  # Now that the points are graphed, we need to get an edgelist
  if (lines == TRUE) {
    edges <- edge_locations(attr, edgelist)
    lines3d(edges)
  }
}



sort.surface.sort <- function(attr,edges,layout.par,mod=0){   #This is the original. All nodes go to the average of their neighbors, 
                                                            #then the nodes blow out from the geometric mean of the network. Result is always a full sphere.
  
  
  
  if (mod==0){mod<-layout.par["iterations"]+1}              #This sets the mods to the layout.par value, if nothing is given. This controls how often in the iterations to graph.
  iterations<-layout.par["iterations"]                      #sets how many times to run the algorithm
  lines<-layout.par["lines"]                                #should it include lines or only nodes in the final graph?
  layout.par["lines"]<-FALSE                                #turns off lines during the intermediate graphs
  nw<-network(edges, directed = layout.par["directed"])     #Uses the provided edgelist, and network package to interpret the edgelist.
  hood_list<-get_neighborhoods(nw)                          #Generates a neighborhood list for all nodes. This happens inside the sort command to allow for network manipulations to exist later - 
  loud <-layout.par["verbose"]                              #turns on or off most print messages.
  #sort will automatically regenerate from a newly provided edgelist. 
  
  attr<-degree_scaler(attr,layout.par)                      #degree_scaler generates a radius number, with major hubs getting close to zero. however, I'm not sure THIS script actually uses this.
  if (loud == 1)                                            # note that TRUE was stored in layout.par["verbose"] as a 1
    (print("first it recenters and normalizes everyone to their proper radius"))
  attr<-recenter(attr)
  attr<-normalize_subjective(attr,target_list=1:nrow(attr),layout.par)
  if (loud == 1) (print("Then it moves everyone to their geometric mean - do in order by hubs?"))
  for (i in 1:iterations){
    if (loud == 1) (print(i))
    attr<-geo_mean(hood_list,attr,batch=TRUE,target_list=1:nrow(attr))
    attr<-recenter(attr)
    attr<-normalize_subjective(attr,target_list=1:nrow(attr),layout.par) 
    if (i%%mod==0){network_plot3d(attr,edges,layout.par)}
  }
  #df<-pendulums(df,layout.par,FALSE)
  layout.par["lines"]<-lines

  pop3d(type="shapes")
  
  #resize(attr,layout.par)
  network_plot3d(attr,edges,layout.par)
  
  return(attr)
}

1

There are 1 answers

0
user2554330 On

To avoid the strobing, use save <- par3d(skipRedraw = TRUE) before any changes, and par3d(save) when they are done. Then the only update will be from the old display to the new one, with nothing drawn in between.