I recently needed some colorful animations of temporal network data. You can see the result here. These film clips show the proximity of children in a French primary school (ages 6–12). Watch out for the clear transitions between lectures and recess or lunch break (e.g. around 3:28 min into the video below).
A legend is as follows:
- The width of the links represents the interaction strength between nodes. Following Takaguchi et al., we assume every interaction event adds a constant to the link, which then decays exponentially (a factor of 0.9 every 20 (real) seconds). If the link weight is under a threshold, the link is considered nonexistent. The width of the nodes is the same as the thickest link attached to them (for aesthetic reasons).
- The radius of the nodes is proportional to the largest weight of any of the node’s links. The reason I do not add weight is that the node sizes would be just too different. (The reason I do not use the area to represent the weight because it would disbalance the thickness of lines and the visual impression of the nodes.)
- The squares are teachers. They are assigned the class they have the most interaction with.
- The blobs mark the classes.
- The clock shows the time.
As a consequence of this procedure, links linger longer than indicated by the data. It is primarily to make the network structures more visible. Still, one could motivate it scientifically—if the link represents an opportunity for social influence, it could last beyond the dissolution of a meeting.
The blobs are constructed from the convex hull of the members of a class. I first smooth the resulting polygon by iterating Chaikin’s corner-cutting smoothing fivefold.
I keep the classes together by assigning an ultra-lightweight dummy link between disconnected nodes. For the other, proper, links I have the same weight for all. One could use the same weights as in the network construction, but it contracts some graphs too much. I use graph-tool‘s sfdp_layout to update the positions (max two iterations per frame to make the animation smooth).
How to frame the output of the graph layout algorithm is another challenge without a perfect solution. If one uses the raw output of sfdp_layout the graph will move across such a vast space that there will be too much white space if the picture covers all of it. On the other hand, if one trivially rescales all output to the unit square at every frame, the image will be very jerky. Essentially, all figures’ position depends on the positions of the extremes. So the fluctuations of a heavy object (the entire graph) will follow the fluctuations of a light one (a node). My solution is to smooth these fluctuations of the extremes by a rolling average of 600 frames and expand the view slightly (7%) compared to the setting without smoothing. The drawback is that sometimes, some nodes will still disappear from view, and the frames themselves will maybe move slightly more than ideal. In short, this is a problem without a perfect solution.
You can find the code here. I tried to comment it as much as possible, but it is a quick and dirty code. Anyway, it does not apply to many other data sets. The class-hyperedges would probably look ugly if they were many more than now (ten). So it is kind of disposable / non-recyclable.
Finally, colors are from Colorogical.