How to select superimposed circles in R leaflet::addCircles? - r

I am using the leaflet package for R to plot circles in sizes and colors that are determined by a set of variables. It works well, but not all circles can be selected with the cursor. I cannot show the mouseover tooltip or popup window for circles that are hidden underneath larger circles.
How can I fix that? I already have on/off toggles in my legend to simplify the map and hide categories, but the issue persist when overlapping circles belong to the same category.
A drag-n-drop feature, or a way to cycle through circles under the cursor using the mouse wheel would be perfect, but I am not sure this can be achieved in R.
Thank you.
[Edit] Here is an example:
library(leaflet)
n <- c(50, 100)
coord <- matrix(c(-72.3, -70.3, -72, -70), nrow=2, byrow=T)
map <- leaflet() %>%
addTiles() %>%
setView(lng = -72, lat = -70, zoom = 5)
for (i in 1:length(n)) {
map <- map %>% addCircles(lng = coord[i, 1], lat = coord[i, 2], radius = n[i]*1000, # Radius is proportional to sample size
label=paste0("Mouseover tooltip ", i),
popup=paste0("Popup window ", i),
highlightOptions=highlightOptions(color="black", weight=2))
}
map
Output with circle 2 preventing selection of circle 1 because it is on top:
Radius is a function of sample size in the data set, so I cannot freely manipulate it to avoid overlapping, and cannot reduce it an all circles either because I already have very small samples in the data set. Blue would be one category here (other categories/colors exist in the data set but can toggled off from the legend so it's not an issue when they hide other categories). The circle 1 is smaller than the circle 2 due to a smaller sample.
Of course, here I drew the only two circles using addCircles twice, so I could just decide to plot the smaller circle after the larger one so it's on the top layer. But in my data, there are tens of circles plotted automatically according to the variables and I cannot sort manually the order in which circles from a single category are plotted.
[Edit 2] Just found out that adding sendToBack=T to the highlightOptions=highlightOptions()line helps. It allows cycling through overlapping circles by sending those on the front to the back after they have been hovered by the cursor. However it's not perfect when there are more than 2 circles, because the user would hardly cycle voluntarily using this method, the cursor has to be brought in and out several times until the correct circle is highlighted. Better than nothing though. If anyone has another method to suggest, please don't hesitate.

Related

Detecting a line in an image and save its coordinates

I have an image representing an intensity graph:
intensity graph
In order to multiplicate two intensitiy graphs I need to save the coordinates of this graph. Thus, I first want to find the (middle or one border of the) line and then get its coordinates. So far I tried a few things. Which came nearest to the solution was using the LineSegmentDetector package:
library(pixmap)
image <- read.pnm(file = "graph.pgm", cellres = 1)
x <- image#grey * 255
linesegments <- image_line_segment_detector(x)
linesegments
plot(image)
plot(linesegments, add = TRUE, col = "red")
This gives me a couple of line segments:
enter image description here
However, the aim is to get one line of 1 pixel width like this:
enter image description here
Subsequently, I would need the coordinates of this graph. I would need one y value for every pixel in x direction.
I hope my problem is clear and am thankful for any help!

Finding xy coordinates of shelves in a store floorplan in r

I'm working on the following: I have a store layout, example see below (cannot add the real thing for GDPR reasons but the example should do the trick) on which I have xy coordinates from visitors (anonymous of course)
I already placed a grid on the picture so I can see which route they take in the store. That works fine. origin is bottom left and x & y are scaled from 0-100.
So far so good. Now next step is identifying the coordinates of the shelves, rectangles in the picture. Is there a way to do this without having to do this manually? The real store layout contains more than 900 shelves or am I pushing out the boat too far?
The output I'm looking for is a dataframe that contains a shelve ID and the coordinates for the corners. Idea is to create some heatmaps in the store to see that there are blind spots, hotspots, ...
The second analysis needs also the integer points. The idea is to create vectors of visitor points so we get a direction to which they are looking. By using the scope of what a human being can see I would give percentages of "seen" the products based on intersection with integer points.
thx!
JL
One approach is to perform clustering on the black pixels of the image. The clusters are then the shelves. If the shelves are axis parallel you can find the rectangles by just taking min/max in each direction. This works quite well:
Sample code (I converted the image to PNG as it is easier to read than gif):
library(png)
library(dbscan)
library(tidyverse)
library(RColorBrewer)
img <- readPNG("G18JU.png")
is_black <-
img %>%
apply(c(1, 2), sum) %>% #sum all color channels
{. < 2.5} %>% # we assume black if the sum is lower than 2.5 (max value is 3)
which(arr.ind=TRUE) # the indices of the black pixels
clust <- dbscan(is_black, 2) # identify clusters
rects <-
as.tibble(is_black) %>%
mutate(cluster = clust$cluster) %>% # add cluster information
group_by(cluster) %>%
## find corner points of rectangles normalized to [0, 1]
summarise(xleft = max(col) / dim(img)[2],
ybottom = 1 - min(row) / dim(img)[1],
xright = min(col) / dim(img)[2],
ytop = 1 - max(row) / dim(img)[1])
## plot the image and the rectangles
plot(c(0, 1), c(0, 1), type="n")
rasterImage(img, 0, 0, 1, 1)
for (i in seq_len(nrow(rects))) {
rect(rects$xleft[i], rects$ybottom[i], rects$xright[i], rects$ytop[i],
border = brewer.pal(nrow(rects), "Paired")[i], lwd = 2)
}
Of course this approach also detects other black lines as "rectangles" (e.g. the black border). But I guess you can easily create a "clean" image.
Edit: extend method to find shelves that share a black line
To extend the method such that it can separate shelves that share a black line:
First, identify the rectangles in the way outlined above.
Then, extract each rectangle from the image and compute the row means. This gives you a 1d image (= line) for each rectangle. In this line apply thresholding and clustering as before. The clusters are now the black line segments, and the mean of each cluster corresponds to a vertical line shared by two shelves.
To find horizontal shared lines, the same procedure can be applied, but with column means instead of row means.

Order vertices within layers on tripartite igraph

I have the following dataframe:
df<-data.frame(consumed= c("level1_plt1", "level1_plt2", "level1_plt3", "level1_plt3","level1_plt2","level1_plt4","level1_plt5","level1_plt5","level1_plt6","level1_plt7","level1_plt8","level1_plt9","level1_plt10","level1_plt10","level1_plt1","level1_plt1","level1_plt6","level1_plt6","level1_plt9","level1_plt9","level1_plt11","level1_plt11","level1_plt11","level2_lep1","level2_lep4","level2_lep3"),consumer=c("level2_lep1","level2_lep2","level2_lep3","level2_lep2","level2_lep4", "level2_lep4","level2_lep5","level2_lep5","level2_lep6","level2_lep7","level2_lep8","level2_lep9","level2_lep10","level2_lep10","level2_lep8","level2_lep8","level2_lep1","level2_lep1","level2_lep3","level2_lep11","level2_lep12","level2_lep13","level2_lep13", "level3_pst1","level3_pst3","level3_pst4"))
And have preformed the following steps to get an igraph tripartite output:
links<-
df%>%
group_by(consumed, consumer) %>%
summarize(freq=n())
g<- graph_from_data_frame(d=links,directed=FALSE)
layer <- rep(2, length(V(g)$name))
layer[grepl("level1_",V(g)$name)]=1
layer[grepl("level3_",V(g)$name)]=3
names<- V(g)$name
names<-sub("level2_","", names)
names<-sub("level3_","", names)
names<-sub("level1_","", names)
V(g)$name = names
layout = layout_with_sugiyama(g, layers=layer)
E(g)$width <- E(g)$freq
V(g)$vertex_degree <- degree(g)*7
plot(g,
layout=cbind(layer,layout$layout[,1]),edge.curved=0,
vertex.shape=c("square","circle","square")[layer],
vertex.frame.color = c("darkolivegreen","darkgoldenrod","orange3")
[layer],
vertex.color=c("olivedrab","goldenrod1","orange1")[layer],
vertex.label.color="white",
vertex.label.font=2,
vertex.size=V(g)$vertex_degree,
vertex.label.dist=c(0,0,0)[layer],
vertex.label.degree=0, vertex.label.cex=0.5)
And I would like to do two things to adjust the picture, if possible:
Order the layers from the largest shape (highest degree) to smallest shape (smallest degree). For example, in the green layer the order could be as follows: plt9, plt3,plt2,plt11,plt6,plt1,plt7,plt5,plt4,plt10,plt8.
Create space between the shapes so that there is no overlap (e.g. lep3 and lep4). I like the current sizes/proportions so I am opposed to making shapes smaller to create space between shapes.
Flip the graph and vertex font 90 degrees counter-clockwise so that from bottom to top it would be in the order green layer-->yellow layer-->orange layer. (I guess it is always an option to rotate vertex text and I can rotate the image in word or ppt.)
I know this question is old, but I hope that the answer will help someone.
Rather than using layout_with_sugiyama, It may be easiest to do this with
a custom layout. It is not very hard to do so. You already constructed the
horizontal position with your layer variable. To get the vertical positions,
we need to order the vertices by size (vertex_degree) and then allow shape proportional to the size, so we will set the height using cumsum on the vertex_degrees within each layer. After I make the layout the complex call to plot is the same as yours except
that I swap my custom layout for your call to sugiyama.
MyLO = matrix(0, nrow=vcount(g), ncol=2)
## Horizontal position is determined by layer
MyLO[,1] = layer
## Vertical position is determined by sum of sorted vertex_degree
for(i in 1:3) {
L = which(layer ==i)
OL = order(V(g)$vertex_degree[L], decreasing=TRUE)
MyLO[L[OL],2] = cumsum(V(g)$vertex_degree[L][OL])
}
plot(g,
layout=MyLO, edge.curved=0,
vertex.shape=c("square","circle","square")[layer],
vertex.frame.color = c("darkolivegreen","darkgoldenrod","orange3")[layer],
vertex.color=c("olivedrab","goldenrod1","orange1")[layer],
vertex.label.color="white",
vertex.label.font=2,
vertex.size=V(g)$vertex_degree,
vertex.label.dist=0,
vertex.label.degree=0, vertex.label.cex=0.5)

How to get the color coded plotted areas in images using R?

Hi R expert of the world,
Assume I have a point pattern that generate an intensity map and that this map is color coded in 3 region in an pixeled image.... how could I get the color-coded area?
here it is an example using spatstat:
library(spatstat)
japanesepines
Z<-density(japanesepines); plot(dens) # ---> I create a density map
b <- quantile(Z, probs = (0:3)/3) # ---> I "reduce it" to 3 color-ceded zones
Zcut <- cut(Z, breaks = b, labels = 1:3); plot(Zcut)
class(Zcut) # ---> and Zcut is my resultant image ("im")
Thank you in advance
Sacc
In your specific example it is very easy to calculate the area because you used quantile to cut the image: This effectively divides the image into areas of equal size, so there should be three areas of size 1/3 since the window is a unit square. In general to calculate areas from a factor valued image you could use as.tess and tile.areas (continuing your example):
Ztess <- as.tess(Zcut)
tile.areas(Ztess)
In this case the areas are 0.333313, which must be due to discretization.
I'm not exactly sure what you're after, but you can count up the number of pixels in each color using the table() function.
table(Zcut[[1]])

Join overlapping circles using R

I want to draw circles with semitransparent colour on top of a map (showing prevalence), the colour at overlap areas is too heavy to show the background image, the code am using is too long to put here, but for circles am using:
symbols(data[,c(9, 10)],
circles = 5/(pi * a.rad * cos(atan(b.rad / a.rad * tan((data[,10])*pi/180)))/180000),
fg = NULL,
bg = rgb(0, 1, 0, 0.18),
inches = F,
add = T)
I want to joint circles to plot them with the same "transparent" colour, is there some way to do this using R? Or is there any other alternative using R*?
*Please note: The maps am using are develped using R, and I can't use other program to develop them.
There's no simple way, since you're plotting a series of circles. If you don't demand the fill color be consistent, you could set the alpha value to a very small level. To get a consistent fill color, you'll have to calculate the intersection areas of the circles and plot those areas as well as the nonintersection areas (instead of plotting circles). If you have multiple overlapping circles, you can see that will become a computational nightmare.
My personal recommendation is to plot with the smallest visible alpha value so that the worst-case overlap area doesn't obscure the map. This has the side-effect of clearly indicating the density of overlap areas.

Resources