Gavin Rudge (Institute of Applied Health Research)
2018-Jan-19 17:51 UTC
[R] Leaflet maps. Nudging co-incident markers
I have a dataset showing points, with a category for each point and its location. I simply want to display my points, in a way that users can toggle the points on and off by category. Where I have two objects in the same category I'd like to display them nudged to appear as two distinct, but very close points. I have made reproduceable example (the places are not real), which is loosely based on a tutorial I found recently (https://allthisblog.wordpress.com/2016/10/12/r-311-with-leaflet-tutorial/) I have three categories of things (cafes, libraries and galleries), at three locations but have four objects in my set. This is because on of my locations has two functions - there is a cafe at a gallery (North St Gallery and the Gallery Cafe on the same site) If I make a selection that includes galleries and cafes there are just two points. I would like to nudge the point for the North St Galley and the Gallery Cafe so they appear as two (very close) points on the map and display the name when clicked on. Also if anyone has any suggestions for generally tidying up the code I'd be grateful as my real version is much more complex with many more points and marker categories. I believe there are Java libraries out there for managing markers and how they behave, but I'm hoping this can be done in the Leaflet R library somehow. The only solution I could think of was to interrogate the entire dataframe, identify points that were had the same co-ords and move them diagonally apart by adding and subtracting a fixed amount of longitude and latitude from the co-ordinates. Thanks in advance. GavinR Here is the code: library(leaflet) #make data frame of points idno=c(1,2,3,4) x=c(-1.9116, -1.9116,-1.9237,-1.91848) y=c(52.4898,52.4898,52.5015,52.4851) cat=c('Gallery','Cafe','Library','Cafe') n=c('North St Gallery','Gallery cafe', 'South St Library', 'Coffee 2 go') d<-data.frame(idno,x,y,cat,n) #get a map and zoom into approx area of interest m=leaflet()%>% setView(lng = -1.935, lat=52.485, zoom=12) m=addTiles(m) m #create groups of objects c= subset(d,cat=="Cafe") l= subset(d, cat=="Library") g= subset(d, cat=="Gallery") #add markers m=addCircleMarkers(m, lng = c$x, lat = c$y, popup = c$n, radius = 5, stroke =FALSE, fillOpacity = 0.75, group = "1 - Cafes") m=addCircleMarkers(m, lng = g$x, lat = g$y, popup = g$n, radius = 5, stroke =FALSE, fillOpacity = 0.75, group = "2 - Galleries") m=addCircleMarkers(m, lng = l$x, lat = l$y, popup = l$n, radius = 5, stroke =FALSE, fillOpacity = 0.75, group = "3 - libraries") m = addLayersControl(m, overlayGroups = c("1 - Cafes","2 - Galleries","3 - libraries")) m
Hi Gavin, Here's a sort of brute force way to nudge points. Might be helpful. nudge<-function(x,y,away=0.1,tol=0.01) { dimx<-dim(x) if(missing(y) && !is.null(dimx)) { y<-x[,2] x<-x[,1] } xlen<-length(x) if(xlen != length(y)) stop("x and y must be the same length.") for(i in 1:xlen) { for(j in 1:xlen) { if(i != j) { dist<-sqrt((x[i]-x[j])^2 + (y[i]-y[j])^2) if(dist < tol) { if(x[i] >= x[j]) { x[i]<-x[i]+away x[j]<-x[j]-away } else { x[i]<-x[i]-away x[j]<-x[j]+away } if(y[i] >= y[j]) { y[i]<-y[i]+away y[j]<-y[j]-away } else { y[i]<-y[i]-away y[j]<-y[j]+away } } } } } return(list(x=x,y=y)) } x=c(-1.9116, -1.9116,-1.9237,-1.91848) y=c(52.4898,52.4898,52.5015,52.4851) plot(nudge(x,y,0.0001,0.00001)) Jim On Sat, Jan 20, 2018 at 4:51 AM, Gavin Rudge (Institute of Applied Health Research) <G.Rudge at bham.ac.uk> wrote:> I have a dataset showing points, with a category for each point and its location. > > I simply want to display my points, in a way that users can toggle the points on and off by category. > > Where I have two objects in the same category I'd like to display them nudged to appear as two distinct, but very close points. > I have made reproduceable example (the places are not real), which is loosely based on a tutorial I found recently (https://allthisblog.wordpress.com/2016/10/12/r-311-with-leaflet-tutorial/) > > I have three categories of things (cafes, libraries and galleries), at three locations but have four objects in my set. This is because on of my locations has two functions - there is a cafe at a gallery (North St Gallery and the Gallery Cafe on the same site) > > If I make a selection that includes galleries and cafes there are just two points. I would like to nudge the point for the North St Galley and the Gallery Cafe so they appear as two (very close) points on the map and display the name when clicked on. > > Also if anyone has any suggestions for generally tidying up the code I'd be grateful as my real version is much more complex with many more points and marker categories. I believe there are Java libraries out there for managing markers and how they behave, but I'm hoping this can be done in the Leaflet R library somehow. > > The only solution I could think of was to interrogate the entire dataframe, identify points that were had the same co-ords and move them diagonally apart by adding and subtracting a fixed amount of longitude and latitude from the co-ordinates. > > Thanks in advance. > > GavinR > > Here is the code: > > library(leaflet) > > #make data frame of points > > idno=c(1,2,3,4) > x=c(-1.9116, -1.9116,-1.9237,-1.91848) > y=c(52.4898,52.4898,52.5015,52.4851) > cat=c('Gallery','Cafe','Library','Cafe') > n=c('North St Gallery','Gallery cafe', 'South St Library', 'Coffee 2 go') > d<-data.frame(idno,x,y,cat,n) > > #get a map and zoom into approx area of interest > > m=leaflet()%>% setView(lng = -1.935, lat=52.485, zoom=12) > m=addTiles(m) > m > > #create groups of objects > > c= subset(d,cat=="Cafe") > l= subset(d, cat=="Library") > g= subset(d, cat=="Gallery") > > #add markers > > m=addCircleMarkers(m, > lng = c$x, > lat = c$y, > popup = c$n, > radius = 5, > stroke =FALSE, > fillOpacity = 0.75, > group = "1 - Cafes") > > m=addCircleMarkers(m, > lng = g$x, > lat = g$y, > popup = g$n, > radius = 5, > stroke =FALSE, > fillOpacity = 0.75, > group = "2 - Galleries") > > m=addCircleMarkers(m, > lng = l$x, > lat = l$y, > popup = l$n, > radius = 5, > stroke =FALSE, > fillOpacity = 0.75, > group = "3 - libraries") > > m = addLayersControl(m, overlayGroups = c("1 - Cafes","2 - Galleries","3 - libraries")) > > m > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.