Tuesday, February 15, 2022

Visualization: Animating flow along an edge

In a large network, it is a bit of a pain to visualize the flow. Here is an attempt to show the shortest path in a random sparse directed graph. The shortest path is of course a min-cost flow of one unit. I used cytoscape.js [1] to generate the picture.

A colleague asked the question of whether we can introduce some animation for the flows. Here is what I came up with (with the help of  Google and StackOverflow). Warning: the next picture (animated GIF) may take a bit to load and become fluid.


The technique is somewhat interesting: choose a dashed line style and add a line-dash-offset. By varying the offset we can create a "flow". This is done using some Javascript and Cyptoscape's ele.animation(). This technique is sometimes called a marquee style. (There used to be a marquee HTML tag for showing scrolling text, misused by many early websites. This <marquee> tag is now deprecated. [2]).

This is text inside a marquee tag.

Just in case viewers get dizzy, we can turn off the animation in the network.


  1. Cytoscape.js, Graph theory (network) library for visualisation and analysis,  https://js.cytoscape.org/
  2. HTML Marquee Tag, https://www.w3schools.in/html-tutorial/marquee-tag/

Appendix: Javascript Animation in Cytoscape.js

This is the code I used to implement the edge animation.

       const loopAnimation = (ele, i) => {
         const offset = {
           style: {'line-dash-offset': -10 * i }
          const duration = { duration: 1000 };
          return ele.animation(offset, duration).play()
          .then(() => loopAnimation(ele, i + 1));

      var reds = cy.edges().filter(function(ele) { return ele.data('color') == 'red'; });
      reds.forEach((edge) => {
          loopAnimation(edge, 1);        

This is a small piece of code, but there are some things to say about this.
To turn off animation, I just reset the line style to solid. So the animation loop really will continue, but it becomes invisible. A more sophisticated approach would be to stop the animation and start it again when needed.

A second issue is the recursion in function loopAnimation. Assuming this is not optimized away, at some stage we will exhaust the available stack space. We can alleviate this problem a bit by multiplying the duration by 10 and also the offset by 10 (that would keep the visualization the same).  Of course, we could also implement a loop instead of this recursive call. 

No comments:

Post a Comment