net2blend animation update!

I have added a big new feature to net2blend, my addon for exporting networks from R and importing them into blender as 3d objects.

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.

An animated version of a supplementary figure from a recent mouse paper showing how dynamic communities change after a catastrophic turnover event

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

#load requirements
library(igraph)
source("net2blend.R")

#generate a random network of 13 nodes
g1=erdos.renyi.game(13,0.1)
#as this method does not give nodes names, assign them randomly from the alphabet
V(g1)$name=sample(LETTERS,length(V(g1)))
#give all these nodes an attribute that they were present
V(g1)$present=T
#give edges a weight attribute
E(g1)$weight=1

#generate a second network of 26 nodes
g2=erdos.renyi.game(26,0.1)
#as this method does not give nodes names, assign them randomly from the alphabet
V(g2)$name=sample(LETTERS,length(V(g2)))
#give all these nodes an attribute that they were present
V(g2)$present=T
#give edges a weight attribute
E(g2)$weight=1

#find all nodes
allnodes=find_all_nodes(list(g1,g2))

#find all edges
alledges=find_all_edges(list(g1,g2))

#add nodes to g1 with present attribute set to false
g1=add_missing_nodes(g1,allnodes=allnodes,attrlist=list(present=F))

#If we had nodes disappearing in g2, can run the same line
g2=add_missing_nodes(g2,allnodes=allnodes,attrlist=list(present=F))

#add missing edges to g1 and g2 with a weight of 0
g1=add_missing_edges(g1,alledges=alledges,attrlist=list(weight=0))
g2=add_missing_edges(g2,alledges=alledges,attrlist=list(weight=0))

#For convenience (not required though) can also match the order of nodes
g1=permute(g1,match(V(g1)$name,sort(V(g1)$name)))
g2=permute(g1,match(V(g2)$name,sort(V(2)$name)))

#generate edge names for convenience - makes it easier to find the same edges in different graphs
E(g1)$name=get_edge_names(g1)
E(g2)$name=get_edge_names(g2)

#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
l1=as.data.frame(layout_in_circle(g1))
row.names(l1)=V(g2)$name
#add a z coordinate
l1$z=0
#make a copy
l2=l1
#add z components 
l2$z[row.names(l2)%in%V(g1)[present]$name]=-0.5
l2$z[!row.names(l2)%in%V(g1)[present]$name]=0.5

#export g1
net2blend(g1,layout=l1[match(V(g1)$name,row.names(l1)),],
vertex.color="red",
edge.color="black",
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
netname="example1",
netname2=1)

#for this example, edges that are present in g1 will become blue in g2 while edges that are disappearing will become red
edgecol=rep("black",length(E(g2)))
edgecol[E(g2)$weight==0]="red"
edgecol[E(g2)$name%in%E(g1)[weight>0]$name&E(g2)$weight>0]="blue"

#similarly new nodes will be green while old nodes will become blue.
nodecol=rep("green",length(V(g2)))
nodecol[V(g2)$name%in%V(g1)[present]$name]="blue"

#export g2
net2blend(g2,layout=l2[match(V(g2)$name,row.names(l2)),],
vertex.color=nodecol,
edge.color=edgecol,
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
netname="example1",
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!

Long-term overlap of social and genetic structure in free-ranging house mice reveals dynamic seasonal and group size effects

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.

A natural catastrophic turnover event: individual sociality matters despite community resilience in wild house mice

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.

Changes in dynamic communities as detected by the methods of Jonas Liechti

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.

The paper is out now in Proceedings of the Royal Society B

Also check out the work of former Ottawa MSc student, Dr Teri Jones:

I helped out a bit with this paper, contributing code and network diagrams. Very happy to at least try to keep one toe in the world of seabirds! Teri’s paper can be found in Ecology Letters

Social information use and collective foraging in a pursuit diving seabird

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.

Social information use and collective foraging in a pursuit diving seabird is out now in PLOS One

Some updates to net2blend

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.

Dashed edge example

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.

The importance of preferential associations and group cohesion: Constraint or optimality

Another paper from my previous position at Ottawa is now out in Behavioural ecology and sociobiology.

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.

The importance of preferential associations and group cohesion: Constraint or optimality

Plotting networks in Blender

Github link to the R code and Blender addon

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:

If the object used as a node has no material assigned, it uses the colour defined in R

You can also combine 2d edges with 3d node shapes. I rather like this effect:

A chickadee network with my chickadee model as nodes

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:

 

One of Matt Silk’s badger networks with badgers for nodes

I hope others might also find this fun or useful! I have a few ideas about how I’d like to develop this further..

An igraph hack

Github link to these functions

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

source("igraphplot2.R")

And then add the new functions to the igraph namespace

environment(plot.igraph2) <- asNamespace('igraph')
environment(igraph.Arrows2) <- asNamespace('igraph')

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.

For example, arrowheads dependant on edge weight:

plot.igraph2(g2,edge.arrow.size=E(g2)$weight/max(E(g2)$weight)/2,edge.arrow.width=E(g2)$weight/max(E(g2)$weight))

Hopefully people find this useful! Contact me if there are any queries/issues.

Urbanization and the temporal patterns of social networks and group foraging behaviors

 

Though I have left Canada I continue to help write things about chickadees! This new paper out now in Ecology and Evolution quantifies chickadee group foraging behaviours and tests for differences between urban and rural environments. This paper came out of Teri Jones’ PhD work, who is joint first author of this study. Though many metrics seem to no huge difference between habitat types we did find that how the metrics change over time does seem to differ between urban and rural areas.

For one of the metrics, the “clumpiness” of foraging events throughout a day, I delved into non-biology papers in order to find a suitable metric. I eventually decided on using “entropy” as my measure. In the example paper that I cite, this is used as a way of quantifying Netflix  users binge watching habitats. I found it worked well as an intuitive way of quantifying how birds arrive and depart a feeder throughout a day.

Though there is some network analysis involved in this paper, it was a lot of fun to try and approach group foraging behaviours in different ways. Particularly trying to quantify these behaviours at the group rather than at the individual level.

In other news it is mice breeding season here in Switzerland. There are so very very many pups..

 

 

Effects of ambient noise on zebra finch vigilance and foraging efficiency

Approximately 8 years later, I have published the study I carried out during my masters in behavioural ecology and evolution at the University of Exeter Cornwall campus: “Effects of ambient noise on zebra finch vigilance and foraging efficiency“. In it I looked at the effect of ambient noise on zebra finch foraging behaviour. In particular I was interested in how the masking of conspecific signals by this noise might alter foraging efficiency.

It is quite nice to have finally got this work out! Many thanks to Sasha and Caitlin for their patience in my suddenly deciding I wanted to have another go (after a misunderstanding about how resubmitting worked during the first year of my PhD)