Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping using ggmap & Stamen maps in R: labelling points and scale

I'm trying to make a map of my study site using ggmap & Stamen maps. I've seen a few similar questions but haven't figured out a way to incorporate the solution into my Stamen map code.

I have two questions regarding this: 1. How can I custom label the points on the map? 2. How can I add a scale to maps in Stamen map? (either as a line indicating distance or something like x cm on map = y km in real life)

Tcoords <- read.csv("Tcoords.csv")

My file looks like this

# trap latitude longitude
1 52.34431 0.5374620
2 52.34281 0.5382080
3 52.34468 0.5406787
4 52.34357 0.5398280
5 52.34431 0.5397050
6 52.34516 0.5406294

In response to the suggestion, I've pasted the results to dput(head(Tcoords)) here:

 structure(list(trap = c("1", "2", "3", "4", "5", "6"), latitude = c(52.344312, 
52.342809, 52.3446849, 52.343572, 52.34431, 52.3451601), longitude = c(0.537462, 
0.538208, 0.5406787, 0.539828, 0.539705, 0.5406294)), row.names = c(NA, 
6L), class = "data.frame")

This the code I'm using to plot my points

center = c(lon = 0.5406294, lat = 52.3451601)
qmap(center, zoom = 16, source = "stamen", maptype = "watercolor")+ 
      geom_point(aes(x = longitude, y = latitude), size = 4, shape = 21, 
                 fill = "dark green", data = Tcoords)

But somehow trap isn't being recognised as an object. It's probably something elementary but I'm not really sure what I've missed (new to R). I've saved "trap" as a text object here.

Thanks for your help!

like image 606
kittenbuns Avatar asked Oct 31 '25 15:10

kittenbuns


2 Answers

I would like to suggest tmap as an alternative to ggmap. This is one of many others possible packages for creating maps CRAN Task View: Spatial but I found the scale bar that tmap generates pretty nice and the code simple.

The code to generate the final plot requires the following packages

# To create the map
library(tmap)
# To create the layer with the points given in Tcoords.csv
library(sf)
# To read the background map
library(tmaptools)
library(OpenStreetMap)

Then, we read the coordinates of the six points to be mapped and turn them into an sf object

# Read coordinates
Tcoords = dget("Tcoords.R")

# create an sf object for the six points in the file
coordinates = matrix(c(Tcoords$longitude, Tcoords$latitude), 6, 2)
tcoords_sfc = lapply(1:6, function(k) st_point(coordinates[k, ])) %>%
  st_sfc(crs = 4326)
tcoords_sf = st_sf(trap = Tcoords$trap, geometry = tcoords_sfc)

Next, we find the limits of the six points (bounding box) and extend them by a factor 2.5. You can play with this factor to get maps with other scales.

bb_new = bb(tcoords_sf, ext = 2.5)

Finally we read the background map

map_osm = read_osm(bb_new, zoom = 15, type = "stamen-watercolor")

and draw the final map

Map with scale bar

with the following code

tmap_mode("plot")
tm_shape(map_osm, projection = 4326, unit = "m") +
  tm_rgb() +
  tm_shape(tcoords_sf) + 
  tm_symbols(col = "darkgreen", shape = 21, size = 2) +
  tm_text(text = "trap", col = "white") +
  tm_scale_bar(breaks = c(0, 50, 100, 150, 200), text.size = 0.6) +
  tm_compass(position = c("left", "top"))

To get a dynamic map is even simpler as you do not have read first the basemap (read_osm) and then draw the map.

tmap_mode("view")
tm_shape(tcoords_sf, bbox = bb_new, unit = "m") + 
  tm_symbols(col = "darkgreen", shape = 21, size = 3) +
  tm_text(text = "trap", col = "white") +
  tm_basemap("Stamen.Watercolor") +
  tm_scale_bar()

In the static plot, colors, text and breaks in the scale can be personalized. Note the parameter unit = "m" in the tm_shape in order to get the scale in meters, if not it will be in kilometers.

Hope you will find this alternative worth mentioning.

like image 87
josep maria porrà Avatar answered Nov 03 '25 03:11

josep maria porrà


Getting the labels onto the map was just a matter of redefining the data source in the geom_text() function.
In order to get the scale to print on the map, it was a matter of following the solution in this question: Is there a way to add a scale bar (for linear distances) to ggmap?

#get base map
map.base <- get_map(location = center, zoom = 16, source = "stamen", maptype = "watercolor") # could also use zoom = "auto"
#get extent of base map
bb <- attr(map.base,"bb")

#define the location and length of scale bar
sbar <- data.frame(lon.start = c(bb$ll.lon + 0.1*(bb$ur.lon - bb$ll.lon)),
                   lon.end = c(bb$ll.lon + 0.25*(bb$ur.lon - bb$ll.lon)),
                   lat.start = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat)),
                   lat.end = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat)))

#Calculate distance in meters
library(geosphere)
sbar$distance = distGeo(c(sbar$lon.start,sbar$lat.start), c(sbar$lon.end,sbar$lat.end))

map.scale <- ggmap(map.base, extent="device")   +
   geom_point(aes(x = longitude, y = latitude), size = 4, shape = 21, fill = "dark green", data = Tcoords) +
   geom_text(data=Tcoords, aes(label=trap, x = longitude, y = latitude), nudge_x = 0.0001, nudge_y = 0.0001, color="black") +

   geom_segment(data = sbar,  aes(x = lon.start, xend = lon.end, y = lat.start, yend = lat.end)) +
   geom_text(data = sbar,  aes(x = (lon.start + lon.end)/2,
                 y = lat.start + 0.025*(bb$ur.lat - bb$ll.lat),
                 label = paste(format(distance,   digits = 4, nsmall = 2), 'm')),
             hjust = 0.5, vjust = 0)  
map.scale

enter image description here

May need to adjust the nudge_x & _y in the geom_text() function for proper label placement.

like image 38
Dave2e Avatar answered Nov 03 '25 05:11

Dave2e