My principle investigator Barbara König is retiring this year. For her last “official” day, our group wanted to present her with a gift to commemerate her time here at the University of Zurich. We decided to give her a stylised image of her long term house mouse study that has been running since 2002.
This image is a combination of 3d and handdrawn 2d art. The mice, nestboxes, desk lamp and wall textures were drawn by my girlfriend.
The nest boxes were a little tricky, I actually modeled a 3d version of them to see how they would look from the isometric perspective we had chosen, which my girlfriend then used as a reference when sketching out the hand drawn ones.
These 2d images were then applied to cards in a 3d environment in Blender. I used the mouse drawings as node models when importing a social network into 3d space. A network generated from antennae data from November 2009 to be precise! Handily, once I removed weak edges, this network did not have any edges that would need to pass through the barriers seperating the differnet areas of the barn.
I gave all the modeled geometry some extra black outlines, with a blank page as the main texture. This was mainly done using Blender’s wireframe modifier (although for more complex geometry like the legs of the small table I had to make some custom tweaks)
The result, printed on some glossy photo paper, turned out pretty well! We got all the current team to sign it.
Barbara said she was perhaps the only one who might appreciate this artwork, but hopefully others might enjoy this representation of this study system!
I have just uploaded another major update for net2blend. New features include the ability to animate whether an edge is curved or dashed and importing entire folders of networks.
Interface changes: The import network panel in blender is now located under its own tab instead of being under tools.
You now also have the choice between importing a single network or reading an entire folder. When reading an entire folder, networks are placed at set intervals from each other. This makes creating animations a lot easier. The following animations consist of 20 networks from R, which would be extremely tedious to import one by one.
Dashed edges: the way dashed edges are implemented in blender has been completely redone. You can also now animate the dashes. There are two arguments when exporting the network from R that control this.
edge.dash is the numeric amount an edge is dashed. Larger values lead to more dashes.
edge.isdashed is a boolean as to whether edge should be dashed or not.
By combining these you can animate dashed edges in different ways. Changing edge.dash will lead to the size of dashes changing in scale while changing edge.isdashed will lead to an edge fading from dashed to solid (or vice versa).
Curved edges: Whether an edge is curved or not can also be animated (as in the top example). As with nodes appearing and disappearing this requires a little forethought to make sure an edge is set up in advance as curved, even if it is currently straight. You can use the edge.forcecurved argument to ensure that even a straight edge will be set up correctly in blender.
These updates are now on github. As ever, please let me know if there are any queries and suggestions.
Networks can now be animated! This was something I always hoped to add, and I’m pretty pleased with the result. The way it works is pretty simple. There is now a “frame” option in blender:
When you import a network, it’ll assign keyframes at that frame. These keyframes can of course be shifted around, duplicated etc. in the dope sheet editor. At the moment, colours, sizes and positions of nodes and edges can all be animated. This includes the transition between 2d and 3d for edges too. Node shape unfortunatley cannot be easily animated as this would require morphing between two different 3d objects.
There are a few considerations when animating a network, namely that edges and nodes that you want to animate have to exist at every keyframe, even if they are technically not present in that particular network. An example of this can be seen in the animated example above, with edges and nodes appearing and disappearing. You can see that in the blender screenshot above, the edges that are invisible in the animation are still present. In order to make this easier I have added several R functions to the script file, all designed to help ensure consistency between network. Below is an example of code for generating an animation similar to the one above, demonstrating the use of the utility functions to easily create hidden edges and nodes. This script can also be found on the net2blend github repository.
#This is an example of animating nodes/edges moving, appearing/disappearing and changing colour
#generate a random network of 13 nodes
#as this method does not give nodes names, assign them randomly from the alphabet
#give all these nodes an attribute that they were present
#give edges a weight attribute
#generate a second network of 26 nodes
#as this method does not give nodes names, assign them randomly from the alphabet
#give all these nodes an attribute that they were present
#give edges a weight attribute
#find all nodes
#find all edges
#add nodes to g1 with present attribute set to false
#If we had nodes disappearing in g2, can run the same line
#add missing edges to g1 and g2 with a weight of 0
#For convenience (not required though) can also match the order of nodes
#generate edge names for convenience - makes it easier to find the same edges in different graphs
#generate a layout for both networks to use.
#This will be identical, but we'll add a change in z coordinate in the second frame
#add a z coordinate
#make a copy
#add z components
edge.size=0.025*E(g1)$weight,#edges of weight 0 will be invisible
vertex.size=0.05*V(g1)$present,#non present nodes will be invisible
#for this example, edges that are present in g1 will become blue in g2 while edges that are disappearing will become red
#similarly new nodes will be green while old nodes will become blue.
edge.size=0.025*E(g2)$weight,#edges of weight 0 will be invisible
vertex.size=0.05*V(g2)$present,#non present nodes will be invisible
netname2=2)#note that netname 2 is different
#Go to blender and import the 2 networks on different frames.
If anyone has any questions/issues/suggestions, please let me know!
While my first paper based on the mouse barn system focused around a single event my new paper in Current Zoology looks uses 10 years of data. We used multilayer network techniques to look at how the overlap between social associations and genetic similarity changed over time. Mice tend to live in groups of relatives. There are a number of potential advantages to this such as a general reduction in aggression between individuals and chances to cooperate. However staying in such a group increases the risk of inbreeding and means that if resources such as available mates are limited, you have to compete with relatives. The costs and benefits of associating with relatives can therefore change depending on resource availability. Individuals might also become less picky about associating with relatives in certain circumstances, such as when they need to huddle together to keep warm in the winter.
One of the original ideas in this study was that individuals would find it harder to associate with relatives, even if they want to as the population increased. Over the 10-year study period, population size increased from a yearly average of 97.5 tagged individuals in 2008 to an average of 357.9 tagged individuals. We predicted that sheer population pressure would be forcing individuals to move to other, less genetically similar groups.
To look into this, we built monthly social networks for our 10 years of data. We also built monthly networks of genetic similarity. We then treated these as seperate layers in monthly multilayer networks and looked at the overlap between layers per month. Above you can see an example of two monthly networks, with the thickness of curved edges indicating the strength of social association and the brightness of colour indicating genetic similarity. The straight edges that fade in and out show the genetic similarity of individuals who have a social association strength of zero, meaning they never interacted with each other. From this you can see some clear cases of highly related individuals not interacting with each other, which leads to a decrease in the similarity between social association and genetic similarity in one of our overlap measures.
We found that there was a seasonal change in the similarity between social associations and genetic relatedness. This led to us looking at some seasonal variables that might explain this change: temperature and the level of breeding activity (as measured by the number of pups found in a month). As all these strongly correlate with each other, we can’t really disentangle to what extent behavioural changes due to breeding activity or environmental conditions drive the observed seasonal patterns. In all likelihood it is a mixture of both. Interestingly, our results suggest that instead of becoming less picky and associating with more non-relatives in winter, they seem to spend more of their time in association with relatives.
We found only a weak effect of the increase in overall population size, though as might be expected there was a lower level of overlap between social associations and genetic similarity within larger social groups. This seems to indicate that the changes we see are due to shorter term changes in the benefits of associating with relatives, likely due to breeding activity or need to keep warm in winter, rather than individuals being forced by population pressure to associate with less related individuals (or vice versa). It will probably take experiments in a far more controlled environment than the barn to disentangle what might drive such a change in associations.
The paper is out now in Current Zoology. This will eventually be part of a special issue on multilayer networks, but as of this post is available in non-typeset accepted form.
My first paper using the mouse barn system here in Zurich has been published. In it we describe the changes in social structure in the population after a sudden and unexpected predation event. Namely, somehow some cats got into the barn one weekend.
As might be expected, this caused a large change in the structure of the social network because of individuals disappearing. However the survivors then had to deal with the indirect effects of these changes for some time as individuals altered their social connections after the event. We therefore looked at how individuals altered their network statistics in relation to how much they were affected by the event and how social they had been before the event. We found that how an individual altered their social connections seemed to be affected by their pre-event social preferences.
We expected to find some large changes in community structure, but the changes we did find within survivors’ social groups didn’t appear to be predicted by how much the group had been affected by the event. In this animation, the size of circles indicates what proportion of connections an individual lost during the event, while colour shows the different social gorups.
The event described in this paper was a bit of an unpleasant event for us, causing damage to our study population. Population size bounced back extremely quickly however! It would be interesting to see if the event had any effect on subsequent breeding activity.
After quite a long time, I have published another chapter from my PhD. It’s been an extremely long journey for this particular paper. I didn’t really imagine it ending quite like this when I was first working on this. However, the paper is now out and hopefully people will enjoy reading it.
To summarise, we were interested in whether European shags pay attention to each others dives when deciding when and where to dive themselves. I spent a while on the Scillies recording video footage of large groups of shags,which we referred to as foraging rafts. We then used video tracking to extract their position and detect when they dived:
After this we quantified their positions in the raft, showing that they were quite organised, with individuals generally moving in front and behind each other and in the same direction. After this we wanted some way of statistically testing if the diving behaviour we observed changed depending on whether a bird had detected another diving. To do this we came up with a model based on two different probabilities of diving: a general probability (intrinsic rate) of diving and the probability of a dive if another bird is observed diving (social rate). We then explored the parameters defining what constituted a social dive:
There parameters controlled the size of a visual range of a focal diving individual and how recently in time another bird had to have dived for the diving individual’s dive to be classified as “social”. So in the example above, the other dive circled in red falls in the bird’s visual field and happened recently enough in time to be defined as social.
We then values of these parameters that best fit the real data. If the visual angle was a full 360 degrees, it would be unlikely that birds are actually paying attention to the bird in front of them, and instead simply reacting to the same things going on underwater. Similarly, if we ended up with social dives being able to occur a long time before a focal dive, this would also make it unlikely that our focal bird was actually paying attention to that dive.
The results we found classified dives that happened 2 seconds before a focal individual dive and in front of that individual as “social”. The model results indiccated that when this happened, the focal individuals were twice as likely to dive than if they did not see another bird dive. This seems to suggest that birds might copy each others diving behaviour. There may be a few reasons for this. The first bird might disturb fish, increasing the chances of success for the second bird. Alternatively, while in the Scillies I frequently saw birds foraging alone peering underwater whilst on the surface, suggesting that birds can’t easily see what is going on underwater. Using others as a source of social information could therefore save a shag from making prospecting dives with no clear idea about what is happening underwater.
While it has been quite a while since I worked on European shags now, I still think there are a number of interesting questions that can be asked about this flocking and diving behaviour! Perhaps this paper might get others interested in those questions.
I’ve added a few additional features to net2blend. The new version can be found over on github.
The biggest new feature is the ability of have dashed edges. You can give a value to edge.dash and Blender will take care of the rest. A larger value results in more dashes. Currently these edges will only show up as dashed in the cycles render.
Another feature is the ability to better control curved edges. Previously two networks with differing numbers of edges but otherwise the same layout could end up with different curves. Now you can calculate the maximum edge length of one network using a provided function and then force the other network to utilise the same value. This results in the curves being identical in both networks.
2d edges will now distribute themselves a little differently to avoid clipping 2d nodes. 2d edges will also alter their height a little so that the last edges in the network are plotted on top, as with igraph. 2d square nodes will also be a bit bigger by default so the size argument better matches with circular nodes.
Finally, collections created in blender will be named based on the provided file for greater convenience.
Once again, I hope people find this useful! Please let me know if there are any issues or if you have ideas for further features.
We were interested in how much we could infer about the benefits of chickadee flocking behaviour by looking at how network structure changed depending on the distribution of resources. The theory being that not all individuals in a group will receive equal benefits from being in that group. Subordinates in particular can suffer fitness consequences by associating with dominant individuals, who will often physically attack them and monopolise food and cover. As such, individuals in the group need to compromise between associating with preferred individuals and following group consensus:
An individual who is only in a group because there is a lack of resources or that is the only way they can access a territory might prefer to associate more loosely with the group where possible. Alternatively, an individual gaining a lot of benefits from being in a group might compromise more, placing a higher priority on retaining general cohesion than following their preferential associations.
Depending on an individual’s for being in a group and the costs of losing contact with the group (such as missed foraging opportunities or increased predation risk) we predicted that network structure would change with resource distribution as it became easier or harder for individuals to exhibit social preferences and still maintain contact with the group.
This was the experiment that led to me spending a lot of time in snowy Canadian forests at night, moving feeders about in darkness so the chickadees could not see where they’d gone.
Graph from XKCD
To summarise our findings from analysing the networks measured at the different resource distributions:
A trade-off between preferential associations and general group cohesion appears to exist within chickadee groups BUT while individuals can be more selective the high degree of correlation between association matrices, lack of change in the number of detected clusters and consistency of individual positions suggest that individuals retain a similar level of cohesiveness no matter the distribution of resources, meaning that even when alternative resources are in proximity, individuals prefer to remain in contact with the group.
This may be due to the benefits of grouping, perhaps it is advantageous to associate with dominant individuals regardless of cost, due to the advantage these individuals might bring due to experience, or perhaps it is better to consider the costs of not grouping. Depending on the costs of being isolated from a group joining a group can still be considered the optimal decision even if benefits are unequally distributed.
This paper wouldn’t have been possible without Nicolas (pictured above one very below freezing dark night) who helped with a lot of chickadee capture and many dark treks through the forest.
What does one do on a rainy weekend in Switzerland? Apparently decide it would be fun to be able to convert networks to Blender objects.
I have written code that will take an igraph object, layout and some plotting properties and export files from R, which can then be read in the free 3d modelling software Blender.
The function in R is set up very similarly to igraph.plot. You are able to customise layout, colours, edge sizes, vertex sizes etc. The function will then export two files, one for edge and one for vertexes. These can then simply be read in using the dialogue the Blender addon adds:
The code fully supports arrows and curved edges too. You can even create a purely 2d network if you want, with 2d edges, though of course it actually exists in 3d space.
The code allows you to simply use spheres, cubes, circle and squares node shapes. However it can also use any existing object in a blender scene as a node shape. Here is a network using the Blender monkey head primitive as a node shape in a network with a 3d layout:
You can also combine 2d edges with 3d node shapes. I rather like this effect:
Additionally plotting networks in blender makes it very easy to use any sort of picture as a node. Here is an example using a 2d picture as a node:
I hope others might also find this fun or useful! I have a few ideas about how I’d like to develop this further..
So by default, the igraph R package does not allow you to set a per edge arrow size when plotting networks. For as long as I have been using it, the help page has read:
Currently this is a constant, so it is the same for every edge. If a vector is submitted then only the first element is used, ie. if this is taken from an edge attribute then only the attribute of the first edge is used for all arrows. This will likely change in the future.
This can be a little frustrating if you want fine scale control over how your plots look. For example, here is what the default arrow size looks like on a directional weighted network plotted in igraph:
If you want to alter the arrow head size, you have to do it for all edges, which can sometimes look wrong when you are weighting the edges by associatin strength:
I have therefore made some alterations to the plot.igraph code, creating a modified function called plot.igraph2. This modified version of the code allows you to set multiple values for both the edge.arrow.width and edge.arrow.size parameters when plotting networks.
For example, per edge arrow.width
Per edge arrow.size:
And finally both:
The function should also be able to deal with vectors for these parameters that are shorter than the number of edges, though I haven’t tested this quite so robustly.
As of yet I have not modified the code for plotting the other types of arrow available (arrowhead on opposite end, arrowhead on both ends). I can do this if there is interest!
To use this code, simply download the source from my github.
Then read it into R
And then add the new functions to the igraph namespace
You can now use the function plot.igraph2 in the same way as you would normally use plot.igraph (which is the function used when using plot() on an igraph graph object) with the added benefit of being able to set arrowhead size on a per edge basis.