Interactive map with leaflet and R: plotting a large quantity of sites
We will see here how to plot interactively a huuuuuge amount of site on a map with very few lines of code. I am not an expert in GIS, but people have developed nice packages that are doing the job for you. At the end of this tutorial, you will be able to do these maps (and much better ones) by just copy/pasting my code and change the input data.
The map was published here: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8507310/bin/13071_2021_4950_MOESM1_ESM.html
In the paper from Roland Bamou et al. An update on the mosquito fauna and mosquito-borne diseases distribution in Cameroon, 2021, Parasites and vectors.
Let’s go.
You will need to install and load these packages:
-leaflet
-plyr
-reshape2
-RColorBrewer
-stringr
Load data
dat <- read.table("Database_ano.txt", h=T )
head(dat)
## Country GAUL_Admin1 GAUL_Admin2 Lat Long YeStart YeEnd
## 1 Cameroon Adamaoua Djerem 6.500000 12.70000 1998 2007
## 2 Cameroon Adamaoua Djerem 6.509783 12.47790 1998 2007
## 3 Cameroon Adamaoua Djerem 6.569880 12.69280 1998 2007
## 4 Cameroon Adamaoua Djerem 6.751020 13.11061 1998 2007
## 5 Cameroon Adamaoua Djerem 6.366667 12.75000 1998 2007
## 6 Cameroon Adamaoua Djerem 6.550000 12.68333 1998 2007
## An_gambiae_complex An_gambiae_ss SS_M_Form SS_S_Form An_arabiensis An._melas
## 1 1 1 0 0 0 0
## 2 1 1 0 1 1 0
## 3 1 1 0 1 1 0
## 4 1 1 1 1 1 0
## 5 1 1 0 0 0 0
## 6 1 1 0 0 0 0
## An._merus An_bwambae An_funestus_s.l An_funestus_s.s. An_rivulorum An_leesoni
## 1 0 0 1 1 0 0
## 2 0 0 1 1 0 0
## 3 0 0 1 1 0 0
## 4 0 0 1 1 0 0
## 5 0 0 1 1 0 0
## 6 0 0 1 1 0 0
## An_parensis An_vaneedeni An_nili_s.l An_moucheti_s.l An_pharoensis
## 1 0 0 0 0 0
## 2 0 0 0 0 0
## 3 0 0 0 0 0
## 4 0 0 0 0 0
## 5 0 0 0 0 0
## 6 0 0 0 0 0
## An_hancocki An_mascarensis An_marshalli An_squamous An_wellcomei An_rufipes
## 1 0 0 0 0 0 0
## 2 0 0 0 0 0 0
## 3 0 0 0 0 0 0
## 4 0 0 0 0 0 0
## 5 0 0 0 0 0 0
## 6 0 0 0 0 0 0
## An_coustani_s.l An_ziemanni An_paludis Adults_Larvae Sampling_Methods
## 1 0 0 0 Adults PSC
## 2 0 0 0 Adults PSC
## 3 0 0 0 Adults PSC
## 4 0 0 0 Adults PSC
## 5 0 0 0 Adults PSC
## 6 0 0 0 Adults PSC
## Species_Identification
## 1 M_PCR
## 2 M_PCR
## 3 M_PCR
## 4 M_PCR
## 5 M_PCR
## 6 M_PCR
Prepare the data
I melt the data from wide to long data.frame format, discard some species that I don’t want to plot and make some text edit.
data_anopheles <- melt(dat[,-c(8,34,35,36)], c(1:7))
data_anopheles <- na.omit(data_anopheles)
data_anopheles$Lat <- as.numeric(as.character(data_anopheles$Lat))
data_anopheles$Long <- as.numeric(as.character(data_anopheles$Long))
ddply(data_anopheles, .(variable), summarise, N=sum(value) )
## variable N
## 1 An_gambiae_ss 456
## 2 SS_M_Form 137
## 3 SS_S_Form 318
## 4 An_arabiensis 227
## 5 An._melas 11
## 6 An._merus 0
## 7 An_bwambae 0
## 8 An_funestus_s.l 439
## 9 An_funestus_s.s. 232
## 10 An_rivulorum 11
## 11 An_leesoni 13
## 12 An_parensis 0
## 13 An_vaneedeni 0
## 14 An_nili_s.l 141
## 15 An_moucheti_s.l 153
## 16 An_pharoensis 54
## 17 An_hancocki 59
## 18 An_mascarensis 0
## 19 An_marshalli 21
## 20 An_squamous 26
## 21 An_wellcomei 23
## 22 An_rufipes 41
## 23 An_coustani_s.l 132
## 24 An_ziemanni 44
## 25 An_paludis 66
data_anophelesb <- subset(data_anopheles, variable!= "An._merus" & variable!= "An_bwambae" & variable!= "An_parensis"
& variable!= "An_vaneedeni"
& variable!= "An_mascarensis"
& variable!= "An_gambiae_ss")
#ddply(data_anophelesb, .(variable), summarise, N=sum(value) )
#Replace text for a better visual
data_anophelesb$variable <- str_replace(data_anophelesb$variable, "SS_M_Form", "An. gambiae ss M form")
data_anophelesb$variable <- str_replace(data_anophelesb$variable, "SS_S_Form", "An. gambiae ss S form")
data_anophelesb$variable <- str_replace(data_anophelesb$variable, "_", ". ")
data_anophelesb$variable <- str_replace(data_anophelesb$variable, "An.. melas", "An. melas")
data_anophelesb$variable <- str_replace(data_anophelesb$variable, "_s.l", " sl")
data_anophelesb$variable <- str_replace(data_anophelesb$variable, "_s.s.", " ss")
Create your Bounding Box and visualize with a Leaflet interactive map.
GPS coordinates are in Decimal Degrees. If your coordinates are in DMS format (Degrees Minutes Seconds), you can easily convert them via dedicated websites, such as: https://www.latlong.net/lat-long-dms.html (this one display the location on a map).
# Define bounding box with longitude/latitude coordinates
bbox <- list(
p1 = list(long = 8, lat = 1),
p2 = list(long = 17, lat = 14)
)
Is the bounding box ok? Change the GPS coordinate if needed.
Define a clolor palette
I assign a color to each species.
n <- 20
qual_col_pals = brewer.pal.info[brewer.pal.info$category == 'qual',]
col_vector = unlist(mapply(brewer.pal, qual_col_pals$maxcolors, rownames(qual_col_pals)))
pie(rep(1,n), col=sample(col_vector, n))
data_anophelesb$variable <- factor(data_anophelesb$variable)
Col <- colorFactor(palette = col_vector, data_anophelesb$variable)
I now only select sites where a species was observed
data_anophelesb <- subset(data_anophelesb, value==1 )
Plot the map with Leaflet
Define your group factor
Here the grouping factor is the Anopheles species.
groups = as.character(unique(data_anophelesb$variable))
Make the map. The name of the place will appear when you click on a point on the map (popup), sample date will appear when you will place the mouse over the point (label).
map = leaflet() %>%
addTiles() %>%
addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>%
addRectangles(
lng1 = bbox$p1$long, lat1 = bbox$p1$lat,
lng2 = bbox$p2$long, lat2 = bbox$p2$lat,
fillColor = "transparent" ) %>%
fitBounds(
lng1 = bbox$p1$long, lat1 = bbox$p1$lat,
lng2 = bbox$p2$long, lat2 = bbox$p2$lat )
for(g in groups){
d = data_anophelesb[data_anophelesb$variable == g, ]
map = map %>% addCircleMarkers(data = d, ~Long, ~Lat, popup = ~as.character(GAUL_Admin2),color = ~Col(variable), label = ~as.character(paste(d$YeStart,d$YeEnd, sep="-")), radius=5, stroke = FALSE, fillOpacity = 0.9, group = g)
}
Add layer controls and a minimap and display the results:
map %>% addLayersControl(baseGroups = c("OSM (default)", "Toner Lite"), overlayGroups = groups, options = layersControlOptions(collapsed = FALSE)) %>% addMiniMap(tiles = providers$Esri.OceanBasemap, width = 120, height=80)
You can now save a stand alone htlm file from Rstudio with export/Save a web page.
NOTE: The layer controls are not rendering here. But it should appear OK on your computer. Here is the final map: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8507310/bin/13071_2021_4950_MOESM1_ESM.html