4

I want to represent 2 ships on a map in an interactive way (leaflet based method) with some of their metadata as well. Naturally, metadata of a ship usually contains the heading of the vessel and the most digestible way to represent is by rotating the symbol of the point data accordingly.

After some first trials, I managed to recreate it by following icon rotation in leaflet package, using sheer leaflet and a plugin that allowed me to write in smooth syntax like rotationAngle=~T_heading. This way's result looks like below.enter image description here

However, I am searching for a way to use sf and tmap packages as syntax (tmap's interactive view is also leaflet based) since they are much more complete and sophisticated frameworks for managing and visualizing geospatial information.

Let's again recreate the sample data of the two vessels and plot them.

aship<-c(23.622333,37.937489,'Santa Maria',8,300)
bship<-c(23.621303,37.937430,'Vancouver CC',10,35)
shipdata<-data.frame(rbind(aship,bship))
colnames(shipdata)<-c('long','lat','VesselName','sog','T_heading')
shipdata$long<-as.numeric(as.character(shipdata$long))
shipdata$lat<-as.numeric(as.character(shipdata$lat))
shipdata$sog<-as.numeric(as.character(shipdata$sog))
shipdata$T_heading<-as.numeric(as.character(shipdata$T_heading))
#Simple features transformation 
ship_sf<-shipdata%>%
st_as_sf(coords=c('long','lat'))%>%
st_set_crs(4326)
# Use tmap and plot the vessels using a vessel_icon of my own
map_s1<-tm_basemap(leaflet::providers$OpenStreetMap)+
tm_shape(ship_sf)+
tm_markers(shape = vessel_icon)+
tm_view(set.view=c(lon=23.622333,lat=37.937489,zoom=17))

enter image description here

Up until now I haven't found a way to rotate markers in a tmap way. Is there any simple solution i am missing out?

Much appreciated

1 Answers1

3

This is a solution based on leaflet. Might not be super satisfactory, but seems to me less hackish than other solutions (this or this). As you said, tmap makes use of leaflet, so a straightforward solution is using addAwesomeMarkers and tweaking a bit the icons. Build your map with tmap as you did and make a leaflet widget out of it with tmap_leaflet(). Note that, this is a similar case: R Leaflet plot ship direction.

Your data and the tmap object:

library(tmap)
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
library(leaflet)

tmap_mode("view")
#> tmap mode set to interactive viewing

# Your data
shipdata <- data.frame(long = c(23.622333, 23.62130),
                       lat = c(37.93749, 37.93743),
                       VesselName = c("Santa Maria", "Vancouver CC"),
                       sog = c(8, 10),
                       T_heading = c(300, 35))
ship_sf <- st_as_sf(x = shipdata, 
                    coords = c('long', 'lat'), 
                    crs = "+proj=longlat +datum=WGS84")

# Make use of tmap functionality to produce the map as you posted
map_s1 <-
  tm_basemap(leaflet::providers$OpenStreetMap) +
  tm_shape(ship_sf) +
  tm_symbols(size = 0) + # need to add a layer after tm_shape(), so add "empty" points
  tm_view(set.view = c(lon = 23.622333, lat = 37.937489, zoom = 17))

Now, forge some icons; see also https://ionicons.com Only arrow-up icon works well with the given rotation angles; other arrows have their own rotation already that can mess things up. Then pipe the tmap object into tmap_leaflet() to create a leaflet widget. Finally, add the custom icons:

shipIcon <- makeAwesomeIcon(icon = "arrow-up",
                            iconRotate = shipdata$T_heading,
                            squareMarker = TRUE,
                            markerColor = "black")

map_s1 %>% 
  tmap_leaflet() %>% 
  addAwesomeMarkers(lng = shipdata$lon, 
                    lat = shipdata$lat, 
                    icon = shipIcon, 
                    popup = shipdata$VesselName)

Extra thought

Another idea would be to use iconList() function (mentioned here for example), defining a series of rotated images/icons corresponding to several rotation classes. Another approach in this direction is presented here.

Created on 2019-01-21 by the reprex package (v0.2.1)

Valentin_Ștefan
  • 6,130
  • 2
  • 45
  • 68