I'm getting the following error when using ggmap: Error in if (is.waive(data) || empty(data)) return(cbind(data, PANEL = integer(0))) :
missing value where TRUE/FALSE needed
I've been using ggmap for quite some time now, but can't figure out what the problem is - tried running it on different versions of R (3.3.2, 3.3.3), still getting the same problem. Other datasets with the same spatial extent plot ok...
toy dataset
sub <- structure(list(Lat = c(49.3292885463864, 49.3316446084215,
49.3300452342386, 49.3317620975044, 49.3304515659156, 49.3305117886863,
49.3283736754004, 49.3307167462002, 49.3318995940679, 49.333169419547,
49.3309562839252, 49.3317698899629, 49.3281374770165, 49.3316554590127,
49.3326735200194, 49.331519408234, 49.3280156106529, 49.3291709916829,
49.3328300103323, 49.3306140984074), Lon = c(-117.657207875892,
-117.672957375133, -117.66331506511, -117.672862630678, -117.66304525751,
-117.668207331581, -117.655158806988, -117.66229183045, -117.673965605927,
-117.673707660621, -117.662873110863, -117.673069192809, -117.655568553898,
-117.674182492008, -117.673907352374, -117.675914855, -117.65485127671,
-117.657316414995, -117.671748537091, -117.662937333234), z =
c(9.27369836928302, 2.39183027404169, -1.93395087707449, -3.18890166171755,
-0.97968656067399, 2.2968631268102, 8.25209737911514, -1.44955530148785,
-1.16576549902187, 0.341268832113262, -1.15519233610136, 10.2579242298728,
-4.65813764430002, 0.301315621593428, 5.25169173852741, -5.37463429849591,
4.70020657978266, -4.64139357200872, -1.38702225667279, 9.38668592801448)),
.Names = c("Lat", "Lon", "z"), row.names = c(266748L, 266749L, 266750L,
266756L, 266758L, 266760L, 266768L, 266770L, 266771L, 266772L, 266778L,
266782L, 266783L, 266784L, 266787L, 266791L, 266792L, 266796L,
266801L, 266802L), class = "data.frame")
code
library(ggmap)
library(ggplot2)
prep <- get_googlemap(center = c(-117.660, 49.329), zoom = 14,
maptype = 'satellite', scale = 2)
map <- ggmap(prep, size = c(100, 200),
extent='device', darken = 0, legend = "bottom",
base_layer = ggplot(data = sub, aes(x = Lon, y = Lat)))
map
map + geom_point(data = sub, aes(x = Lon, y = Lat, colour = z), size = 1)
EDIT
I need to use facets, which is why the base_layer call is there.
Why the base_layer bit?
This works fine for me:
map <- ggmap(prep, size = c(100, 200),
extent='device', darken = 0, legend = "bottom")
map + geom_point(data = sub, aes(x = Lon, y = Lat, colour = z), size = 1)
Update:
Works with facet_wrap, too!
sub$facet <- sample(x = 1:4, size = nrow(sub), replace = TRUE)
map2 <- ggmap(ggmap = get_googlemap(maptype = 'satellite',
center = c(-117.660, 49.329),
zoom = 14)) +
geom_point(data = sub, aes(x = Lon, y = Lat, colour = z), size = 1) +
facet_wrap(~ facet, nrow = 2)
Related
I am trying to color in specific grid cells within a map to highlight sampling effort.
I can generate the map but then I am unsure how to utilize the data points I have to color in the entire grid cell. The data points I have are for the top left hand corner of a grid cell.
I have tried using stat_density2d (kernel density func), as far as I can work out the issue is I just want the discrete values plotted but currently it is filling in everything in-between.
library(ggOceanMaps)
library(ggOceanMapsData)
dt <- data.frame(lon = c(35, 35, 60, 60), lat = c(-25, -25, -40, -40))
grid_2_colour <- data.frame(lat=c(-29), long=c(50))
basemap(data = dt, bathymetry = TRUE,
lon.interval = 1,
lat.interval = 1,
# bathy.style = "contour_blues",
bathy.border.col = NA,
bathy.size = 0.1,
bathy.alpha = 1) +
stat_density2d(data = grid_2_colour, aes(x = long, y = lat, fill =..density..), geom = 'tile', contour = F)
found a solution:
m1 = basemap(data = dt, bathymetry = TRUE,
lon.interval = 1,
lat.interval = 1,
# bathy.style = "contour_blues",
bathy.border.col = NA,
bathy.size = 0.1,
bathy.alpha = 1)
m1 + stat_density2d(data = grid_2_colour, aes(x = long, y = lat, fill =..density..), geom = 'tile', contour = F)
I'm working with spatial data. I'd like to create an animation of a movement path, with older data fading out. I figured out how to create the fade-out effect with points, but it looks like there's no built-in support for transitions for geom_path (Error: path layers not currently supported by transition_components). But are there any clever workarounds that could be used? My full dataset is large (200K points) and the overlapping paths get out of hand...
toy data:
library(ggplot2)
library(gganimate)
df <- structure(list(Lon = c(-66.6319163369509, -66.5400363369509,
-65.3972830036509, -65.2810430036509, -65.1169763369509, -64.7409730036509,
-64.3898230036509, -64.3458230036509, -64.1435830036509, -64.1902230036509,
-64.5269330036509, -64.5508330036509, -64.9324130036509, -66.4002496703509,
-66.4605896703509, -66.6230763369509, -66.6636963369509, -66.6425830036509,
-66.5310230036509, -66.4582830036509, -66.2992030036509, -65.8810363369509,
-65.3338363369509, -65.2480363369509, -65.3705963369509, -65.8357874342282,
-66.7324643369709, -66.8768896703509, -66.8215363369509, -66.8320584884004
), Lat = c(63.9018749538395, 64.1357216205395, 64.4444682872395,
64.4580016205395, 64.4744549538395, 64.4951416205395, 64.5202416205395,
64.5237216205395, 64.5388016205395, 64.5400516205395, 64.5090116205395,
64.5069516205395, 64.4609016205395, 64.2904882872395, 64.1898016205395,
63.9022816205395, 63.9948082872395, 64.0236682872395, 64.1115882872395,
64.2171216205395, 64.3599949538395, 64.3979682872395, 64.4634216205395,
64.4719816205395, 64.4459016205395, 64.4008282316608, 63.8029216205395,
63.7730882872395, 63.8046816205395, 63.8239941445658), DateTime = structure(c(1451784300,
1451790981, 1451806092, 1451807038, 1451808331, 1451811238, 1451813999,
1451814338, 1451815898, 1451820189, 1451822838, 1451823018, 1451826048,
1451838029, 1451840610, 1451848380, 1451864271, 1451865064, 1451867591,
1451870472, 1451874641, 1451878100, 1451882678, 1451883331, 1451886921,
1451890867, 1451910187, 1451925099, 1451929401, 1451934427), class = c("POSIXct",
"POSIXt"), tzone = "GMT")), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -30L))
df$TimeNum <- as.numeric(df$DateTime)
Plots:
##### successful fade - with points
p <- ggplot(df) +
geom_point(aes(x = Lon, y = Lat), size = 2) +
transition_components(TimeNum, exit_length = 20) +
ease_aes(x = 'sine-out', y = 'sine-out') +
shadow_wake(0.05, size = 2, alpha = TRUE, wrap = FALSE, #exclude_layer = c(2, 3),
falloff = 'sine-in', exclude_phase = 'enter')
animate(p, renderer = gifski_renderer(loop = F), duration = 10)
anim_save("try.gif")
##### successful plot with geom_path, but no fading - it gets REALLY busy with the
##### full dataset!
p1 <- ggplot(df) +
geom_path(aes(x = Lon, y = Lat), size = 2) +
transition_reveal(DateTime, keep_last = FALSE) +
labs(title = 'A: {frame_along}') +
exit_fade()
animate(p1, renderer = gifski_renderer(loop = F), duration = 10)
anim_save("try1.gif", width = 1000, height = 1000)
I'm not sure this is exactly what you're looking for, but you could use geom_segment instead of geom_path by adding the adjacent coordinate.
library(dplyr)
df1 <- df %>%
mutate(next_Lon = lead(Lon),
next_Lat = lead(Lat))
ggplot(df1) +
geom_segment(aes(x = Lon, y = Lat,
xend = next_Lon,
yend = next_Lat), size = 2) +
geom_point(aes(x = Lon, y = Lat), size = 2) +
transition_components(TimeNum, exit_length = 20) +
ease_aes(x = 'sine-out', y = 'sine-out') +
shadow_wake(0.05, size = 2, alpha = TRUE, wrap = FALSE, #exclude_layer = c(2, 3),
falloff = 'sine-in', exclude_phase = 'enter')
I have a dataset of people arriving in a location, how long they stayed, and their home locations. I want to create an animated chart which 'flies' them to their destination, and returns them to their original point once their trip is over. But I'm not sure if this is possible with gganimate or not. At the moment I only seem to be able to do a "start" and "end" frame, though it's a little hard to tell whether it just doesn't have enough frames to do the intended action.
Here's something like what I have so far:
library(dplyr)
library(ggplot2)
library(ggmap)
library(gganimate)
#Coordinates
europecoords <- c(left = -23, bottom = 36, right = 27.87, top = 70.7)
londonareacoords <- c(left = -.7, bottom = 51, right = 0.2, top = 52)
londonpointcoords <- as.data.frame(list(lon = -.14, lat = 51.49))
#Get the map we'll use as the background
europe <- get_stamenmap(europecoords, zoom = 4, maptype = "toner-lite")
#Sample dataset configuration
numberofpoints <- 10
balance <- 0.1
#Set up an example dataset
ids <- seq(1:numberofpoints)
arrivalday <- sample(x = 30, size = numberofpoints, replace = TRUE)
staylength <- sample(x = 7, size = numberofpoints, replace = TRUE)
startlocationlondonarealon <- sample(x = seq(londonareacoords['left'] * 10, londonareacoords['right'] * 10), size = numberofpoints * balance, replace = TRUE) / 10
startlocationlondonarealat <- sample(x = seq(londonareacoords['bottom'] * 10, londonareacoords['top'] * 10), size = numberofpoints * balance, replace = TRUE) / 10
startlocationeuropelon <- sample(x = seq(europecoords['left'] * 10, europecoords['right'] * 10), size = (numberofpoints * (1 - balance)), replace = TRUE) / 10
startlocationeuropelat <- sample(x = seq(europecoords['bottom'] * 10, europecoords['top'] * 10), size = (numberofpoints * (1 - balance)), replace = TRUE) / 10
startlocationlon <- c(startlocationlondonarealon, startlocationeuropelon)
startlocationlat <- c(startlocationlondonarealat, startlocationeuropelat)
points <- as.data.frame(cbind(ID = ids, arrivalday, staylength, departureday = arrivalday + staylength, startlocationlon, startlocationlat))
#Map the sample dataset to check it looks reasonable
ggmap(europe) +
geom_point(data = points, aes(x = startlocationlon, y = startlocationlat), col = "blue", size = 2) +
geom_point(data = londonpointcoords, aes(x = lon, y = lat), col = "red")
#Separate the events out to rearrange, then glue them back together
event1 <- points %>%
mutate(Event = "Day Before Arrival", Date = arrivalday - 1) %>%
mutate(Lon = startlocationlon,
Lat = startlocationlat) %>%
select(ID, Event, Date, Lon, Lat)
event2 <- points %>%
mutate(Event = "Arrival Date", Date = arrivalday) %>%
mutate(Lon = londonpointcoords$lon[1],
Lat = londonpointcoords$lat[1]) %>%
select(ID, Event, Date, Lon, Lat)
event3 <- points %>%
mutate(Event = "Departure Date", Date = departureday) %>%
mutate(Lon = londonpointcoords$lon[1],
Lat = londonpointcoords$lat[1]) %>%
select(ID, Event, Date, Lon, Lat)
event4 <- points %>%
mutate(Event = "Day After Departure", Date = departureday + 1) %>%
mutate(Lon = startlocationlon,
Lat = startlocationlat) %>%
select(ID, Event, Date, Lon, Lat)
events <- rbind(event1, event2, event3, event4) %>%
mutate(Event = factor(Event, ordered = TRUE, levels = c("Day Before Arrival", "Arrival Date", "Departure Date", "Day After Departure"))) %>%
mutate(ID = factor(ID))
#Make an animation
ggmap(europe) +
geom_point(data = events, aes(x = Lon, y = Lat, group = ID, col = ID), size = 2) +
#geom_point(data = londonpointcoords, aes(x = lon, y = lat), col = "red") +
transition_manual(Date) +
labs(title = "Date: {frame}") +
NULL
But as I said, the points don't seem to be 'flying' as much as just appearing and disappearing. Should I be using a different data format? Transition type? Number of frames? (I'm having trouble finding documentation on any of the above, which is part of why I'm stuck...)
Final result
Code
library(ggplot2)
library(ggmap)
library(gganimate)
ggm <- ggmap(europe) +
geom_point(data = events,
aes(x = Lon, y = Lat,
colour = ID, group = ID, shape = Event),
size = 3, alpha = 0.8) +
transition_time(Date) +
labs(title = paste("Day", "{round(frame_time,0)}")) +
shadow_wake(wake_length = 0.1)
animate(ggm, fps = 24, duration = 16)
========================================================
Step-by-step
You have lots of moving parts there. Let's break it down a bit:
0. Load libraries
library(ggplot2)
library(ggmap)
library(gganimate)
library(ggrepel) # will be useful for data exploration in step 1
1. Data exploration
ggplot(data = events, aes(x = ID, y = Date, colour = Event)) +
geom_point()
We see, that the arrival and departure events are each quite close together for each plane. Also, there is always a gap of a couple of days inbetween. That seems reasonable.
Let's check the Date variable:
> length(unique(events$Date))
[1] 24
> min(events$Date)
[1] 2
> max(events$Date)
[1] 33
Okay, this means two things:
Our data points are unevenly spaced.
We don't have data for all Dates.
Both things will make the animation part quite challenging.
ggplot(data = unique(events[, 4:5]), aes(x = Lon, y = Lat)) +
geom_point()
Furthermore, we only have 11 unique locations (== airports). This will probaly lead to overlapping data. Let's plot it by day:
ggplot(data = unique(events[, 3:5]), aes(x = Lon, y = Lat, label = Date)) +
geom_point() +
geom_text_repel()
Yup, this will be fun... Lots of things happening at that airport in the middle.
2. Basic animation
gga <- ggplot(data = events, aes(x = Lon, y = Lat)) +
geom_point() +
transition_time(Date)
animate(gga)
We used transition_time() and not transition_states(), because the former is used for linear time variables (e.g., second, day, year) and automatic interpolation, while the latter gives more manual control to the user.
3. Let's add colour
gga <- ggplot(data = events, aes(x = Lon, y = Lat, colour = ID)) +
geom_point() +
transition_time(Date)
animate(gga)
It's starting to look like something!
4. Add title, transparency, increase size
gga <- ggplot(data = events, aes(x = Lon, y = Lat, col = ID)) +
geom_point(size = 3, alpha = 0.5) +
transition_time(Date) +
labs(title = paste("Day", "{round(frame_time, 0)}"))
Note the rounded {round(frame_time, 0)}. Try using {frame_time} and see what happens!
5. Add some pizzaz
gga <- ggplot(data = events, aes(x = Lon, y = Lat, col = ID, group = ID,
shape = Event)) +
geom_point(size = 3, alpha = 0.5) +
transition_time(Date) +
labs(title = paste("Day", "{round(frame_time, 0)}")) +
shadow_wake(wake_length = 0.05)
animate(gga)
Looks good, let's finish it up!
6. Add the map, make animation slower, tweak some details
ggm <- ggmap(europe) +
geom_point(data = events,
aes(x = Lon, y = Lat,
colour = ID, group = ID, shape = Event),
size = 3, alpha = 0.8) +
transition_time(Date) +
labs(title = paste("Day", "{round(frame_time,0)}")) +
shadow_wake(wake_length = 0.1)
animate(ggm, fps = 24, duration = 16)
Not too shabby, eh? As a side note: animate(ggm, nframes = 384) would have had the same effect on the animation as fps = 24 with duration = 16.
If you have any question please do not hesitate to shoot me a comment.
I will try my best to help or clarify things.
This code only works for the center coordinates (x=-95.36, y=29.76). I want to change them and select random data from that area.
Does anyone knows what is happening?
#Select random data and connect it
get_googlemap(urlonly = TRUE)
ggmap(get_googlemap())
# markers and paths are easy to access
d <- function(x=-95.36, y=29.76, n,r,a){
round(data.frame(lon = jitter(rep(x,n), amount = a),
lat = jitter(rep(y,n), amount = a)),
digits = r)
}
df <- d(n=50,r=3,a=.3)
map <- get_googlemap(markers = df, path = df,, scale = 2)
ggmap(map)
ggmap(map, extent = "device") +
geom_point(aes(x = lon, y = lat), data = df, size = 3, colour = "black") +
geom_path(aes(x = lon, y = lat), data = df)
I'm working with the ggmap package in R and I am relatively new to geospatial data visualizations. I have a data frame of eleven latitude and longitude pairs that I would like to plot on a map, each with a label. Here is the dummy data:
lat<- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,47.586349,47.512684,47.571232,47.562283)
lon<-c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,-122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
labels<-c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D","Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")
df<-data.frame(lat,lon,labels)
Now I use annotate to create the data point labels and plot these on a map;
map.data <- get_map(location = c(lon=-122.3485,lat=47.6200),
maptype = 'roadmap', zoom = 11)
pointLabels<-annotate("text",x=uniqueReach$lon,y=c(uniqueReach$lat),size=5,font=3,fontface="bold",family="Helvetica",label=as.vector(uniqueReach$label))
dataPlot <- ggmap(map.data) +
geom_point(data = uniqueReach,aes(x = df$lon, y = df$lat), alpha = 1,fill="red",pch=21,size = 6) + labs(x = 'Longitude', y = 'Latitude')+pointLabels
This produces a plot of the data points
As you can see, there are two data points that overlap around (-122.44,47.63), and their labels also overlap. Now I can manually add a shift to each label point to keep the labels from overlapping (see this post), but this is not a great technique when I need to produce many of these plots for different sets of latitude and longitude pairs.
Is there a way I can automatically keep data labels from overlapping? I realize whether the labels overlap is dependent on the actual figure size, so I'm open to fixing the figure size at certain dimensions if need be. Thank you in advance for any insights!
EDIT
The following is modified code using the answer given by Sandy Mupratt
# Defining function to draw text boxes
draw.rects.modified <- function(d,...){
if(is.null(d$box.color))d$box.color <- NA
if(is.null(d$fill))d$fill <- "grey95"
for(i in 1:nrow(d)){
with(d[i,],{
grid.rect(gp = gpar(col = box.color, fill = fill,alpha=0.7),
vp = viewport(x, y, w, h, "cm", c(hjust, vjust=0.25), angle=rot))
})
}
d
}
# Defining function to determine text box borders
enlarge.box.modified <- function(d,...){
if(!"h"%in%names(d))stop("need to have already calculated height and width.")
calc.borders(within(d,{
w <- 0.9*w
h <- 1.1*h
}))
}
Generating the plot:
dataplot<-ggmap(map.data) +
geom_point(data = df,aes(x = df$lon, y = df$lat),
alpha = 1, fill = "red", pch = 21, size = 6) +
labs(x = 'Longitude', y = 'Latitude') +
geom_dl(data = df,
aes(label = labels),
list(dl.trans(y = y + 0.3), "boxes", cex = .8, fontface = "bold"))
This is a MUCH more readable plot, but with one outstanding issue. You'll note that the label "Site 1E" begins to overlap the data point associated with "Site 1A". Does directlabels have a way with dealing with labels overlapping data points belonging to another label?
A final question I have regarding this is how can I plot several duplicate labels using this method. Suppose the labels for data.frame are all the same:
df$labels<-rep("test",dim(df)[1])
When I use the same code, directlabels removes the duplicate label names:
But I want each data point to have a label of "test". Any suggestions?
Edit 11 Jan 2016: using ggrepel package with ggplot2 v2.0.0 and ggmap v2.6
ggrepel works well. In the code below, geom_label_repel() shows some of the available parameters.
lat <- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,
47.586349,47.512684,47.571232,47.562283)
lon <- c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,
-122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
labels <- c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D",
"Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")
df <- data.frame(lat,lon,labels)
library(ggmap)
library(ggrepel)
library(grid)
map.data <- get_map(location = c(lon = -122.3485, lat = 47.6200),
maptype = 'roadmap', zoom = 11)
ggmap(map.data) +
geom_point(data = df, aes(x = lon, y = lat),
alpha = 1, fill = "red", pch = 21, size = 5) +
labs(x = 'Longitude', y = 'Latitude') +
geom_label_repel(data = df, aes(x = lon, y = lat, label = labels),
fill = "white", box.padding = unit(.4, "lines"),
label.padding = unit(.15, "lines"),
segment.color = "red", segment.size = 1)
Original answer but updated for ggplot v2.0.0 and ggmap v2.6
If there is only a small number of overlapping points, then using the "top.bumpup" or "top.bumptwice" method from the direct labels package can separate them. In the code below, I use the geom_dl() function to create and position the labels.
lat <- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,
47.586349,47.512684,47.571232,47.562283)
lon <- c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,
-122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
labels <- c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D",
"Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")
df <- data.frame(lat,lon,labels)
library(ggmap)
library(directlabels)
map.data <- get_map(location = c(lon = -122.3485, lat = 47.6200),
maptype = 'roadmap', zoom = 11)
ggmap(map.data) +
geom_point(data = df, aes(x = lon, y = lat),
alpha = 1, fill = "red", pch = 21, size = 6) +
labs(x = 'Longitude', y = 'Latitude') +
geom_dl(data = df, aes(label = labels), method = list(dl.trans(y = y + 0.2),
"top.bumptwice", cex = .8, fontface = "bold", family = "Helvetica"))
Edit: Adjusting for underlying labels
A couple of methods spring to mind, but neither is entirely satisfactory. But I don't think you will find a solution that will apply to all situations.
Adding a background colour to each label
This is a bit of a workaround, but directlabels has a "box" function (i.e., the labels are placed inside a box). It looks like one should be able to modify background fill and border colour in the list in geom_dl, but I can't get it to work. Instead, I take two functions (draw.rects and enlarge.box) from the directlabels website; modify them; and combine the modified functions with the "top.bumptwice" method.
draw.rects.modified <- function(d,...){
if(is.null(d$box.color))d$box.color <- NA
if(is.null(d$fill))d$fill <- "grey95"
for(i in 1:nrow(d)){
with(d[i,],{
grid.rect(gp = gpar(col = box.color, fill = fill),
vp = viewport(x, y, w, h, "cm", c(hjust, vjust=0.25), angle=rot))
})
}
d
}
enlarge.box.modified <- function(d,...){
if(!"h"%in%names(d))stop("need to have already calculated height and width.")
calc.borders(within(d,{
w <- 0.9*w
h <- 1.1*h
}))
}
boxes <-
list("top.bumptwice", "calc.boxes", "enlarge.box.modified", "draw.rects.modified")
ggmap(map.data) +
geom_point(data = df,aes(x = lon, y = lat),
alpha = 1, fill = "red", pch = 21, size = 6) +
labs(x = 'Longitude', y = 'Latitude') +
geom_dl(data = df, aes(label = labels), method = list(dl.trans(y = y + 0.3),
"boxes", cex = .8, fontface = "bold"))
Add an outline to each label
Another option is to use this method to give each label an outline, although it is not immediately clear how it would work with directlabels. Therefore, it would need a manual adjustment of the coordinates, or a search of the dataframe for coordinates that are within a given threshold then adjust. However, here, I use the pointLabel function from maptools package to position the labels. No guarantee that it will work every time, but I got a reasonable result with your data. There is a random element built into it, so you can run it a few time until you get a reasonable result. Also, note that it positions labels in a base plot. The label locations then have to extracted and loaded into the ggplot/ggmap.
lat<- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,47.586349,47.512684,47.571232,47.562283)
lon<-c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,-122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
labels<-c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D","Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")
df<-data.frame(lat,lon,labels)
library(ggmap)
library(maptools) # pointLabel function
# Get map
map.data <- get_map(location = c(lon=-122.3485,lat=47.6200),
maptype = 'roadmap', zoom = 11)
bb = t(attr(map.data, "bb")) # the map's bounding box
# Base plot to plot points and using pointLabels() to position labels
plot(df$lon, df$lat, pch = 20, cex = 5, col = "red", xlim = bb[c(2,4)], ylim = bb[c(1,3)])
new = pointLabel(df$lon, df$lat, df$labels, pos = 4, offset = 0.5, cex = 1)
new = as.data.frame(new)
new$labels = df$labels
## Draw the map
map = ggmap(map.data) +
geom_point(data = df, aes(x = lon, y = lat),
alpha = 1, fill = "red", pch = 21, size = 5) +
labs(x = 'Longitude', y = 'Latitude')
## Draw the label outlines
theta <- seq(pi/16, 2*pi, length.out=32)
xo <- diff(bb[c(2,4)])/400
yo <- diff(bb[c(1,3)])/400
for(i in theta) {
map <- map + geom_text(data = new,
aes_(x = new$x + .01 + cos(i) * xo, y = new$y + sin(i) * yo, label = labels),
size = 3, colour = 'black', vjust = .5, hjust = .8)
}
# Draw the labels
map +
geom_text(data = new, aes(x = x + .01, y = y, label=labels),
size = 3, colour = 'white', vjust = .5, hjust = .8)