# Which functions and packages are used in a given R script

Did you ever wrote an R script and then had to use it in a different computer, were all the required packages are not loaded?

Or just wanted to know which functions/packages you used in a given function?

Well this happened to me (both situations). I found a very helpful function to provide information on the functions and packages used in a given R script:

install.packages("NCmisc") library(NCmisc)

list.functions.in.file(filename=path_to_script, alphabetic = TRUE))

And that’s it!

NOTE: It’s better practice to identify the package of the function in use at any given moment (I’m not used to do that, but I should).

For instance, if you want to use the function remove_patch from our package lconnect:

lconnect::remove_patch()

I work in ecology, biogeography, etc… Biotic interactions (interactions between species) and its repercussions on species distributions is my main research interest.

As such, I had, at some point, to download datasets on species interactions. I wanted to be able to produce a uniform (more or less, not as much as I would like) R object whatever the database I used. I created this function to do just that!

It can be used to download from database website or upload csv files into R (depending on the database). It currently uses the following databases:

1. EcoBase – The database for the models using Ecopath with Ecosim. These are really good, have good metadata and spatial information (polygons) (Christensen & Walters, 2004Heymans et al. 2016).
2. Web of Life – To be really honest I don’t know this database all that much. However it also provides information on the dataset location, but it does not provide details on the ecosystem where it occurs (Fortuna et al. 2014). For this database the user has to download the datasets to a folder previously (which should be given in the argument “folder”).
3. Global Web – This database provides details on the ecosystem where the interaction dataset occur, bu no details on spatial location are provided (Thompson et al. 2012). For this database the user has to download the datasets to a folder previously (which should be given in the argument “folder”).
4. Mangal – This database provides lots of information on the biotic interactions datasets (Poisot et al. 2015).

In order to write this function I relied on work previously done by others. Namely the code to download EcoBase interaction datasets was obtained here. In what concerns the mangal database I relied on the work done in the package rmangal.

At the end of this long function you can find a small example of its use.

NOTE: This is important! Be sure to check the results of the function! I’m still working on it, so this is a provisional version. But I think it works pretty good though.

(Somewhere in the future it might be available in my GitHub.)

create.fw.list <- function(db, folder = NULL, type = NULL, ecosyst=FALSE, ref=FALSE, spatial=FALSE, code=FALSE)
{

#### Arguments  ####
#'db' - database - eb (EcoBase), gw (GlobalWeb), wl (Web of Life) and mg (Mangal)
#'folder' - folder in the WD to get the dataset files (db=gw and wl).
#'type' - if db=mg the user should provide the type of interactions to be downloaded
# 'ecosyst' - Getting ecosystem information, only for gw, eb
#'ref' references information
#'spatial' - get spatial info, only for wl, eb and mg

#### Data Sources ####
#Global Web: https://www.globalwebdb.com/
#EcoTroph Example (EcoBase): http://sirs.agrocampus-ouest.fr/EcoTroph/index.php?action=examples
#Script for EcoBase: http://sirs.agrocampus-ouest.fr/EcoBase/#discoverytools
#Mangal: #https://mangal-wg.github.io/rmangal/articles/rmangal.html
#Web of Life: http://www.web-of-life.es/

#### Results  ####
fwlist <- list()

#### Conditions for data entry  ############################################################

#db

if(!db %in% c("eb","wl","gw","mg"))stop("Argument 'db' must take one of the following values:\n
'wl' - Web of Life
'mg' - mangal
'gw' - globalweb
'eb' - ecobase")

#folder
if(!db %in% c("wl","gw") & !is.null(folder)) stop("Argument 'folder'can only be used if 'db'= 'wl' or 'gw'!")

#type

#folder
if(!db %in% c("mg") & !is.null(type)) stop("Argument 'type'can only be used if 'db'= 'mg'!")

#ecosyst

if(!db %in% c("gw", "eb") & ecosyst==TRUE) stop("Argument 'ecosyst'can only be used if 'db'= 'eb' or 'gw'!")

#ref
#all

#spatial
if(!db %in% c("wl", "mg", "eb") & spatial==TRUE) stop("Argument 'spatial'can only be used if 'db'= 'eb', 'mg' 'wl'!")

#code
if(!db %in% c("wl", "mg", "gw") & code==TRUE) stop("Argument 'code'can only be used if 'db'= 'wl', 'mg'', 'gw'!")

############################################################################################
#Updating each dataset database

#GlobalWeb
if (db == "gw"){
message("####################### GLOBALWEB DATABASE #######################\n\n")

message("Fetching info from the provided folder!")
files_gw <- list.files(path = folder, pattern = "WEB")
ngw <- length(files_gw)
message (paste0("There are ", ngw, " food web files in the folder!"))

#And create vector of references
if (ref==TRUE) reflist_gw <- c()

names_gw <- c()#FW names

#getting the files into R
for(i in 1:ngw){

message(paste0("Fetching food web ", i, " in ", ngw, "!"))

dfgw <- dfgw[, colSums( is.na(dfgw) ) <=1]#Remove columns with all NA
#dfgw <- dfgw[colSums( is.na(dfgw) ) <=1,]#Remove rows with no data

#Get the FW name
names_gw[i] <- as.character(dfgw[2,1])

#Get the reference to the vector
if (ref==TRUE) reflist_gw[i] <- as.character(dfgw[1,1])

#to name the columns
names_gw_c <- c()
n1 <- ncol(dfgw)-1
for(j in 1:n1){
names_gw_c[j] <- as.character(dfgw[2,j+1])
}

#to name the rows
names_gw_r <- c()
n2 <- nrow(dfgw)-2
for(j in 1:n2){
names_gw_r[j] <- as.character(dfgw[j+2, 1])
}

dfgw <- dfgw[-c(1,2),-1]

#Remove columns with NA
dfgw[dfgw==""] <- NA
dfgw <- na.omit(dfgw)

if(i==281){names_gw_r <- names_gw_r[-c(36,37)]}#the FW on i=281 has a note at the bottom

#Delete the 'empty names'
names_gw_c <- names_gw_c[names_gw_c!=""]
names_gw_r <- names_gw_r[names_gw_r!=""]

#Same names in rows or columns?
#if(length(unique(names_gw_r)) < length(names_gw_r)) rown[i] <- as.character(i)
#if(length(unique(names_gw_c)) < length(names_gw_c)) coln[i] <- as.character(i)

#For some strange reason some rows and columns have the same name
names_gw_c <- paste0("sp_", as.character(1:length(names_gw_c)), "_",names_gw_c)
names_gw_r <- paste0("sp_", as.character(1:length(names_gw_r)), "_",names_gw_r)

colnames(dfgw) <- names_gw_c
rownames(dfgw) <- names_gw_r

fwlist[[i]] <- dfgw

}

#Name the list
names(fwlist) <- names_gw

if(ref==TRUE){

references <- as.data.frame(matrix(ncol = 4))
names(references) <- c("FW code", "first_author", "year", "full_ref" )

files_gw <- list.files(folder, pattern = "WEB")

message("Fetching references from the dataset files!")

for(w in 1:ngw){

dfgw <- dfgw[, colSums( is.na(dfgw) ) <=1]#Remove columns with all NA

#Get the reference to the vector
full_ref1 <- as.character(dfgw[1,1])
references[w,4] <- full_ref1#full reference
references[w,1] <- files_gw[w]#fw code
references[w,2] <- str_sub(word(full_ref1, start = 1), 1, str_length(word(full_ref1, start = 1))-1)#fisrt author
references[w,3] <- regmatches(x = full_ref1,gregexpr("[0-9]+",text = full_ref1))[[1]][1]#year
#references[w,3] <- gsub('.+\$$([0-9]+)\$$.+?$', '\\1', full_ref1)#year }#end loop to add refs }#end gw refs #ECOSYSTEM if(ecosyst==TRUE){ message("Searching for 'gw_list.csv' file...") if (!file.exists(paste0(folder, "/gw_list.csv"))) stop("\nThe pdf 'gw_list.pdf' has to be previously converted to a csv file...") #I had to conver the gw_list.pdf file to excel (csv), since I could not install tabulizes to extract pdf tables gw_eco <- read.csv(paste0(folder,"/","gw_list.csv"), header = TRUE, sep = ";") # read csv file filn <- paste0("WEB", as.character(gw_eco[,1]), ".csv") gw_eco2 <- gw_eco[,1:3] gw_eco2[,1] <- filn names(gw_eco2)[1] <- "FW" #yes... I do know the following few lines are 'ugly'... filn <- as.data.frame(cbind(filn, filn)) names(filn) <- c("filn1","filn2") #files_gw <- list.files(path = folder, pattern = "WEB") ecosystem <- merge(x=filn, y=gw_eco2, by.x= "filn2", by.y = "FW") ecosystem <- ecosystem[,c(2, 3, 4)] names(ecosystem)[1] <- "Food web" } }#end of gw #Web of Life if (db == "wl"){ message("####################### WEB OF LIFE DATABASE #######################\n\n") files_wl <- list.files(path = folder, pattern = "FW") nwl <- length(files_wl) message (paste0("There are ", nwl, " food web files in the folder!")) #Get refs and metrics table if (file.exists(paste0(folder, "/references.csv"))) { table_wl <- read.csv(paste0(folder, "/references.csv"), header = TRUE) # read csv file } else { stop("There is no 'references.csv' file on the folder, as provided by the website!") } #FW names names_wl <- as.character(table_wl[,8]) #Load files for(i in 1:nwl){ message(paste0("Fetching food web ", i, " in ", nwl, "!")) dfwl <- read.csv(paste0(folder, "/",files_wl[i]), header = TRUE) # read csv file #row.names(dfwl) <- as.character(dfwl[,1]) #dfwl <- dfwl[,-1] dfwl[is.na(dfwl)] <- 0 fwlist[[i]] <- dfwl } names(fwlist) <- names_wl #REFERENCES if(ref==TRUE){ references <- as.data.frame(matrix(ncol = 4)) names(references) <- c("FW code", "first_author", "year", "full_ref" ) message("Fetching references from the 'references.csv' file!") message("Checking the presence of the 'references.csv' file...") if(!file.exists(paste0(folder, "/references.csv"))==TRUE)stop("Can't retrieve reference details... \n File not present!") ref_file <- read.csv(paste0(folder, "/references.csv"), header = TRUE) # read csv file for(w in 1:nwl){ full_ref1 <- as.character(ref_file[w,7]) references[w,4] <- full_ref1#full reference references[w,1] <- as.character(ref_file[w,1])#fw code references[w,2] <- str_sub(word(full_ref1, start = 1), 1, str_length(word(full_ref1, start = 1))-1)#fisrt author references[w,3] <- regmatches(x = full_ref1,gregexpr("[0-9]+",text = full_ref1))[[1]][1]#year #references[w,3] <- gsub('.+\$$([0-9]+)\$$.+?$', '\\1', full_ref1)#year

}#end wl refs

#SPATIAL
if(spatial==TRUE){

message("Fetching the spatial information from the 'references.csv' file!")
message("Checking the presence of the 'references.csv' file...")
if(!file.exists(paste0(folder, "/references.csv"))==TRUE)stop("Can't retrieve spatial info... \n File not present!")

spatial1 <- ref_file[,c(1,9,10)]

}#end of spatial

}#end of wl

#EcoBase
if(db == "eb"){

message("####################### ECOBASE DATABASE #######################\n\n")

message("Fetching info from the EcoBase website!")
suppressWarnings({

#To obtain the list of available models

suppressMessages({
h=basicTextGatherer()
curlPerform(url = 'http://sirs.agrocampus-ouest.fr/EcoBase/php/webser/soap-client_3.php',writefunction=h$update) data1 <- xmlTreeParse(h$value(),useInternalNodes=TRUE)
liste_mod <- ldply(xmlToList(data1),data.frame)#liste_mod contains a list and decription
})

#Select only those allowing dissemination
l2 <- subset(liste_mod, model.dissemination_allow =="true")#only those of which dissemination is allowed
message("Sellected only those to which model dissemination is allowed!")

#Select only those with whole food webs
l3 <- subset(l2, model.whole_food_web =="true")#only those with the full food web
message("Sellected only those to which the whole food web is available!")

#Get model names
model.name <- as.character(l3$model.model_name) input_list <- list() id <- as.numeric(as.character(l3$model.model_number))

#Loop to get input list
for(i in 1:nrow(l3)){

message(paste0("Fetching information on food web ",i, " of ", nrow(l3)))

suppressMessages({
h=basicTextGatherer()
mymodel <- id[i]
curlPerform(url = paste('http://sirs.agrocampus-ouest.fr/EcoBase/php/webser/soap-client.php?no_model=',mymodel,sep=''),writefunction=h$update,verbose=TRUE) data2 <- xmlTreeParse(h$value(),useInternalNodes=TRUE)
input1 <- xpathSApply(data2,'//group',function(x) xmlToList(x))
})

#need do name the columns
names_input <- as.character(input1[1,])
input1 <- as.data.frame(input1)
colnames(input1) <- names_input
input1 <- input1[-1,]
input_list[[i]] <- input1
}#end of loop to get input list

mnames <- names(input_list)

for (i in 1:length(input_list)){

m2 <- input_list[[i]] #get the model

nnodes <- length(m2)
node_names <- names(m2)

int_matrix <- as.data.frame(matrix(ncol=nnodes, nrow=nnodes))

for(j in 1:length(m2)){

node1 <- m2[[j]]
node_id <- as.numeric(node1$group_seq) node_name <- node_names[j] #matrix colnames(int_matrix)[node_id] <- node_name rownames(int_matrix)[node_id] <- node_name diet_node1 <- node1$diet_descr
nr_food_items <- length(diet_node1)

for(a in 1:nr_food_items){
item1 <- diet_node1[[a]]
id_item1 <- as.numeric(item1$prey_seq) proportion_item1 <- as.numeric(item1$proportion)
detritus_item1 <- as.numeric(item1$detritus_fate) #send to matrix int_matrix[id_item1,node_id] <- proportion_item1 } } int_matrix[is.na(int_matrix)] <- 0#replacing NA with 0 fwlist[[i]] <- int_matrix } names(fwlist) <- model.name })#end of outer suppressWarnings #REFERENCES if(ref==TRUE){ references <- as.data.frame(matrix(ncol = 4)) names(references) <- c("FW code", "first_author", "year", "full_ref" ) message("Fetching the references information!") for(w in 1:nrow(l3)){ #Get the reference to the vector full_ref1 <- as.character(l3$model.reference)[w]
references[w,4] <- full_ref1#full reference
references[w,1] <- as.numeric(as.character(l3$model.model_number[w]))#fw code references[w,2] <- as.character(l3$model.author[w])#fisrt author
references[w,3] <- regmatches(x = full_ref1,gregexpr("[0-9]+",text = full_ref1))[[1]][1]#year
#references[w,3] <- gsub('.+\$$([0-9]+)\$$.+?$', '\\1', full_ref1)#year }#end loop to add refs }#end of eb refs #ECOSYSTEM if(ecosyst==TRUE){ ecosystem <- data.frame(l3$model.model_number, l3$model.country, l3$model.ecosystem_type)

names(ecosystem) <- c("Food web", "Location", "Ecosystem")

}#end of eb ecosystem

#SPATIAL
if(spatial==TRUE){

message("Fetching spatial information from the EcoBase website...")

#Get actual polygons

ebd <- EcoBase_shape$Name #Getting the model numbers nmr <- list() for(i in 1:length(ebd)){ nr <- strsplit(as.character(ebd[i]), "--::")[[1]][1] nr <- as.numeric(str_extract_all(nr, "\\d+")[[1]]) nmr[[i]] <- nr } nmr2 <- c()#line rows for each model for(i in 1:length(nmr)){ a <- nmr[[i]] b <- length(a) c1 <- rep(i,b) nmr2 <- c(nmr2, c1) } #In Which row in ecobase geo file is the model? nmr <- unlist(nmr) table1 <- as.data.frame(cbind(nmr2, nmr)) colnames(table1) <- c("row_n","id") #In which row does model.model_number with a given Id occurs? lines_n <- c() for (i in 1:nrow(liste_mod)){ id <- as.numeric(as.character(liste_mod$model.model_number[i]))
lines_n[i] <- as.numeric(table1[table1$id==id,][1]) } ecobase_poly2 <- list() for(i in 1:length(lines_n)){ ecobase_poly2[i] <- st_geometry(EcoBase_shape)[lines_n[i]] #plot(st_geometry(EcoBase_shape)[lines_n[i]], border="green", add=TRUE) } #if no polygon then bounding box #into here ecobase_poly2 for(i in 1:length(ecobase_poly2)){ if(is.na(lines_n[i])){ #create a bounding box geographic thing z1 <- as.numeric(unlist(regmatches(liste_mod$model.geographic_extent[[i]],gregexpr("[[:digit:]]+\\.*[[:digit:]]*",liste_mod$model.geographic_extent[[i]])))) z2 <- c(z1[4], z1[1], z1[2], z1[1], z1[2], z1[3], z1[4], z1[3]) x1 <- as.data.frame(matrix(z2, ncol=2, byrow=TRUE)) x1 <- cbind(x1[2], x1[1])#had to change lat and long... I had this the other way around... p1 <- Polygon(x1) ps1 <- Polygons(list(p1),1) ecobase_poly2[[i]] <- st_as_sf(SpatialPolygons(list(ps1))) } ecobase_poly2[[i]] <- ecobase_poly2[[i]] } #convert all to class sf for(i in 1:length(ecobase_poly2)){ if(!any(class(ecobase_poly2[[i]])=='sf')){ t2 <- ecobase_poly2[[i]] t3 <- st_cast(t2, to="POLYGON") ecobase_poly2[[i]] <- st_as_sf(as(st_zm(st_geometry(t3)), "Spatial")) } else message("Ok!") } #line.Id correspondence table2 <- as.data.frame(cbind(1:length(ecobase_poly2),as.numeric(as.character(liste_mod$model.model_number))))
names(table2) <- c("row","id")

#select the corresponding polygons
id_selected <- as.numeric(as.character(l3$model.model_number)) #Which rows? rows_selected <- c() for(i in 1:length(id_selected)){ rows_selected[i] <- as.numeric(table2[table2["id"]==id_selected[i],][1]) } spatial1 <- ecobase_poly2[rows_selected] }#end of eb spatial }#end of eb #MANGAL if(db == "mg"){ message("####################### MANGAL DATABASE #######################\n\n") message("Fetching datasets from the Mangal website! \n\n Types 'predation' and 'herbivory' by default... \n but run mangal function 'avail_type' to check available types...\n\nThis operation might take a long time!") ntypes <- length(type) net_info <- list() for(i in 1:ntypes){ message(paste0("\n\nFetching information from interactions of the type ","'",type[i], "'!")) fwlist1 <- search_interactions(type = type[i]) %>% get_collection() net_info <- rbind(net_info, fwlist1) fwlist2 <- as.igraph(fwlist1) fwlist <- c(fwlist, fwlist2) #class(fwlist) } #Converting igraph objects to data frame for(i in 1:length(fwlist)){ fw2 <- fwlist[[i]] #convert each igraph to a data frame fw3 <- as_data_frame(fw2, what = "both") id_name <- fw3$vertices[,1:2]

for(j in 1:nrow(id_name)){#clean the names

node_name <- id_name$original_name[j] if (grepl(":", node_name, fixed=TRUE)) { node_name <- tail(strsplit(node_name, ": "))[[1]] id_name[j,2] <- node_name[2] } else id_name[j,2] <- node_name }#end clean names id_edges <- fw3$edges[,1:3]
int_matrix <- as.data.frame(matrix(ncol = nrow(id_name), nrow = nrow(id_name)))
colnames(int_matrix) <- id_name$original_name rownames(int_matrix) <- id_name$original_name

#Fill the matrix
for(a in 1:nrow(id_edges)){
edge1 <- as.numeric(id_edges[a,1:2])
name1 <- id_name[as.character(edge1[1]),][,2]
name2 <- id_name[as.character(edge1[2]),][,2]
int_matrix[name1,name2] <- 1
}

int_matrix[is.na(int_matrix)] <- 0 #convert all NA to zero

fwlist[[i]] <- int_matrix

}#end of loop to convert to a data frame

if(ref==TRUE){
references <- as.data.frame(matrix(ncol = 4))
names(references) <- c("Dataset ID", "first_author", "year", "DOI" )

message("Fetching references!")

for(j in 1:length(net_info)){
dataset_id <- net_info[[j]]$dataset$dataset_id
first_author <- net_info[[j]]$reference$first_author
year_mng <- as.numeric(net_info[[j]]$reference$year)
doi_mng <- net_info[[j]]$reference$doi
references[j,1] <- dataset_id
references[j,2] <- first_author
references[j,3] <- year_mng
references[j,4] <- doi_mng

references <- references[order(references$Dataset ID),] rownames(references) <- 1:nrow(references) } }#End of mg refs if(spatial==TRUE){ spatial1 <- as.data.frame(matrix(ncol = 4)) names(spatial1) <- c("Dataset ID", "first_author", "lat", "long") message("Fetching coordinates!") for(z in 1: length(net_info)){ dataset_id <- net_info[[z]]$dataset$dataset_id lat_mng <- net_info[[z]]$network$geom_lat long_mng <- net_info[[z]]$network$geom_lon first_author <- net_info[[z]]$reference$first_author if(length(unlist(lat_mng))>1){ spatial2 <- as.data.frame(matrix(ncol = 4)) names(spatial2) <- c("Dataset ID", "first_author", "long", "lat" ) for(b in 1:length(unlist(lat_mng))){ spatial2[b,3] <- long_mng[[1]] [b] spatial2[b,4] <- lat_mng [[1]] [b] } spatial2[,1] <- dataset_id spatial2[,2] <- first_author spatial1 <- rbind(spatial1, spatial2) } spatial1[z,1] <- dataset_id spatial1[z,2] <- first_author if(length(unlist(lat_mng))==1) spatial1[z,3] <- lat_mng if(length(unlist(lat_mng))==1) spatial1[z,4] <- long_mng } spatial1 <- spatial1[order(spatial1$Dataset ID),]
rownames(spatial1) <- 1:nrow(spatial1)

}#End of mg spatial

if (exists("references") & exists("spatial1")) (if(nrow(references)!=nrow(spatial1)) message("WARNING: There are more than on FW in some datasets! References and Spatial data frames have different number of rows."))

}#end of mangal

message(paste0("DONE! \n\nOverall the list stores ", length(fwlist), " datasets!"))

master_list <- list()
master_list[["int_matrix"]] <- fwlist

if(ecosyst==TRUE) {
master_list[["ecosystem"]] <- ecosystem
message ("\n Additional element in the results: \n\n The vector with information on the ecosystems.")
}

if(ref==TRUE) {
master_list[["references"]] <- references
message ("Additional element in the results! \nA data frame with information on the references.")
}

if(spatial==TRUE) {
master_list[["spatial_info"]] <- spatial1
message ("\n Additional element in the results: \n\n Spatial information was added.")
}

if(code==TRUE) {
if(db == "gw") master_list[["code"]] <- files_gw
if(db == "wl") master_list[["code"]] <- files_wl
if(db == "mg") master_list[["code"]] <- references[1,]

message ("Added food web code information.")
}

#Return results
if(length(master_list)==1) return(fwlist)
if(length(master_list)!=1) return(master_list)

message("####################### DONE! #######################")

}#END OF FUNCTION create.fw.list

Next a small example of the function, resorting to EcoBase:

#TUTORIAl (example with EcoBase data)

library(RCurl)
library(XML)
library(plyr)
library(stringr)
library(NCmisc)
library(sf)

#ecosystem=TRUE - We require information on the ecosystem
#ref=TRUE - We require information on the references

eb1 <- create.fw.list(db="eb", ecosyst=TRUE, ref=TRUE)

#Getting the list of interaction matrices
eb1$int_matrix #Getting the information on the ecosystem eb1$ecosystem

#Getting the information on the references
eb1$references eb1$int_matrix[[1]]
Phytoplankton Macroalgae Mesozooplankton Inf. zoobenthos Intertidal inv.
Phytoplankton                 0          0             0.8            0.00            0.23
Macroalgae                    0          0             0.0            0.00            0.00
Mesozooplankton               0          0             0.0            0.29            0.36
Inf. zoobenthos               0          0             0.0            0.01            0.00
Intertidal inv.               0          0             0.0            0.00            0.10
Macrozooplankton              0          0             0.0            0.00            0.00
Epi. zoobenthos               0          0             0.0            0.00            0.00
Wild salmon fry               0          0             0.0            0.00            0.00
Hatch. salmon fry             0          0             0.0            0.00            0.00
Herring                       0          0             0.0            0.00            0.00
Small pelagics                0          0             0.0            0.00            0.00
Sea otters                    0          0             0.0            0.00            0.00
Demersal fish                 0          0             0.0            0.00            0.00
Birds                         0          0             0.0            0.00            0.00
Salmon                        0          0             0.0            0.00            0.00
Trans. mammals                0          0             0.0            0.00            0.00
Res. mammals                  0          0             0.0            0.00            0.00
Pinnipeds                     0          0             0.0            0.00            0.00
Detritus                      0          0             0.2            0.70            0.31
Macrozooplankton Epi. zoobenthos Wild salmon fry Hatch. salmon fry
Phytoplankton                 0.25           0.000            0.00              0.00
Macroalgae                    0.00           0.199            0.00              0.00
Mesozooplankton               0.75           0.100            0.75              0.75
Inf. zoobenthos               0.00           0.500            0.00              0.00
Intertidal inv.               0.00           0.000            0.00              0.00
Macrozooplankton              0.00           0.000            0.25              0.25
Epi. zoobenthos               0.00           0.080            0.00              0.00
Wild salmon fry               0.00           0.000            0.00              0.00
Hatch. salmon fry             0.00           0.000            0.00              0.00
Herring                       0.00           0.000            0.00              0.00
Small pelagics                0.00           0.000            0.00              0.00
Sea otters                    0.00           0.000            0.00              0.00
Demersal fish                 0.00           0.000            0.00              0.00
Birds                         0.00           0.000            0.00              0.00
Salmon                        0.00           0.000            0.00              0.00
Trans. mammals                0.00           0.000            0.00              0.00
Res. mammals                  0.00           0.000            0.00              0.00
Pinnipeds                     0.00           0.000            0.00              0.00
Detritus                      0.00           0.121            0.00              0.00
Herring Small pelagics Sea otters Demersal fish Birds Salmon
Phytoplankton         0.0          0.000          0         0.000 0.000   0.00
Macroalgae            0.0          0.000          0         0.000 0.002   0.00
Mesozooplankton       0.6          0.600          0         0.100 0.000   0.00
Inf. zoobenthos       0.0          0.101          1         0.130 0.000   0.00
Intertidal inv.       0.0          0.000          0         0.025 0.216   0.00
Macrozooplankton      0.4          0.299          0         0.265 0.187   0.15
Epi. zoobenthos       0.0          0.000          0         0.030 0.000   0.00
Wild salmon fry       0.0          0.000          0         0.005 0.000   0.00
Hatch. salmon fry     0.0          0.000          0         0.005 0.000   0.00
Herring               0.0          0.000          0         0.080 0.000   0.00
Small pelagics        0.0          0.000          0         0.260 0.459   0.85
Sea otters            0.0          0.000          0         0.000 0.000   0.00
Demersal fish         0.0          0.000          0         0.100 0.136   0.00
Birds                 0.0          0.000          0         0.000 0.000   0.00
Salmon                0.0          0.000          0         0.000 0.000   0.00
Trans. mammals        0.0          0.000          0         0.000 0.000   0.00
Res. mammals          0.0          0.000          0         0.000 0.000   0.00
Pinnipeds             0.0          0.000          0         0.000 0.000   0.00
Detritus              0.0          0.000          0         0.000 0.000   0.00
Trans. mammals Res. mammals Pinnipeds Detritus
Phytoplankton              0.000        0.000     0.000        0
Macroalgae                 0.000        0.000     0.000        0
Mesozooplankton            0.137        0.000     0.000        0
Inf. zoobenthos            0.000        0.000     0.000        0
Intertidal inv.            0.000        0.000     0.070        0
Macrozooplankton           0.459        0.010     0.000        0
Epi. zoobenthos            0.000        0.000     0.000        0
Wild salmon fry            0.000        0.000     0.000        0
Hatch. salmon fry          0.000        0.000     0.000        0
Herring                    0.067        0.296     0.051        0
Small pelagics             0.138        0.487     0.362        0
Sea otters                 0.000        0.001     0.000        0
Demersal fish              0.193        0.150     0.500        0
Birds                      0.000        0.000     0.000        0
Salmon                     0.001        0.056     0.017        0
Trans. mammals             0.000        0.000     0.000        0
Res. mammals               0.001        0.000     0.000        0
Pinnipeds                  0.004        0.000     0.000        0
Detritus                   0.000        0.000     0.000        0



# Just accepted: “Species traits, patch turnover and successional dynamics: When does intermediate disturbance favour metapopulation occupancy?”

Well… and to finish the year the last paper of my PhD was accepted for publication in BMC Ecology. Let’s hope that 2020 is, at least, as productive as 2019!

With this paper we are not trying to rehabilitate the Intermediate Disturbance Hypothesis (IDH), which has received some criticism.  The IDH “…posits that biodiversity should be highest at intermediate time periods after a disturbance, at intermediate frequencies of disturbance, and at intermediate extents of disturbance.

Here we want to address a distinct issue: is individual species persistence in the landscape benefited by some degree of disturbance? If yes, what types of species? And in what types of landscapes?

We resorted to ecological simulation, by using 54 virtual species and determining how these species reacted to different disturbance intensities in landscapes with distinct habitat availability.

Here’s the abstract:

Background: In fragmented landscapes, natural and anthropogenic disturbances coupled with successional processes result in the destruction and creation of habitat patches. Disturbances are expected to reduce metapopulation occupancy for species associated with stable habitats, but they may benefit species adapted to transitory habitats by maintaining a dynamic mosaic of successional stages. However, while early-successional species may be favoured by very frequent disturbances resetting successional dynamics, metapopulation occupancy may be highest at intermediate disturbance levels for species with mid-successional habitat preferences, though this may be conditional on species traits and patch network characteristics. Here we test this ‘intermediate disturbance hypothesis’ applied to metapopulations (MIDH), using stochastic patch occupancy simulation modelling to assess when does intermediate disturbance favour metapopulation occupancy. We focused on 54 virtual species varying in their habitat preferences, dispersal abilities and local extinction and colonization rates. Long-term metapopulation dynamics was estimated in landscapes with different habitat amounts and patch turnover rates (i.e. disturbance frequency).
Results: Equilibrium metapopulation occupancy by late-successional species strongly declined with increasing disturbance frequency, while occupancy by early-successional species increased with disturbance frequency at low disturbance levels and tended to level-off thereafter. Occupancy by mid-successional species tended to increase along with disturbance frequency at low disturbance levels and declining thereafter. Irrespective of habitat preferences, occupancy increased with the amount of habitat, and with species dispersal ability and colonisation efficiency.
Conclusions: Our study suggests that MIDH is verified only for species associated with mid-successional habitats. These species may be particularly sensitive to land use changes causing either increases or decreases in disturbance frequency. This may be the case, for instance, of species associated with traditional agricultural and pastoral mosaic landscapes, where many species disappear either through intensification or abandonment processes that change disturbance frequency.

If you’re a user of the R based package gDefrag then you should update it. Version 0.2 will be available during the following days.

It brings no major features noticeable to the user. The need to develop a new version of the package was caused by changes to other packages, on which gDefrag depends.

# Just out: “Structural simplification compromises the potential of common insectivorous bats to provide biocontrol services against the major olive pest Prays oleae”

Check out our new paper on biocontrol services in olive groves.

Here’s the abstract:

Crop production intensification often leads to the structural simplification of production systems. This structural simplification is expected to have strong impacts on biodiversity and the provisioning of ecosystem services, but information about this topic is scarce. For instance, no information exists for Mediterranean olive (Olea europaea) groves, despite olive farming representing a significant share of the agricultural sector in some European countries. We investigated the impact of in-farm and landscape-level structural simplification on the potential of three common insectivorous bats (i.e., Pipistrellus kuhlii, P. pygmaeus and P. pipistrellus) to provide biocontrol services against one of the most harmful olive pests worldwide, the olive fruit moth Prays oleae. Bats and insect surveys were both carried out in olive groves representing increasing levels of structural simplification and during three sampling seasons (spring, summer and autumn). At grove-level, structural simplification was considered as resulting from reduced planting pattern variability (i.e., tree and row spacing) and tree features (diameter at breast height, height of the trunk and canopy area), while at landscape level was considered as resulting from reduced land-cover types. We found that the Kuhl’s pipistrelle was the most frequently recorded species in all types of olive groves and seasons. Moreover, the activity levels of pipistrelle bats as a whole significantly decreased with the structural simplification of olive groves. The abundance of P. oleae was highest at intermediate levels of structural simplification, irrespective of the season. Forest cover in the surrounding landscape had a significant positive influence on the activity levels of P. kuhlii, and a significant and negative influence on the abundance of P. oleae. Our study demonstrates that structural simplification differentially influences the activity patterns of both insectivorous bats and insect pests within olive groves. Moreover, it suggests that structural simplification may strongly compromise biocontrol services provided by bats on the major olive pest P. oleae.

# Just out: “Prioritizing road defragmentation using graph-based tools”

Check out our new paper on minimizing the impact of roads on carnivores in the Iberian Peninsula here.

A great collaborative work with Fernando Ascensão and Márcia Barbosa.

# Just accepted “Prioritizing road defragmentation using graph-based tools”

The paper I co-authored with Fernando Ascensão and Márcia Barbosa, entitled “Prioritizing road defragmentation using graph-based tools“, was just accepted for publication in Landscape and Urban Planning.

This has been a great collaboration, which already resulted in the publication of one R package (gDefrag) and one other paper!

Here’s the abstract:

# Updating MetaLandSim…

A new development version is know available for the package MetaLandSim (v. 1.0.6). It can be downloaded from GitHub.

The user has to run the following code in order to install the package from GitHub:

library(devtools)
install_github(“FMestre1/MetaLandSim”)

These changes were required because of recent improvements made to the package rgrass7 (which allows to work on GRASS from R). MetaLandSim relies on rgrass7 to properly run the function range_raster.

One of the outputs MetaLandSim provides is a simulation of range expansion by a given species (with a given set of characteristics) in a given landscape (with a given connectivity). This function, range_raster, converts the output of the simulation to rasters.

The final result are these two rasters (bellow), but check out the manual, and this paper describing the package to get further details. Also, if you want to see how these results can be used, and combined with Ecological Niche Models, check out this paper.

I will update MetaLandSim on CRAN briefly.

# Just out: “Bad moon rising? The influence of the lunar cycle on amphibian roadkills”

As a “side-project” I collaborated with people from my previous research group and wrote this paper on the influence on the lunar cycle on amphibian mortality caused by road traffic.

It provides a view on a different, but very relevant, environmental factor, the moon cycle. It might be helpful when designing conservation mesures to mitigate the negative effects of roads on wildlife.

I wish to thank Helena Lopes, Tiago Pinto, Luís Guilherme Sousa, António Mira and Sara Santos for this excellent cooperation.

You can read the full paper here, but here’s the abstract:

Annually, roads, and their associated users, are responsible for millions of roadkills worldwide. Mortality affects multiple taxonomic groups, but amphibians are particularly vulnerable, due to their size and underreporting. In fact, very high mortality frequencies can occur, mostly during short periods of time, when individuals migrate to and from reproduction areas (e.g., ponds). In this study, we assess the influence of the lunar cycle on amphibian roadkills, while accounting for weather conditions. As expected, the main environmental effects explaining roadkill numbers were weather related, with increases in minimum air temperature, average relative air humidity, and cumulative rainfall during the previous 24 h having a positive effect on roadkill numbers for all studied species. However, the lunar cycle also affected roadkills for two of the studied species. Darker nights had higher numbers of roadkills of Pleurodeles waltl, while moonlit nights had higher numbers of Salamandra salamandra. As such, these moon effects are species specific. Animals that are more active in moonlight may be at an advantage if their visual acuity is better than that of their predators. We hypothesize that differences between species in the response to moonlight may be due to differences perceived in predation risk. This information should be considered when designing mitigation measures. Volunteer actions, for instance, can be planned and coordinated keeping in mind the most appropriate weather conditions for the general amphibian community and specific phases of the lunar cycle for particular species.

# I Iberian Meeting on Agroecological Research

Last November took place at Évora University the I Iberian Meeting on Agroecological Research. It was an event for science presentation but also for discussion with those that could benefit from this initiative and research topics (scientists, farmers, managers, policy makers, etc).

If the topic interests you, feel free to download the book of abstracts or check out the related paper about the meeting.