library(r2d3)
library(bipartite )
library(purrr)
library(dplyr)
library(tidyr)
library(stringr)
library(tibble)
library(RColorBrewer)
library(bipartiteD3)
Bipartite networks describe the interactions between two discrete sets of nodes, for example plants and their pollinators or parasitoids and their hosts. The analysis of bipartite networks within ecology is commonly done with the bipartite package (Dormann et al.) which includes routines for a wide variety of network analyses.
Bipartite networks are often highly complex and visualising their structure is a considerable challenge. It is very common that bipartite networks include so many overlapping interactions that it becomes challenging to interpret. Furthermore there has recently been concerted effort within ecology to compare multiple networks simultaneously across time, space of interaction type.
Recent developments to improve the connections between R code and other coding languages make it possible to smoothly relate the data-analysis power and familiarity of R to languages and packages that are well suited to interactive plots. The D3 (Data-Driven Documents) is a JavaScript library for visualising and interacting with data, that is now supported within RStudio. However, coding in JavaScript is significantly different to R coding and for most ecologists it would not be a worthwhile investment in time to learn how to use an additional language
This package is designed to provide a smooth interface from R and data formats used in the bipartite package to make html widgets containing bipartite graphs that can be explored interactively.
These can either be viewed in RStudio v1.2+ or in a browser. The
r2D3
package also provides the save_d3_png
and
save_d3_html
functions to directly save d3 objects. When
used together gist.github.com and bl.ocks.org together provide a route
to straightforward free public hosting of D3 widgets, which can be
useful for sharing.
testdata <- data.frame(higher = c("bee1","bee1","bee1","bee2","bee1","bee3"),
lower = c("plant1","plant2","plant1","plant2","plant3","plant4"),
webID = c("meadow","meadow","meadow","meadow","meadow","meadow"), freq=c(5,9,1,2,3,7))
bipartite::frame2webs(testdata)-> SmallTestWeb
SmallTestWeb
## $meadow
## higher
## lower bee1 bee2 bee3
## plant1 6 0 0
## plant2 9 2 0
## plant3 3 0 0
## plant4 0 0 7
Doubletestdata <- data.frame(higher = c("bee1","bee1","bee1","bee2","bee1","bee3", "bee1","bee1","bee1","bee2","bee1","bee3"),
lower = c("plant1","plant2","plant1","plant2","plant3","plant4","plant2","plant1","plant2","plant3","plant4", 'plant5'),
webID = c("meadow","meadow","meadow","meadow","meadow","meadow","bog","bog","bog","bog","bog","bog"), freq=c(5,9,1,2,3,7, 2,3,4,7,4,2))
bipartite::frame2webs(Doubletestdata)-> DoubleTestWeb
bipartite_D3(data =DoubleTestWeb, colouroption = 'brewer', filename = 'demo1')
## Warning in bipartite_D3(data = DoubleTestWeb, colouroption = "brewer", filename
## = "demo1"): Making too few facets. Guessing you want 1 row
The core function bipartite_D3() can take in the matrix formats used by bipartite, either as a discrete matrix, a list of matrices or an array, as may be output by frame2webs() or webs2array(). It’s native format however is a data frame where each row is an interaction. The first column details the name of the primary level species, the second column the secondary level species and the third the strength of the link. Additional webs can be added by adding fourth and subsequent columns, each named to indicate the site. Hence:
## Primary Secondary bog meadow
## 1 plant1 bee1 3 6
## 2 plant2 bee1 6 9
## 3 plant3 bee1 0 3
## 4 plant4 bee1 4 0
## 5 plant5 bee1 0 0
## 6 plant1 bee2 0 0
## 7 plant2 bee2 0 2
## 8 plant3 bee2 7 0
## 9 plant4 bee2 0 0
## 10 plant5 bee2 0 0
## 11 plant1 bee3 0 0
## 12 plant2 bee3 0 0
## 13 plant3 bee3 0 0
## 14 plant4 bee3 0 7
## 15 plant5 bee3 2 0
It is worth noting that many options can be set directly using the CSS file, but here is not really the place to describe that.
##Colour
Note that horizontal isn’t yet supported as well as vertical, and labels often overlap when interactions are rare. Generally it is not recommended.
These are inherited directly from the data. If you want to change these it is best to do that upstream of bipartite_d3.
If you have many small interactions, that would otherwise be 0, can extend the number of decimal places shown:
To change other properties of the labels, the easiest way is to
change the CSS file, then set the CSS_Output_Supress
argument to TRUE
. The CSS file controls things like the
size, color and font of the labels. Detailing this is beyond the scope
of this vignette. If you want an easy way experiment with this, you can
open a html document in a browser and use the ‘inspect element’ or
equivalent feature to see how the different elements relate to each
other.
Can supply the order of either sides of the bipartite diagram.
df<-List2DF(SmallTestWeb)
# To sort primary by total size:
df %>%
group_by(Primary) %>%
summarise(Total=sum(meadow))%>%
arrange(Total)-> SortDf
# To sort secondary manually
SortSec <- c('bee2', 'bee3', 'bee1')
bipartite_D3(df, SortPrimary = SortDf$Primary, SortSecondary = SortSec,
filename = 'demo11')
Also included is a function that finds an order that minimises
crossovers, by first dividing the networks by compartments, then sorting
by compartment size, then minimising within-compartment cross-over using
a CCA, similar to that used by the plotweb
function in
bipartite
. These orders can be then passed to
bipartite_D3()
## $PrimaryOrder
## [1] "Cynanchum diemii" "Mutisia decurrens"
## [3] "Berberis darwinii" "Alstroemeria aurea"
## [5] "Calceolaria crenatiflora" "Ribes magellanicum"
## [7] "Rosa eglanteria" "Aristotelia chilensis"
## [9] "Schinus patagonicus"
##
## $SecondaryOrder
## [1] "Formicidae3" "Nitidulidae"
## [3] "Braconidae3" "Torymidae2"
## [5] "Bombus dahlbomii" "Phthiria"
## [7] "Manuelia gayi" "Sapromyza.Minettia"
## [9] "Vespula germanica" "Phthiria1"
## [11] "Sphecidae" "Thomisidae"
## [13] "Ichneumonidae2" "Ruizantheda proxima"
## [15] "Svastrides melanura" "Trichophthalma jaffueli"
## [17] "Syrphus octomaculatus" "Staphilinidae"
## [19] "Corynura prothysteres" "Chalepogenus caeruleus"
## [21] "Trichophthalma amoena" "Allograpta.Toxomerus"
## [23] "Platycheirus1" "Ruizantheda mutabilis"
## [25] "Policana albopilosa" "Braconidae2"
## [27] "Ichneumonidae4"
The sizing and positioning of the various elements is one of the hardest features to balance. Large plots need to have sufficient space, but too much leads to large white gaps. With a more complex plot it is worth playing around with the various parameters. These are:
MainFigSize : The total size of the html canvas or widget that the figure is put in. By default it is 700x700 per facet. Increase this if things look cramped, the sides of the plot are uneven or bars are getting inverted.
IndivFigSize : This controls the size of the area in which the links are plotted. Only really worth changing in most cases if you want to change the ratios in some way
mp: This sets the number of rows and columns to plot the individual facets of multiple graphs. By default it assumes you want just one row.
BarSize: This the thickness of the bars. Defaults to 35
MinWidth: This sets the size to which each segment shrinks too when others are highlighted
Pad: Padding between boxes to make them more readable.
BoxLabPos: This is two numbers for primary and secondary levels that shift the label text. Larger values shift the text away from the graph. By default it takes a guess based on the maximum number of characters.
PercPos: This does the equivalent for the percentages
# With larger datasets the default can look a bit awkward, with overlaps and inversions
data(Safariland, vazquenc, package = 'bipartite')
data2<-bipartite::webs2array(Safariland, vazquenc)
bipartite_D3(data = data2, filename = 'demo12')
## Warning in bipartite_D3(data = data2, filename = "demo12"): Making too few
## facets. Guessing you want 1 row
The scripts above leave behind two JavaScript files, the library
vizjs.js
, and the graph itself which by default is called
JSBP.js
, and a matching style file JSBP.css
.
Most of the time these are no problem, and in fact are actually useful
to be able to inspect and directly edit. However, to keep the CRAN
checks happy, this tidies them up.
## [1] TRUE
## Warning in file.remove("JSBP.js"): cannot remove file 'JSBP.js', reason 'No
## such file or directory'
## [1] FALSE
## Warning in file.remove("JSBP.css"): cannot remove file 'JSBP.css', reason 'No
## such file or directory'
## [1] FALSE