Supplementary Material to Gourguet et al. - Participatory qualitative modelling to assess coastal socio-ecological system sustainability
Content of this supplementary material
This Rmarkdown document provides all the supplementary material and the R code behind the results presented in the paper “Participatory qualitative modelling to assess coastal socio-ecological system sustainability …”.
The different sections detail how the results were produced from original graphs obtained during 7 workshops and from an 8th graph that proposes a Synthetic representation of the socio-ecosystem based on other models. All qualitative modelling analyses were performed using the QPress package (Melbourne-Thomas et al., 2012) according to the implementation proposed in Marzloff et al. (2016).
- Melbourne-Thomas, J., Wotherspoon, S., Raymond, B. & Constable, A. Comprehensive evaluation of model uncertainty in qualitative network analyses. Ecol. Monogr. 82, 505–519 (2012).
- Marzloff, M. P. et al. Modelling marine community responses to climate-driven species redistribution to guide monitoring and adaptive ecosystem-based management. Glob. Chang. Biol. 22, 2462–2474 (2016).
Import Packages
## IMPORT PACKAGES ##
library(lattice)
library(grid)
library(XML)
library(igraph)
library(gridExtra)
library(ggplot2)
library(plyr)
library(dplyr)
library(vegan)
library(ggplot2)
library(reshape2)
## Import Core QPress functions
Graph_dir <- "/Users/mpmarzlo/Documents/Collaborations/201703_projetREMAIC/QualModels_final/"
Graph_dir <- "/Users/mpmarzlo/Documents/Collaborations/201703_projetREMAIC/QualModels_Frontiers/"
source(file.path(Graph_dir, 'PlotFunctions.R'), echo = FALSE)
Import Graphs
graph_list <- list.files(Graph_dir, pattern = '2021.dia' )
setwd(Graph_dir)
invisible(list.files(pattern = '2021.dia'))
B1 = model.dia(("B1_english2021.dia"))
B2 = model.dia(("B2_english2021.dia"))
B3 = model.dia(("B3_english2021.dia"))
N1 = model.dia(("N1_english2021.dia"))
N2 = model.dia(("N2_english2021.dia"))
N3 = model.dia(("N3_english2021.dia"))
Re = model.dia(("Researcher_english2021.dia"))
Sy = model.dia(("Synthetic_english2021.dia"))
models_label = list(labelsB1 = levels(B1$From), labelsB2 = levels(B2$From), labelsB3 =levels(B3$From), labelsN1 = levels(N1$From),labelsN2 = levels(N2$From),labelsN3 = levels(N3$From), labelsSy = levels(Sy$From), labelsRe = levels(Re$From))
mod_list <- list('B1' = B1, 'B2' =B2, 'B3' = B3, 'N1'=N1, 'N2'=N2, 'N3'=N3, 'Sy'= Sy,'Re'=Re)
## PLOT MODELS FOR VISUAL CHECK
plot_graph = invisible(lapply(1:length(mod_list), function(x){
g_B1 <- graph_from_data_frame(mod_list[[x]], directed = F)
plot(g_B1,
main = paste('model',names(mod_list[x])) )
} ))
## ADD DENSITY DEPENDENCE TO EACH MODEL NODE
B1 <- enforce.limitation(B1)
B2 <- enforce.limitation(B2)
B3 <- enforce.limitation(B3)
N1 <- enforce.limitation(N1)
N2 <- enforce.limitation(N2)
N3 <- enforce.limitation(N3)
Re <- enforce.limitation(Re)
Sy <- enforce.limitation(Sy)
mod_list <- list('B1' = B1, 'B2' =B2, 'B3' = B3, 'N1'=N1, 'N2'=N2, 'N3'=N3, 'Sy'= Sy,'Re'=Re)
Scenarios
Here we define 6 alternative long-term perturbations scenarios
- Increase in “Lease_area”
- Decrease in “Farming_and_land_uses”
- Increase in “Waste_collection” (alternatively captured as decrease in “Undersized_organic_waste” in certain models)
- Increase in “Shellfish_aqua_management”
- Increase in “Integrated_management”
- Decrease in “Rearing_density”
scenariosList = list(
list("Increase in Lease Area" = c("Lease_area" = +1)),
list("Reduction in Farming and land uses" = c("Farming_and_land_uses" = -1)),
list("Increase in Waste collection" = c("Waste_collection" = +1)),
list("Improved shellfish farming management" = c("Shellfish_aqua_management" = +1)),
list("Improved integrated management" = c("Integrated_management" = +1)),
list("Decrease in Stock density" = c("Rearing_density" = -1))
)
scenarios = list(
"Lease_area" = c("Lease_area" = +1),
"Farming_and_land_uses" = c("Farming_and_land_uses" = -1),
"Waste_collection" = c("Waste_collection" = +1),
"Shellfish_aqua_management" = c("Shellfish_aqua_management" = +1),
"Integrated_management" = c("Integrated_management" = +1),
"Rearing_density" = c("Rearing_density" = -1))
# Model subset per scenarios
scen_mod = do.call('rbind', lapply(models_label, function(lab){
names(scenarios) %in% lab
}) )
row.names(scen_mod) = names(mod_list)
colnames(scen_mod) = names(scenarios)
Output Variables
Variables highlighted in bold below summarises the responses across the 3 main sustainability components of the socio-ecosystem, i.e. ecological, economic and social.
- Ecological components
- Plankton
- Nutrients
- Pollutants and bacteria
- Undersized organic waste
- Economic components
- Production
- Stock density
- Quality
- Economic return
- Social components
- Lease Area
- Patrimonial value
- Social acceptability
output_var <-as.factor(c("Production", "Economic_return", "Pollutants_bacteria", "Social_acceptability", "Undersized_organic_waste", "Plankton", "Recreationnal_fishing", "Commercial_fishing"))
response_var <- as.factor(c("Plankton", "Nutrients", "Pollutants_bacteria","Undersized_organic_waste", "Production", "Rearing_density","Shellfish_quality","Economic_return","Lease_area","Social_acceptability" ))#,"Patrimonial_values"
response_3var <- as.factor(c("Undersized_organic_waste", "Economic_return","Social_acceptability" ))
Explore model structure discrepancies, and produce summary statistics
include_synth <- F
include_research <- F
nb_list_var <- F
## AGGREGATE ALL GRAPH OBJECTS FOR MODEL STRUCTURE COMPARISON
for(i in 1:length(mod_list)){
mod_list[[i]]$Model <- as.factor(names(mod_list)[i])
}
Agg_Model <- do.call('rbind', mod_list)
#summary(Agg_Model)
# Remove synthetic and/or scientists model for plot
if(! include_synth){
Agg_Model <- Agg_Model[Agg_Model$Model!='Sy',]}
if(! include_research){
Agg_Model <- Agg_Model[Agg_Model$Model!='Re',]}
Agg_Model$Model <- factor(Agg_Model$Model)
#summary(Agg_Model)
nb_model = nlevels(Agg_Model$Model)
nb_model
## [1] 6
# Barplot of Frequency of Variables
var_count = as.data.frame(xtabs(~From, data = Agg_Model[Agg_Model[,'From']==Agg_Model[,'To'], ]))
var_count$Freq = as.numeric(var_count$Freq)
var_count = var_count[order(var_count$Freq, decreasing = T),]
var_count$From = factor(var_count$From, levels = as.character(var_count$From))
var_count$Var_Nb = seq(1, nrow(var_count))
var_count$Name = as.factor(c(do.call('rbind', lapply(strsplit(as.character(var_count$From), split='_'),function(x){paste(x, collapse = ' ')}))))
var_count$Name = factor(var_count$Name, levels = as.character(var_count$Name))
var_count$category = c('environmental')
# GREEN for following variables: Nutrients, Plankton, Pollutants_bacteria, Predation, Production, Unanticipated_losses, Undersized_organic_waste, Turbidity, Wild_shellfish
green_var = c('Nutrients', 'Plankton', 'Pollutants_bacteria', 'Predation', 'Production', 'Unanticipated_losses', 'Undersized_organic_waste', 'Turbidity', 'Wild_shellfish')
var_count[var_count$From %in% green_var,'category'] = 'environmental'
# BLUE for following variables: Economic_return, Stock_density, Shellfish_quality, Area_concessions, Certification, Commercial_fishing, Market_price, Recreationnal_fishing, Running_costs
blue_var = c('Economic_return', 'Rearing_density', 'Shellfish_quality', 'Lease_area', 'Certification', 'Market_price', 'Running_costs','General_demand','External_production')
var_count[var_count$From %in% blue_var,'category'] = 'economic'
# RED for following variables: Farming_and_land_uses, Shellfish_aqua_management, Social_acceptability, Integrated_management, Waste_collection, Patrimonial_values
red_var = c( 'Farming_and_land_uses', 'Shellfish_aqua_management', 'Social_acceptability', 'Integrated_management', 'Waste_collection', 'Patrimonial_values','Commercial_fishing','Recreationnal_fishing','Solid_waste')
var_count[var_count$From %in% red_var,'category'] = 'social'
var_count$category = factor(var_count$category, levels = c('social','environmental','economic'))
var_count_mod = as.data.frame(xtabs(~From+Model, data = Agg_Model[Agg_Model[,'From']==Agg_Model[,'To'], ]))
var_count_mod$From = factor(var_count_mod$From, levels = as.character(var_count$From))
var_count_mod = var_count_mod[var_count_mod$Freq!=0,]
var_synth = merge (var_count, var_count_mod, by = 'From')
# Coloured Barplot
var_plot = var_synth[var_synth$Freq.x >1,]
var_plot$Name = factor(var_plot$Name)
levels(var_plot$Name) <- paste(seq(1,nlevels(var_plot$Name)), levels(var_plot$Name))
p <- ggplot(data = var_plot, aes(x = Name, y = Model, fill = Freq.y, col= category ) )+
theme(legend.position="none", axis.text.x=element_text(angle=45,hjust=1)) +
geom_tile(width = .8, height = .4, size = 2)+
scale_fill_gradient(low='darkgrey')+
xlab("Variables")+ylab("Models")+
ggtitle("Variables Inclusion In Stakeholders' Models")
p
p <- ggplot(data = var_plot, aes(x = Model, y = Name, fill = Freq.y, col= category ) )+
theme(legend.position="none") +
geom_tile(width = .8, height = .4, size = 1)+
scale_fill_gradient(low='darkgrey')+
xlab("Models")+ylab("Variables")+
ggtitle("Variables Inclusion In Stakeholders' Models")+
scale_y_discrete(limits = rev(levels(var_plot$Name)))
p0 <- p + theme(
plot.title = element_text(color="black", size=14, face="italic"),
axis.title.x = element_text(color="black", size=14, face="bold"),
axis.title.y = element_text(color="black", size=14, face="bold"),
plot.margin=unit(c(1,1,1,1.5),"cm") )
p0
# Distance between models
dist_mod = t(xtabs(~From+Model, data = Agg_Model[Agg_Model[,'From']==Agg_Model[,'To'], ]))
rownames(dist_mod)
## [1] "B1" "B2" "B3" "N1" "N2" "N3"
dist_mod=(dist(t(xtabs(~From+Model, data = Agg_Model[Agg_Model[,'From']==Agg_Model[,'To'], ])), method = 'binary',diag = T, upper = T))
dist_mod = data.matrix(dist_mod)
dist_mod = melt(dist_mod)
ggplot(data = dist_mod, aes(x = Var1, y = Var2, fill = value ) )+
theme(legend.position="none", axis.text.x=element_text(angle=45,hjust=1)) +
geom_tile(width = .8, height = .4)+
scale_fill_gradient(low='white', high= 'black')
# Other Barplots about Variables Inclusion in Models
p <- ggplot(
data = var_count, aes(x = From, y = Freq ) ) +
theme(axis.text.x=element_text(angle=45,hjust=1)) +
geom_bar (stat= 'identity')+
xlab("Variables")+ylab("Frequency")+
ggtitle("Frequency of Variables Inclusion Across All Models")
p1 <- p + theme(
plot.title = element_text(color="red", size=14, face="italic"),
axis.title.x = element_text(color="blue", size=14, face="bold"),
axis.title.y = element_text(color="#993333", size=14, face="bold"),
plot.margin=unit(c(1,1,1,1.5),"cm") )
p <- ggplot(
data = var_count[var_count$Freq>1,], aes(x = From, y = Freq ) ) +
theme(axis.text.x=element_text(angle=45,hjust=1)) +
geom_bar (stat= 'identity')+
xlab("Variables")+ylab("Frequency")+
ggtitle("Frequency of Variables Inclusion Across All Models")
p2 <- p + theme(
plot.title = element_text(color="red", size=14, face="italic"),
axis.title.x = element_text(color="blue", size=14, face="bold"),
axis.title.y = element_text(color="#993333", size=14, face="bold"),
plot.margin=unit(c(1,1,1,1.5),"cm") )
gridExtra::grid.arrange(p1,p2, nrow = 2)
Explore model structure discrepancies via graph representations
include_research <- F
nb_list_var <- F
## AGGREGATE ALL GRAPH OBJECTS FOR MODEL STRUCTURE COMPARISON
for(i in 1:length(mod_list)){
mod_list[[i]]$Model <- as.factor(names(mod_list)[i])
}
Agg_Model <- do.call('rbind', mod_list)
#summary(Agg_Model)
# Remove scientists model for plot
if(! include_research){
Agg_Model <- Agg_Model[Agg_Model$Model!='Re',]}
Agg_Model$Model <- factor(Agg_Model$Model)
Agg_Model$From <- factor(Agg_Model$From)
Agg_Model$To <- factor(Agg_Model$To)
#summary(Agg_Model)
nb_model = nlevels(Agg_Model$Model)
nb_model
## [1] 7
# Change Variable Names to Numbers For Graphs
Agg_Model$NameFrom <- Agg_Model$From
Agg_Model$NameTo <- Agg_Model$To
levels(Agg_Model$From) <- as.character(seq(1,nlevels(Agg_Model$From)))
levels(Agg_Model$To ) <- as.character(seq(1,nlevels(Agg_Model$To)))
# Remove self limitation
Agg_ModPlot <- Agg_Model[Agg_Model[,'From']!=Agg_Model[,'To'], ]
# Put Model Synthetic First in the list
Agg_ModPlot$Model <- factor(Agg_ModPlot$Model, levels = levels(Agg_ModPlot$Model)[c(7,1:6)] )
nb_model = nlevels(Agg_ModPlot$Model)
# Summarise information per model
nodes = as.data.frame( xtabs( ~ From, data= Agg_ModPlot ))
names(nodes)[2] = "Nb_From"
nodes = cbind(nodes, list('Nb_To' = c(xtabs( ~ To, data= Agg_ModPlot ))) )
nodes = cbind(nodes, list('Model' = rowSums(xtabs( ~ From+Model, data= Agg_ModPlot ))))
nodes = cbind(nodes, matrix(xtabs( ~ From+Model, data= Agg_ModPlot ), ncol= nb_model) )
nodes = cbind(nodes, matrix(xtabs( ~ To + Model, data= Agg_ModPlot), ncol= nb_model))
names(nodes)[5:ncol(nodes)] <- c(paste0("From", 1:nb_model), paste0("To", 1:nb_model))
nodes$Model1 = nodes$From1 > 0 | nodes$To1 > 0
nodes$Model2 = nodes$From2 > 0 | nodes$To2 > 0
nodes$Model3 = nodes$From3 > 0 | nodes$To3 > 0
nodes$Model4 = nodes$From4 > 0 | nodes$To4 > 0
nodes$Model5 = nodes$From5 > 0 | nodes$To5 > 0
nodes$Model6 = nodes$From6 > 0 | nodes$To6 > 0
nodes$Model7 = nodes$From7 > 0 | nodes$To7 > 0
ind_start = 19
if(include_synth){
nodes$Model8 = nodes$From8 > 0 | nodes$To8 > 0
ind_start = 21}
nodes$ModelInclude = apply(nodes[,seq(ind_start,(ind_start+nb_model-1))], 1, FUN = function(x) paste(as.character(1:nb_model)[x], collapse= '_') )
nodes$Nb_Include = rowSums(nodes[,ind_start:(ind_start+nb_model-1)])
nodes$Model_graph = as.numeric(substr(nodes$ModelInclude, start=1, stop=1))
nodes$Model_graph[nodes$Nb_Include == 2] = 8
# RE-order variables in ascending order
row.names(nodes) = levels(Agg_ModPlot$NameFrom)
nodes = nodes[as.character(var_count$From[var_count$Freq >0]),]
nodes$From = 1:nrow(nodes)
#summary(nodes)
# Remove Duplicated Edges and Count Number of Occurrence
interactionCount = as.data.frame(xtabs( ~ From+To+Type, data= Agg_ModPlot ) )
Agg_ModPlot = Agg_ModPlot[! duplicated(Agg_ModPlot[,c('From','To','Type')]), ]
Agg_ModPlot = merge(Agg_ModPlot, interactionCount)
Agg_ModPlot$ModelInclus = factor(Agg_ModPlot$Model, levels= c(levels(Agg_ModPlot$Model),"Pair"))
Agg_ModPlot$ModelInclus[Agg_ModPlot$Freq==2] = "Pair"
Agg_ModPlot$ModelNb = Agg_ModPlot$ModelInclus
levels(Agg_ModPlot$ModelNb) = 1:nlevels(Agg_ModPlot$ModelNb)
#summary(Agg_ModPlot)
# Generate colors based on model
dir_graph= F
g_Agg = graph_from_data_frame(d= Agg_ModPlot, vertices= nodes, directed = dir_graph)
if(include_synth){
colrs = c("gray50", "tomato", "gold","lightblue","darkgreen","blanchedalmond","lawngreen","dodgerblue3","lightgrey")
}else{
colrs = c("gray50", "tomato", "gold","lightblue","blanchedalmond","lawngreen","dodgerblue3","lightgrey")
}
# Set Node Colour based on Model
V(g_Agg)$color <- colrs[V(g_Agg)$Model_graph]
# Set node size based on Nb Of Inclusion
V(g_Agg)$size <- (V(g_Agg)$Nb_Include+10)*1.2
# Set Node Label colour
V(g_Agg)$label.color <- 'black'
# Set edge width based on weight:
if(dir_graph){
E(g_Agg)$width <- E(g_Agg)$Freq/2
E(g_Agg)$arrow.size <- .2
E(g_Agg)$edge.colour <- colrs[E(g_Agg)$ModelNb]
}else{
E(g_Agg)$width <- 1
}
# Plot graphs
# Define legends positions
x_leg = c(-1.7,1,1.4)
y_leg = c(1.5, 1.3)
cex_leg = c(1.2, .5)
nb_list_var = F
set.seed(29)
plot(g_Agg,
vertex.label.cex = 0.8,
edge.width = E(g_Agg)$weight,
edge.arrow.size= .2,
edge.curved=.1,
layout=layout_with_lgl(graph=g_Agg, cellsize = 10e+7),
main = paste('Comparing Model Structures (LGL projections)' ))
levels(Agg_Model$Model)
## [1] "B1" "B2" "B3" "N1" "N2" "N3" "Sy"
legend(x=x_leg[1], y= y_leg[1], levels(Agg_ModPlot$ModelInclus), pch=21,
col="#777777", pt.bg=colrs, pt.cex=2, cex= cex_leg[1], bty="n", ncol=1, title = 'Model')
if(nb_list_var){
legend(x=x_leg[2], y= y_leg[2], paste(1:35,rownames(nodes)[1:35],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
legend(x=x_leg[3], y= y_leg[2], paste(36:nrow(nodes),rownames(nodes)[36:nlevels(Agg_ModPlot$NameFrom)],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
}
plot(g_Agg,
vertex.label.cex = 0.8,
edge.width = E(g_Agg)$weight,
edge.arrow.size= .2,
edge.curved=.1,
layout=layout_with_graphopt,
main = paste('Comparing Model Structures (Graph-opt projection)' ))
legend(x=x_leg[1], y= y_leg[1], levels(Agg_ModPlot$ModelInclus), pch=21,
col="#777777", pt.bg=colrs, pt.cex=4, cex= cex_leg[1], bty="n", ncol=1, title = 'Model')
if(nb_list_var){
legend(x=x_leg[2], y= y_leg[2], paste(1:35,rownames(nodes)[1:35],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
legend(x=x_leg[3], y= y_leg[2], paste(36:nrow(nodes),rownames(nodes)[36:nlevels(Agg_ModPlot$NameFrom)],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
}
plot(g_Agg,
vertex.label.cex = 0.8,
edge.width = E(g_Agg)$weight,
edge.arrow.size= .2,
edge.curved=.1,
layout=layout_nicely,
main = paste('Comparing Model Structures (aesthetic layout)' ))
legend(x=x_leg[1], y= y_leg[1], levels(Agg_ModPlot$ModelInclus), pch=21,
col="#777777", pt.bg=colrs, pt.cex=4, cex= cex_leg[1], bty="n", ncol=1, title = 'Model')
if(nb_list_var){
legend(x=x_leg[2], y= y_leg[2], paste(1:35,rownames(nodes)[1:35],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
legend(x=x_leg[3], y= y_leg[2], paste(36:nrow(nodes),rownames(nodes)[36:nlevels(Agg_ModPlot$NameFrom)],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
}
plot(g_Agg,
vertex.label.cex = 0.8,
edge.width = E(g_Agg)$weight,
edge.arrow.size= .2,
edge.curved=.1,
layout=layout_on_sphere,
main = paste('Comparing Model Structures (sphere layout)' ))
legend(x=x_leg[1], y= y_leg[1], levels(Agg_ModPlot$ModelInclus), pch=21,
col="#777777", pt.bg=colrs, pt.cex=4, cex= cex_leg[1], bty="n", ncol=1, title = 'Model')
if(nb_list_var){
legend(x=x_leg[2], y= y_leg[2], paste(1:35,rownames(nodes)[1:35],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
legend(x=x_leg[3], y= y_leg[2], paste(36:nrow(nodes),rownames(nodes)[36:nlevels(Agg_ModPlot$NameFrom)],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.5, cex= cex_leg[2], bty="n", ncol=1)
}
print( paste(1:nlevels(Agg_ModPlot$NameFrom), levels(Agg_ModPlot$NameFrom)) )
## [1] "1 Catchment_runoff" "2 Certification"
## [3] "3 Economic_return" "4 Farming_and_land_uses"
## [5] "5 Favourable_weather_regime" "6 General_demand"
## [7] "7 Nutrients" "8 Plankton"
## [9] "9 Pollutants_bacteria" "10 Predation"
## [11] "11 Production" "12 Rearing_density"
## [13] "13 Shellfish_aqua_management" "14 Social_acceptability"
## [15] "15 Solid_waste" "16 Turbidity"
## [17] "17 Unanticipated_losses" "18 Undersized_organic_waste"
## [19] "19 Wild_shellfish" "20 Commercial_fishing"
## [21] "21 External_production" "22 Infrastructure_processing"
## [23] "23 Integrated_management" "24 Market_price"
## [25] "25 Patrimonial_values" "26 Recreationnal_fishing"
## [27] "27 Shellfish_quality" "28 Waste_collection"
## [29] "29 Aquaculture_heritage" "30 By_product"
## [31] "31 Lease_area" "32 Local_economy"
## [33] "33 Tourism" "34 Demand_low_quality"
## [35] "35 High_quality_price" "36 Low_quality_price"
## [37] "37 Other_uses" "38 Running_costs"
## [39] "39 Site_suitability" "40 Beach_users_conflicts"
## [41] "41 Boating" "42 Response_to_mortality"
## [43] "43 Stealing" "44 Benthos"
## [45] "45 BOD" "46 Dams"
## [47] "47 DOM" "48 Floods"
## [49] "49 Light" "50 POM"
## [51] "51 Primary_production_monitoring"
plot.new()
if(!nb_list_var){
legend(x=-0.1, y= .9, paste(1:35,rownames(nodes)[1:35],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.9, cex= cex_leg[2], bty="n", ncol=1)
legend(x=.5, y= .9, paste(36:nrow(nodes),rownames(nodes)[36:nlevels(Agg_ModPlot$NameFrom)],sep =' - '), pch=NA,
col="#777777", pt.bg=colrs, pt.cex=.9, cex= cex_leg[2], bty="n", ncol=1)
}
Simulate Long-Term Effects of Alternative Scenarios
Colour scaling in the plots is as follows: - black corresponds to the absence of the response node in a given model; - white corresponds to a null response (no effect of the scenario on response node, which can occur when model does not include input node); - a continuous blue-grey-red colour bar is used to represent negative, ambiguous and positive responses, respectively.
# Generate plots
plot_matrix = lapply(1:length(scenarios), function(i){
selecMod = scen_mod[,names(scenarios[[i]])]
plotResults(mod_list = mod_list[selecMod],
scenario_list = scenariosList[i],
label_list= models_label[selecMod],
output_var = response_var,
label_x = names(mod_list[selecMod]),
Scenario_name = names(scenariosList[[i]]))
})
# Display results
plot_matrix[[1]]
Focus on Synthetic Model Predictions Only
selecMod = 7
plotResults_singModel(model = mod_list[selecMod][[1]],
scenario_list = scenariosList,
label_list= models_label[selecMod],
output_var = response_var,
label_x = c("Lease Area +", "Farming and land uses -", "Waste collection +","Shellfish aqua. mgt. +", "Integrated mgt. +","Stock density -" ), #names(scenarios),
main_title = 'Synthetic Model Predictions')
Focus on Area of Concession Scenario
- Increase in “Lease_area”
invisible(scenarios)
scen_mod_noN3 = scen_mod
scen_mod_noN3['N3',] = FALSE
selecMod = scen_mod_noN3[,names(scenarios[[1]])]
plotResults(mod_list = mod_list[selecMod],
scenario_list = scenariosList[1],
label_list= models_label[selecMod],
output_var = response_3var,
label_x = names(mod_list[selecMod]),
Scenario_name = 'Lease Area Increase')
plotResults(mod_list = mod_list,
scenario_list = scenariosList[1],
label_list= models_label,
output_var = response_3var,
label_x = names(mod_list),
Scenario_name = 'Lease Area Increase')
## Warning in index(names(perturb)): Unknown nodes:Lease_area
## Warning in index(names(perturb)): Unknown nodes:Lease_area
## Warning in index(names(perturb)): Unknown nodes:Lease_area
Focus on Farming and Land Uses Scenario
- Decrease in “Farming_and_land_uses”
selecMod = scen_mod_noN3[,names(scenarios[[2]])]
plotResults(mod_list = mod_list[selecMod],
scenario_list = scenariosList[2],
label_list= models_label[selecMod],
output_var = response_3var,
label_x = names(mod_list[selecMod]),
Scenario_name = 'Farming and Land Uses Reduction')
plotResults(mod_list = mod_list,
scenario_list = scenariosList[2],
label_list= models_label,
output_var = response_3var,
label_x = names(mod_list),
Scenario_name = 'Farming and Land Uses Reduction')
## Warning in index(names(perturb)): Unknown nodes:Farming_and_land_uses
## Warning in index(names(perturb)): Unknown nodes:Farming_and_land_uses
Focus on Waste Reduction Scenario
- Increase in “Waste_collection” or: Decrease in “Undersized_organic_waste”
scenario_waste = list( list('B1' = c("Undersized_organic_waste"=-1)),
list('B2' = c("Waste_collection"= +1)),
list('B3' = c("Waste_collection"= +1)),
list('N2' = c("Waste_collection"= +1)),
list('Sy' = c("Waste_collection"= +1)),
list('Re' = c("Undersized_organic_waste"= -1)))
models_waste = list('B1' = B1, 'B2'= B2, 'B3'=B3,'N2'=N2,'Sy'=Sy,'Re'=Re)
plotResults(mod_list = models_waste, scenario_list = scenario_waste,
label_list= models_label[c(1,2,3,5,7,8)],
output_var = response_3var,
label_x = names(models_waste),
Scenario_name = 'Waste Reduction')
scenario_waste_all = list( list('B1' = c("Undersized_organic_waste"=-1)),
list('B2' = c("Waste_collection"= +1)),
list('B3' = c("Waste_collection"= +1)),
list('N1' = c("Waste_collection"= +1)),
list('N2' = c("Waste_collection"= +1)),
list('N3' = c("Waste_collection"= +1)),
list('Sy' = c("Waste_collection"= +1)),
list('Re' = c("Undersized_organic_waste"= -1)))
plotResults(mod_list = mod_list,
scenario_list = scenario_waste_all,
label_list= models_label,
output_var = response_3var,
label_x = names(mod_list),
Scenario_name = 'Waste Reduction')
## Warning in index(names(perturb)): Unknown nodes:Waste_collection
## Warning in index(names(perturb)): Unknown nodes:Waste_collection
Focus on Shellfish aquaculture management Scenario
- Increase in “Shellfish_aqua_management”
selecMod = scen_mod_noN3[,names(scenarios[[4]])]
plotResults(mod_list = mod_list[selecMod],
scenario_list = scenariosList[4],
label_list= models_label[selecMod],
output_var = response_3var,
label_x = names(mod_list[selecMod]),
Scenario_name = 'Shellfish aquaculture management')
plotResults(mod_list = mod_list,
scenario_list = scenariosList[4],
label_list= models_label,
output_var = response_3var,
label_x = names(mod_list),
Scenario_name = 'Shellfish aquaculture management')
## Warning in index(names(perturb)): Unknown nodes:Shellfish_aqua_management
Focus on Waste Reduction Scenario
- Increase in “Integrated_management”
selecMod = scen_mod_noN3[,names(scenarios[[5]])]
plotResults(mod_list = mod_list[selecMod],
scenario_list = scenariosList[5],
label_list= models_label[selecMod],
output_var = response_3var,
label_x = names(mod_list[selecMod]),
Scenario_name = 'Integrated management')
plotResults(mod_list = mod_list,
scenario_list = scenariosList[5],
label_list= models_label,
output_var = response_3var,
label_x = names(mod_list),
Scenario_name = 'Integrated management')
## Warning in index(names(perturb)): Unknown nodes:Integrated_management
## Warning in index(names(perturb)): Unknown nodes:Integrated_management
## Warning in index(names(perturb)): Unknown nodes:Integrated_management
Focus on Stock Density Reduction Scenario
- Decrease in “Rearing_density”
selecMod = scen_mod_noN3[,names(scenarios[[6]])]
plotResults(mod_list = mod_list[selecMod],
scenario_list = scenariosList[6],
label_list= models_label[selecMod],
output_var = response_3var,
label_x = names(mod_list[selecMod]),
Scenario_name = 'Rearing Density Reduction')
plotResults(mod_list = mod_list,
scenario_list = scenariosList[6],
label_list= models_label,
output_var = response_3var,
label_x = names(mod_list),
Scenario_name = 'Rearing Density Reduction')
## Warning in index(names(perturb)): Unknown nodes:Rearing_density
## Warning in index(names(perturb)): Unknown nodes:Rearing_density
Sensitivity of model results to scenarios and model structures
CAUTION - Performing multivariate analyses on numerical values associated with qualitative modelling requires attention to non-intuitive meaning of numeric outputs (NA, negative and positive or missing value). This is not as simple as treating the matrices as meaningful numeric outcomes of a scenario.
Generate all results
mat_ScenMod = lapply(1:length(scenarios), function(i){
selecMod = scen_mod[,names(scenarios[[i]])]
result = as.matrix(generateResults_singScen(mod_list = mod_list[selecMod],
scenario_list = scenariosList[i],
label_list= models_label[selecMod],
output_var = response_var) )
# FILTER OUT LARGE VALUES (I.E. NO RESPONSE)
result[result>1] = 1+1/60
colnames(result) = paste(names(mod_list[selecMod]),names(scenarios[[i]]), sep = '_')
result
})
mat_ScenMod <- do.call('cbind',mat_ScenMod)
save(mat_ScenMod, file = 'SuppMat_matrixScenarioModels.Rdata')
#print(mat_ScenMod)
print("Values are in [-1, 1] when input and output variables are connnected, =NA when input variables does not impact output variables (which displays in white), = 1+1/60 i.e. 1.016667 when either input or output variables are absent from the model (which displays in black).")
## [1] "Values are in [-1, 1] when input and output variables are connnected, =NA when input variables does not impact output variables (which displays in white), = 1+1/60 i.e. 1.016667 when either input or output variables are absent from the model (which displays in black)."
Multivariate Analysis of Scenario Results
Numerical values are not directly useable in a multivariate analysis so need to be modified.
load(file = 'SuppMat_matrixScenarioModels.Rdata')
#summary(mat_ScenMod)
# PCA To Inspect variability across simulations
pca_matrix <- data.frame(t(mat_ScenMod))
pca_matrix$model = as.factor(substr(rownames(pca_matrix), start = 1, stop = 2) )
pca_matrix$scenario = as.factor(substr(rownames(pca_matrix), start = 4, stop = 40))
#summary(pca_matrix)
# Deal with gaps in matrix (i.e. 1+1/60) by replacing them by mean values for each variable under each scenario
gap_value = 1+1/60
pca_matrix[is.na(pca_matrix)] = 0
pca_matrix[(pca_matrix) == gap_value ] = NA
# Replace missing values by variables mean response for a given scenario
var_mean = aggregate(pca_matrix[,1:length(response_var)], by = list(pca_matrix$scenario), FUN = function(x){mean(x, na.rm = T)})
for(var in 1:11){
pca_matrix[is.na(pca_matrix[,var]),var] <-
var_mean[ pca_matrix[is.na(pca_matrix[,var]),'scenario'], var+1]
}
# Perform PCA
pca_veg <- rda(pca_matrix[,-c((ncol(pca_matrix)-1):ncol(pca_matrix))])
plot(pca_veg,type="text", scaling = 1)
## $species
## PC1 PC2
## Plankton 0.8658424 0.192542950
## Nutrients -0.2880156 0.977455447
## Pollutants_bacteria 0.3414417 0.831395687
## Undersized_organic_waste -0.9979371 -0.311495868
## Production -1.1010014 -0.009636335
## Rearing_density -0.2834886 -0.091683072
## Shellfish_quality 0.3919644 -0.796252428
## Economic_return 0.3622079 -0.708638803
## Lease_area -0.5645641 0.531269474
## Social_acceptability 0.9567860 0.368103470
##
## $sites
## PC1 PC2
## B3_Lease_area -0.86244673 0.17738792
## N1_Lease_area -1.21937330 0.75243392
## N2_Lease_area -0.74350034 -0.22113332
## Sy_Lease_area -0.38491915 -0.13241315
## Re_Lease_area -1.02037232 0.21688394
## B1_Farming_and_land_uses -0.52840444 -0.75494347
## B2_Farming_and_land_uses -0.86030481 -1.04294239
## N2_Farming_and_land_uses 0.52351184 -0.65092036
## N3_Farming_and_land_uses -0.13839490 -0.67888295
## Sy_Farming_and_land_uses -0.04393543 -0.54540070
## Re_Farming_and_land_uses -0.03498854 -0.72959781
## B2_Waste_collection 0.33722482 1.25744122
## B3_Waste_collection -0.47216458 0.87891124
## N2_Waste_collection -0.46953930 0.82104866
## Sy_Waste_collection -0.17791998 0.70242192
## B1_Shellfish_aqua_management 0.74438135 0.39522708
## B2_Shellfish_aqua_management -0.04681466 -0.12675994
## B3_Shellfish_aqua_management -0.27774873 0.10901039
## N1_Shellfish_aqua_management 0.71320129 -0.39698568
## N3_Shellfish_aqua_management 0.01043267 0.11852468
## Sy_Shellfish_aqua_management 0.23620551 0.72335679
## Re_Shellfish_aqua_management -0.71466791 -0.04771455
## B2_Integrated_management -0.26087781 -0.80646915
## N1_Integrated_management 0.77105010 -0.36313426
## N3_Integrated_management 0.26212919 -0.47165852
## Sy_Integrated_management 0.35968759 -0.38824393
## Re_Integrated_management 0.72820917 -0.48526864
## B1_Rearing_density 0.80954914 0.13842373
## B2_Rearing_density 0.72926886 0.84395319
## N1_Rearing_density 0.71118693 -0.42344733
## N2_Rearing_density 0.57133455 0.57763589
## N3_Rearing_density 0.31365051 0.20475212
## Sy_Rearing_density 0.43534945 0.34850348
##
## attr(,"const")
## [1] 3.359213
pca <- prcomp((pca_matrix[,-c((ncol(pca_matrix)-1):ncol(pca_matrix))]))
plot(pca$x[,1:2] )
text(pca$x[,1:2], rownames(pca_matrix) )
#summary(pca)
var_expl <- pca$sd^2
var_expl <- round(var_expl / sum(var_expl)*100 , digits = 1)
## PCA per Model and per Scenario ##
# Prepare data.frame 'dfForPCA' #
dfForPCA <- data.frame(PC1 = pca$x[,1], PC2 = pca$x[,2], Model = pca_matrix$model, Scenario = pca_matrix$scenario)
levels(dfForPCA$Model)
## [1] "B1" "B2" "B3" "N1" "N2" "N3" "Re" "Sy"
## [1] "Farming_and_land_uses" "Integrated_management"
## [3] "Lease_area" "Rearing_density"
## [5] "Shellfish_aqua_management" "Waste_collection"
# Prepare projections of variables onto PC1 and PC2 #
df_vecPCA <- data.frame(x = pca$rotation[,1],
y = pca$rotation[,2])
df_vecPCA$norm <- sqrt(df_vecPCA$x^2 + df_vecPCA$y^2)
#getting the convex hull for a given point set
find_hull <- function(dfForPCA) dfForPCA[chull(dfForPCA$PC1, dfForPCA$PC2), ]
#Adjust Scenario Names
levels(dfForPCA$Scenario)
## [1] "Farming_and_land_uses" "Integrated_management"
## [3] "Lease_area" "Rearing_density"
## [5] "Shellfish_aqua_management" "Waste_collection"
levels(dfForPCA$Scenario) <- c("Decrease in Farming and Land Uses","Increase in Integrated Management","Increase in Lease Area","Decrease in Rearing Density","Increase in Shellfish Aqua. Management","Increase in Waste Collection")
# Basic scatter plot
p <- ggplot(data = dfForPCA, aes(x= PC1, y= PC2, colour = Model, shape= Scenario)) +
geom_point(size=6) +
scale_shape_manual(values=1:nlevels(dfForPCA$Scenario))+
theme(text = element_text(size=15), legend.key.size = unit(1.1,'cm'))+
labs(x = paste('PC 1 (', var_expl[1],'% of total variance)' ),
y = paste('PC 2 (', var_expl[2],'% of total variance)' ))
p
hulls <- ddply(dfForPCA, "Scenario", find_hull)
p <- ggplot(data = dfForPCA, aes(x= PC1, y= PC2, colour = Scenario,fill = Scenario, shape= Model)) +
geom_point(size=6) +
scale_shape_manual(values=1:nlevels(dfForPCA$Model))+
geom_polygon(data= hulls,aes( x=PC1, y=PC2,colour= Scenario, group = Scenario), alpha = .2) +
theme(text = element_text(size=15), legend.key.size = unit(1.1,'cm'))+
labs(x = paste('PC 1 (', var_expl[1],'% of total variance)' ),
y = paste('PC 2 (', var_expl[2],'% of total variance)' ))
p
hulls <- ddply(dfForPCA, "Model", find_hull)
p <- ggplot(data = dfForPCA, aes(x= PC1, y= PC2, colour = Model, fill = Model, shape = Scenario)) +
geom_point(size=6) +
geom_polygon(data= hulls,aes( x=PC1, y=PC2,colour= Model, group = Model), alpha = .2) +
theme(text = element_text(size=15), legend.key.size = unit(1.1,'cm'))+
labs(x = paste('PC 1 (', var_expl[1],'% of total variance)' ),
y = paste('PC 2 (', var_expl[2],'% of total variance)' ))
p
Summary per variables
# Summary across raw numerical predictions
numerical_mat <- data.frame(t(mat_ScenMod))
numerical_mat$model = as.factor(substr(rownames(numerical_mat), start = 1, stop = 2) )
numerical_mat$scenario = as.factor(substr(rownames(numerical_mat), start = 4, stop = 40))
#summary(numerical_mat)
# Deal with gaps in matrix (i.e. 1+1/60) by replacing them by mean values for each variable under each scenario
gap_value = 1+1/60
numerical_mat[is.na(numerical_mat)] = 0
numerical_mat[(numerical_mat) == gap_value ] = NA
apply(numerical_mat,2, function(x){c('Mean' = mean(x, na.rm = T), 'SD' = sd(x, na.rm = T), 'Proportion of occurence' = sum(!is.na(x))/length(x) )} )
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in var(if (is.vector(x) || is.factor(x)) x else as.double(x), na.rm =
## na.rm): NAs introduced by coercion
## Warning in mean.default(x, na.rm = T): argument is not numeric or logical:
## returning NA
## Warning in var(if (is.vector(x) || is.factor(x)) x else as.double(x), na.rm =
## na.rm): NAs introduced by coercion
## Plankton Nutrients Pollutants_bacteria
## Mean NA NA NA
## SD 0.6707240 0.6789458 0.6586542
## Proportion of occurence 0.9090909 0.6666667 0.6666667
## Undersized_organic_waste Production Rearing_density
## Mean NA NA NA
## SD 0.7783254 0.7093752 0.4385780
## Proportion of occurence 0.7575758 0.9090909 0.7878788
## Shellfish_quality Economic_return Lease_area
## Mean NA NA NA
## SD 0.6862848 0.6313439 0.7117441
## Proportion of occurence 0.5757576 0.7878788 0.6363636
## Social_acceptability model scenario
## Mean NA NA NA
## SD 0.7815227 NA NA
## Proportion of occurence 0.7575758 1 1
# Summary across qualitative sign predictions (treated as 'positive / negative / neutral / ambiguous')
model_list2 = as.factor(substr(colnames(mat_ScenMod), start = 1, stop = 2) )
scenario_list2 = as.factor(substr(colnames(mat_ScenMod), start = 4, stop = 40))
mat_RespType = as.data.frame(mat_ScenMod)
mat_RespType[is.na(mat_ScenMod)] = 'Neutral'
mat_RespType[mat_ScenMod> .33] = 'Positive'
mat_RespType[mat_ScenMod< -.33] = 'Negative'
mat_RespType[mat_ScenMod>= -.33 & mat_ScenMod<= .33] = 'Ambiguous'
mat_RespType[mat_ScenMod> 1] = NA
varSensi <- as.data.frame(t(mat_RespType))
varSensi$Model <- as.factor(substr(colnames(mat_ScenMod), start = 1, stop = 2) )
varSensi$Scenario <- as.factor(substr(colnames(mat_ScenMod), start = 4, stop = 40))
#summary(varSensi)
# Compute Simpson index (= 1 if all qualitative predictions are consistent) and proportion of ambiguous predictions for each variable under each scenario across all models. Then compute the mean of both these indices for each variable.
d <- sapply(response_var, function(i){
temp <- as.data.frame(with(varSensi, table(varSensi[,as.character(i)], Scenario)))
var_output = sapply(levels(temp$Scenario), function(scenar){
temp$Var1 <- factor(temp$Var1, levels = c("Negative","Neutral","Positive","Ambiguous"))
temp2 = xtabs(Freq~Var1, data = temp[temp$Scenario == scenar,])
simpson = sum((temp2/sum(temp2))^2)
ambig = temp2["Ambiguous"] / sum(temp2)
(data.frame(Simpson= simpson, Ambig = ambig))
} )
var_output = matrix(apply(var_output,1,function(x) round(mean(as.numeric(x) ), digits= 2)), ncol=2)
var_output
})
rownames(d) = c('Simpson','Ambiguous')
colnames(d) = response_var
d <- as.data.frame(t(d))
d$Variable= response_var
p <- ggplot(data = d, aes(x= Ambiguous, y= Simpson, colour = Variable, shape= Variable)) +
geom_point(size=10) +
scale_shape_manual(values=1:length(response_var))+
theme(text = element_text(size=15), legend.key.size = unit(1.1,'cm'))+
scale_x_continuous(limits = c(0,.4), name = 'Mean proportion of ambiguous predictions' )+
scale_y_continuous(limits = c(.2,1), name = 'Mean Simpson index' )
p
Session info
## R version 4.1.0 (2021-05-18)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Mojave 10.14.6
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] tcltk grid stats graphics grDevices utils datasets
## [8] methods base
##
## other attached packages:
## [1] MASS_7.3-54 tcltk2_1.2-11 RColorBrewer_1.1-2 reshape2_1.4.4
## [5] vegan_2.5-7 permute_0.9-5 dplyr_1.0.6 plyr_1.8.6
## [9] ggplot2_3.3.3 gridExtra_2.3 igraph_1.2.6 XML_3.99-0.6
## [13] lattice_0.20-44
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.1.1 xfun_0.23 purrr_0.3.4 splines_4.1.0
## [5] colorspace_2.0-1 vctrs_0.3.8 generics_0.1.0 htmltools_0.5.1.1
## [9] yaml_2.2.1 mgcv_1.8-36 utf8_1.2.1 rlang_0.4.11
## [13] pillar_1.6.1 glue_1.4.2 withr_2.4.2 lifecycle_1.0.0
## [17] stringr_1.4.0 munsell_0.5.0 gtable_0.3.0 evaluate_0.14
## [21] labeling_0.4.2 knitr_1.33 rmdformats_1.0.2 parallel_4.1.0
## [25] fansi_0.5.0 highr_0.9 Rcpp_1.0.6 scales_1.1.1
## [29] farver_2.1.0 digest_0.6.27 stringi_1.6.2 bookdown_0.22
## [33] tools_4.1.0 magrittr_2.0.1 tibble_3.1.2 cluster_2.1.2
## [37] crayon_1.4.1 pkgconfig_2.0.3 ellipsis_0.3.2 Matrix_1.3-4
## [41] rmarkdown_2.8 R6_2.5.0 nlme_3.1-152 compiler_4.1.0