Search code examples
rgoogle-mapsggplot2ggmaprgooglemaps

R: ggmap: How do I draw lines using only known angles on a ggmap? My geom_spoke method is not working


I am attempting to draw lines in polar coordinates on a ggmap. The general method works fine in ggplot:

library(ggmap)
library(rgdal)
library(ggplot2)

#####################################


## build data frame with triangulation data

t1 <- c(534325, 4858925, 338, 0955)
t2 <- c(534383, 4859261, 290, 1010)
t3 <- c(534386, 4859011, 301, 1015)

df <- as.data.frame(rbind(t1, t2, t3))
colnames(df) <- c("Easting", "Northing", "Azimuth", "Time")
df$Time <- as.character(df$Time)

## plot coordinates with triangulation

ggplot(df, aes(x=Easting, y=Northing, label=Time)) + 
  geom_point() + 
  geom_text(nudge_x = 50) + 
  geom_spoke(aes(angle = Azimuth, radius = -500)) + 
  theme_bw()

Triangulation with no base map:

img1

This is what I want, but with no base map in the background.

However, when I attempt this method in ggmap:

## convert utms to lat long

utmcoor <- SpatialPoints(cbind(df$Easting,df$Northing), 
proj4string=CRS("+proj=utm +zone=12"))
lonlatcoor <- as.data.frame(spTransform(utmcoor,CRS("+proj=longlat")))
colnames(lonlatcoor) <- c("lon", "lat")

df$lon <- lonlatcoor$lon
df$lat <- lonlatcoor$lat

## plot on base map

zoom <- 15 

meanlon <- mean(df$lon)
meanlat <- mean(df$lat)

basemap <- get_googlemap(center=c(lon=meanlon, lat=meanlat), zoom=zoom, 
maptype="hybrid")

ggmap(basemap) + 
  geom_point(aes(x=lon, y=lat), colour="red", size=2, data=df) +
  geom_spoke(aes(x=lon, y=lat, angle = Azimuth), data=df, radius=-200) + 
  theme_void()

I get the error

Warning message:
Removed 3 rows containing missing values (geom_segment).

The code works fine without the geom_spoke line, resulting in basemap without triangulations:

img2

I understand that this function is generally used for things like quiver plots. Does ggmap not support geom_spoke? Is there a better function altogether that I am not aware of?

Thanks in advance.


Solution

  • The issue is with the coordinates: You're giving geom_spoke a radius of -200, but the coordinates you're working with are several orders of magnitude smaller. I took out the theme_void just to remind myself of how small the scale is; you want a radius of something like 0.01. Mess around with the radius value I put here.

    geom_spoke basically does a little trigonometry behind the scenes to calculate the endpoint of each spoke, then draws a segment. If that endpoint is out of the bounds of the plot, you get that missing values warning. I'm not sure if -200 is the radius you're sticking with, or just a dummy value, but you could use your original coordinates and angles to calculate the endpoints, then project those points to figure out the radius. Or just use those endpoints to draw the geom_segment yourself. I'll leave those calculations to you, or it might make for another question. I'm pretty partial to sf and have a feeling that could provide an easy enough way to get those points.

    library(ggmap)
    library(rgdal)
    library(ggplot2)
    
    # .....
    # everything up until ggmap is the same as in question
    
    ggmap(basemap) + 
      geom_point(aes(x=lon, y=lat), colour="red", size=2, data=df) +
      geom_spoke(aes(x=lon, y=lat, angle = Azimuth), data=df, radius = -1e-2)
    

    Created on 2018-07-18 by the reprex package (v0.2.0).