r - Dynamic data point label Positioning in ggmap -


i'm working ggmap package in r , relatively new geospatial data visualizations. have data frame of eleven latitude , longitude pairs plot on map, each label. here 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 use annotate create data point labels , plot these on 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 plot of data points plot of data points labels

as can see, there 2 data points overlap around (-122.44,47.63), , labels overlap. can manually add shift each label point keep labels overlapping (see this post), not great technique when need produce many of these plots different sets of latitude , longitude pairs.

is there way can automatically keep data labels overlapping? realize whether labels overlap dependent on actual figure size, i'm open fixing figure size @ dimensions if need be. thank in advance insights!

edit

the following modified code using answer given sandy mupratt

# defining function 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 determine text box borders enlarge.box.modified <- function(d,...){   if(!"h"%in%names(d))stop("need have calculated height , width.")   calc.borders(within(d,{     w <- 0.9*w     h <- 1.1*h   })) } 

generating 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")) 

ggmap plot labels within text boxes

this more readable plot, 1 outstanding issue. you'll note label "site 1e" begins overlap data point associated "site 1a". directlabels have way dealing labels overlapping data points belonging label?

a final question have regarding how can plot several duplicate labels using method. suppose labels data.frame same:

df$labels<-rep("test",dim(df)[1]) 

when use same code, directlabels removes duplicate label names: enter image description here

but want each data point have label of "test". suggestions?

edit 11 jan 2016: using ggrepel package ggplot2 v2.0.0 , ggmap v2.6

ggrepel works well. in code below, geom_label_repel() shows of 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) 

enter image description here



original answer updated ggplot v2.0.0 , ggmap v2.6

if there small number of overlapping points, using "top.bumpup" or "top.bumptwice" method direct labels package can separate them. in code below, use geom_dl() function create , position 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")) 

enter image description here

edit: adjusting underlying labels

a couple of methods spring mind, neither entirely satisfactory. don't think find solution apply situations.

adding background colour each label
bit of workaround, directlabels has "box" function (i.e., labels placed inside box). looks 1 should able modify background fill , border colour in list in geom_dl, can't work. instead, take 2 functions (draw.rects , enlarge.box) directlabels website; modify them; , combine modified functions "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 have calculated height , 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")) 

enter image description here

add outline each label
option use this method give each label outline, although not clear how work directlabels. therefore, need manual adjustment of coordinates, or search of dataframe coordinates within given threshold adjust. however, here, use pointlabel function maptools package position labels. no guarantee work every time, got reasonable result data. there random element built it, can run few time until reasonable result. also, note positions labels in base plot. label locations have extracted , loaded 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  # map map.data <- get_map(location = c(lon=-122.3485,lat=47.6200),                      maptype = 'roadmap', zoom = 11)  bb = t(attr(map.data, "bb"))   # map's bounding box  # base plot plot points , using pointlabels() 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 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 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 labels map +     geom_text(data = new, aes(x = x + .01, y = y, label=labels),       size = 3, colour = 'white', vjust = .5, hjust = .8) 

enter image description here


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -