How to reproduce the MaxEnt Response Curves with R
“It always seems impossible until it’s done.”
—Nelson Mandela
Introduction
The default MaxEnt outputs are generally not suite for publications.
However, there is no way to customize these graphics. Fortunately, the
software provides raw data that can be used to reproduce the graphics
using personalized features.The present tutorial presents the codes used
to produce the Figure 4
in Agunbiade, M. B., Madow, J.,
Camara, F., Fotang, C., Tangwa, E., Tédonzong, L. R.
D., Yuh, Y. G., Ogada, D. & Birkhofer, K. (2025). Mapping
suitable habitat for Hooded Vultures in one of the last West African
strongholds for the species, The Gambia. Ostrich. https://doi.org/10.2989/00306525.2025.2474919.
This method was also used in the following articles!
Fotang, C., Bröring, U., Roos, C. R., …, Tédonzong, L. R. D., Willie, J., Angwafo, T. E., Yuh, Y. G., Schierack, P. & Birkhofer, K. (2023). Mapping suitable habitat for Nigeria–Cameroon chimpanzees in Kom-Wum Forest Reserve, North-Western Cameroon. Primates 64, 339–350. https://doi.org/10.1007/s10329-023-01054-z
—
Figure 5
Tédonzong, L. R. D., Willie, J., Makengveu, S. T., Lens, L. and Tagg, N. (2020). Variation in behavioral traits of two frugivorous mammals may lead to differential responses to human disturbance. Ecology and Evolution 10, 3798-3813. https://doi.org/10.1002/ece3.6178
—
Figure 4
Importing packages
Some of these packages were not used in this tutorial.
package_list=c("ade4","adehabitatHR","ggplot2","maptools","readr","reshape2","reshape","spatstat",
"spatialEco","spatstat.utils","raster","ggpubr","gridExtra","cowplot","ggThemeAssist",
"ecospat","shapefiles","png","ggthemes")
ipak <- function(pkg){
new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
if (length(new.pkg))
install.packages(new.pkg, dependencies = TRUE, repos = "http://cran.us.r-project.org")
sapply(pkg, require, character.only = TRUE)
}
ipak(package_list)
## ade4 adehabitatHR ggplot2 maptools readr
## TRUE TRUE TRUE TRUE TRUE
## reshape2 reshape spatstat spatialEco spatstat.utils
## TRUE TRUE TRUE TRUE TRUE
## raster ggpubr gridExtra cowplot ggThemeAssist
## TRUE TRUE TRUE TRUE TRUE
## ecospat shapefiles png ggthemes
## TRUE TRUE TRUE TRUE
Loading dataset
The function lapply is used hare to read many .dat
files
at once and store them in a stack variable that can then be manipulated
to create a dataframe containing all data arranged. The output is a list
of all tables present in the folder.
Maxent_responses_F2 <- list.files(path="D:/Luc/Articles/Mike/Results/MaxentGambiaCrossValidate_New_Road_Livestock/plots",
pattern=".dat$", full.names=TRUE)
Maxent_stack = lapply(Maxent_responses_F2, read.csv)
typeof(Maxent_stack)
## [1] "list"
Data wrangling
Here we extract the different tables in the stack variable to build a
dataframe. It is important here to verify and note the indexes of the
different tables corresponding to each environmental variable.
selection
is to create a vector to subset the rows of the
average file. It comes with 1001 rows while others come with 501 rows.
VariableSelection
is used to discard the repeated
X
and variable
columns. The
for loop
is used here to extract the tables
0 to 9
for each variable and cbind
them to an
empty dataframe with empty columns.At the end, the resulting dataframes
for each variable are rbind
to create a unique dataframe
with all variables.
Var_Num=length(Maxent_responses_F2)/11
Variables_order=seq(1,Var_Num,1)
dim_empty=dim(data.frame(Maxent_stack[[1]]))
mat_empty = matrix(ncol = 0, nrow = dim_empty[1])
df_empty=df=data.frame(mat_empty)
selection=seq(1,1001, by=2)
VariableSelection=c(4,5,7,8,10,11,13,14,16,17,19,20,22,23,25,26,28,29,31,32)
for (i in Variables_order) {
assign(paste0("Var_",i),cbind(data.frame(Maxent_stack[i]),data.frame(Maxent_stack[i+15]),
data.frame(Maxent_stack[i+15*2]),data.frame(Maxent_stack[i+15*3]),
data.frame(Maxent_stack[i+15*4]),data.frame(Maxent_stack[i+15*5]),
data.frame(Maxent_stack[i+15*6]),data.frame(Maxent_stack[i+15*7]),
data.frame(Maxent_stack[i+15*8]),data.frame(Maxent_stack[i+15*9]),
data.frame(Maxent_stack[i+15*10])[selection,])[,-VariableSelection])
}
df_Final=rbind(Var_1,Var_2, Var_3,Var_4, Var_5,Var_6,Var_7,Var_8, Var_9, Var_10,
Var_11,Var_12,Var_13,Var_14,Var_15)
Preparing the dataframe
Here we finalize the data preparation process, by assigning a variable containing the names of the environmental variables, as they should appear on the plot.
# converting the matrix to data
R_colNames = c("Variable0","Avg_X","Var_Y1","Var_Y2","Var_Y3","Var_Y4","Var_Y5","Var_Y6","Var_Y7","Var_Y8","Var_Y9","Var_Y10","Avg_Y")
colnames(df_Final)=R_colNames
unique(df_Final$Variable0) # This is to see the order of variables in the dataframe.
## [1] "bio11" "Bio17"
## [3] "Bio18" "Bio19"
## [5] "cattle_mask" "Elevation"
## [7] "Landuse01 Water" "Landuse02 Trees"
## [9] "landuse04 Flooded vegetation" "Landuse05 Crops"
## [11] "Landuse07 Built Area" "Landuse08 Bare ground"
## [13] "Landuse11 Rangeland" "road_distance"
## [15] "Slope"
Var_list_sorted=c("Mean temp. of coldest quarter","Precipitation of driest quarter",
"Precipitation of warmest quarter","Precipitation of coldest quarter","Density of livestock",
"Elevation","Density of water","Density of trees","Density of flooded vegetation",
"Density of crops","Density of built area","Density of bare ground",
"Density of rangeland", "Distance to road","Slope")
Var_list_num=rep(1:Var_Num,1)
Variables11022_1 = rep(Var_list_sorted, each = 501)
Variables11022_2 = rep(Var_list_num, each = 501)
df_Final$Variable = Variables11022_1
df_Final$Variable1 = Variables11022_2
df_Final$Variable2=paste(df_Final$Variable1,"_",df_Final$Variable)
Head1=head(df_Final)
Variable0 | Avg_X | Var_Y1 | Var_Y2 | Var_Y3 | Var_Y4 | Var_Y5 | Var_Y6 | Var_Y7 | Var_Y8 | Var_Y9 | Var_Y10 | Avg_Y | Variable | Variable1 | Variable2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | bio11 | 23.59500 | 0.6293595 | 0.643364 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter |
3 | bio11 | 23.59992 | 0.6293595 | 0.643364 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter |
5 | bio11 | 23.60484 | 0.6293595 | 0.643364 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter |
7 | bio11 | 23.60976 | 0.6293595 | 0.643364 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter |
9 | bio11 | 23.61468 | 0.6293595 | 0.643364 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter |
11 | bio11 | 23.61960 | 0.6293595 | 0.643364 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter |
Calculating the variables Min_Y
and
Max_Y
Here we create two functions to calculate the variables
Min_Y
and Max_Y
, that will be binded to the
dataframe to build the plot.
Maxent_Var_Resp_All3=df_Final
dimension=dim(Maxent_Var_Resp_All3)
Min_Y=c()
for (i in 1:dimension[1]) {
Min_Y1=min(Maxent_Var_Resp_All3[i,c(3:12)])
Min_Y=c(Min_Y,Min_Y1)
}
Max_Y=c()
for (i in 1:dimension[1]) {
Max_Y1=max(Maxent_Var_Resp_All3[i,c(3:12)])
Max_Y=c(Max_Y,Max_Y1)
}
Maxent_Var_Resp_All3$Max_Y=Max_Y
Maxent_Var_Resp_All3$Min_Y=Min_Y
Head2=rbind(head(Maxent_Var_Resp_All3),tail(Maxent_Var_Resp_All3))
Variable0 | Avg_X | Var_Y1 | Var_Y2 | Var_Y3 | Var_Y4 | Var_Y5 | Var_Y6 | Var_Y7 | Var_Y8 | Var_Y9 | Var_Y10 | Avg_Y | Variable | Variable1 | Variable2 | Max_Y | Min_Y | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | bio11 | 23.59500 | 0.6293595 | 0.6433640 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter | 0.6912590 | 0.5099581 |
3 | bio11 | 23.59992 | 0.6293595 | 0.6433640 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter | 0.6912590 | 0.5099581 |
5 | bio11 | 23.60484 | 0.6293595 | 0.6433640 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter | 0.6912590 | 0.5099581 |
7 | bio11 | 23.60976 | 0.6293595 | 0.6433640 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter | 0.6912590 | 0.5099581 |
9 | bio11 | 23.61468 | 0.6293595 | 0.6433640 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter | 0.6912590 | 0.5099581 |
11 | bio11 | 23.61960 | 0.6293595 | 0.6433640 | 0.6164757 | 0.691259 | 0.6749287 | 0.6899486 | 0.5099581 | 0.6654155 | 0.5956612 | 0.5612458 | 0.6277616 | Mean temp. of coldest quarter | 1 | 1 _ Mean temp. of coldest quarter | 0.6912590 | 0.5099581 |
99116 | Slope | 18.51533 | 0.7838191 | 0.6991724 | 0.7075460 | 0.739804 | 0.7095181 | 0.8184615 | 0.6797429 | 0.7549191 | 0.7330689 | 0.7374325 | 0.7363485 | Slope | 15 | 15 _ Slope | 0.8184615 | 0.6797429 |
99314 | Slope | 18.55618 | 0.7838191 | 0.6991724 | 0.7075460 | 0.739804 | 0.7095181 | 0.8184615 | 0.6797429 | 0.7549191 | 0.7330689 | 0.7374325 | 0.7363485 | Slope | 15 | 15 _ Slope | 0.8184615 | 0.6797429 |
99514 | Slope | 18.59702 | 0.7838191 | 0.6991724 | 0.7075460 | 0.739804 | 0.7095181 | 0.8184615 | 0.6797429 | 0.7549191 | 0.7330689 | 0.7374325 | 0.7363485 | Slope | 15 | 15 _ Slope | 0.8184615 | 0.6797429 |
99714 | Slope | 18.63786 | 0.7838191 | 0.6991724 | 0.7075460 | 0.739804 | 0.7095181 | 0.8184615 | 0.6797429 | 0.7549191 | 0.7330689 | 0.7374325 | 0.7363485 | Slope | 15 | 15 _ Slope | 0.8184615 | 0.6797429 |
99914 | Slope | 18.67871 | 0.7838191 | 0.6991724 | 0.7075460 | 0.739804 | 0.7095181 | 0.8184615 | 0.6797429 | 0.7549191 | 0.7330689 | 0.7374325 | 0.7363485 | Slope | 15 | 15 _ Slope | 0.8184615 | 0.6797429 |
100114 | Slope | 18.71955 | 0.7838191 | 0.6991724 | 0.7075460 | 0.739804 | 0.7095181 | 0.8184615 | 0.6797429 | 0.7549191 | 0.7330689 | 0.7374325 | 0.7363485 | Slope | 15 | 15 _ Slope | 0.8184615 | 0.6797429 |
Subsetting the dataframe
Here the subset is created to select the variables to be displayed.
Creating the plot with ggplot2
In ggplot2
, we will use the function
~factor()
to define the order in which we want the graph to
present the variables.
plot1 = ggplot(data = Maxent_Var_Resp_All1, aes(x=Avg_X, y=Avg_Y)) +
geom_ribbon(aes(ymin = Min_Y, ymax = Max_Y), alpha = 1.0,
fill = "#0000FF", color = "transparent")+
geom_line(linetype = "solid", col = "#DF0020", size = 0.6)+
facet_wrap( ~factor(Variable, levels=c("Density of built area",
"Precipitation of warmest quarter",
"Density of water","Distance to road",
"Elevation","Density of bare ground")),
scales="free",ncol = 3)+
##facet_grid( ~ Variable)+
theme_bw() + scale_colour_tableau()+
theme(axis.text.x = element_text(angle = 0, hjust = 0.5, vjust = 0.5))+
labs(y =" ", x = NULL)+ylim(0,1)+
labs(y = "Logistic output", x = "Variable values")
Response of Hooded Vultures Necrosyrtes monachus to the most important variables for habitat suitability
Exporting the plot
It is possible to export the plot into publication ready format such
as pdf
or eps
, etc. The height and the width
or the resolution of the plot can be specified here.