I am using ggplot2(), plotly, and onRender() from htmlWidgets.
Basically, I have a scatterplot with 20 black points. When the user selects (Using, say “Box select” from plotly) a subset of these points, they become red. For the most part, this seems to be working correctly.
However, I notice that if the user selects over points that have already become red (i.e. selects a point that they have already selected before), then other black points in the scatterplot that were not selected accidentally become red.
I am not sure, but I suspect the issue is from the fact that when a user selects a point, I simply overlay a new point in red on top of it (so it appears the point become red). So, when the user reselects a red point, they are actually selecting >1 points (the red point on top and the black original point beneath it).
I am hoping one way to solve this is to force the red points (made in the Plotly.addTraces() function) to not be “selectable” by users. That way, when a user selects a red point, they will only be selecting the original black point beneath it, and in theory, a new red point will be overlaid (appearing like nothing changed to the user).
Is it possible to achieve this functionality? My MWE is below:
library(plotly)
library(GGally)
library(htmlwidgets)
set.seed(1)
dat <- data.frame(ID = paste0(“ID”,sample(c(1:20),20)), A=rnorm(20), B=rnorm(20))
dat$ID <- as.character(dat$ID)
minVal = min(dat[,-1])
maxVal = max(dat[,-1])
p <- ggplot(data = dat, aes(x=A, y=B)) + coord_cartesian(xlim = c(minVal, maxVal), ylim = c(minVal, maxVal))
ggPS <- ggplotly§
myLength <- length(ggPS[[“x”]][[“data”]])
for (i in 1:myLength){
item =ggPS[[“x”]][[“data”]][[i]]$text[1]
if (!is.null(item))
if (!startsWith(item, “co”)){
ggPS[[“x”]][[“data”]][[i]]$hoverinfo <- “none”
}
}
ggPS %>% onRender("
function(el, x, data) {
var Points = [];
var Traces = [];
var selRows = [];
data.dat.forEach(function(row){selRows.push(row);})
var xArr = [];
var yArr = [];
var keepIndex = [];
for (a=0; a<selRows.length; a++){
xArr.push(selRows[a]['A'])
yArr.push(selRows[a]['B'])
keepIndex.push(selRows[a]['ID'])
}
Points.push(keepIndex);
var tracePoints = {
x: xArr,
y: yArr,
hoverinfo: 'none',
mode: 'markers',
marker: {
color: 'black',
size: 4
}
};
Traces.push(tracePoints);
Plotly.addTraces(el.id, Traces);
var idRows = []
for (a=0; a<data.dat.length; a++){
idRows.push(data.dat[a]['ID'])
}
el.on('plotly_selected', function(e) {
numSel = e.points.length
cN = e.points[0].curveNumber;
var pointNumbers = [];
var selData = [];
for (a=0; a<numSel; a++){
pointNumbers.push(e.points[a].pointNumber)
selData.push(data.dat[idRows.indexOf(Points[0][pointNumbers[a]])])
}
var Traces = [];
var xArr = [];
var yArr = [];
for (a=0; a<selData.length; a++){
xArr.push(selData[a]['A'])
yArr.push(selData[a]['B'])
}
var trace = {
x: xArr,
y: yArr,
mode: 'markers',
marker: {
color: 'red',
size: 4
},
hoverinfo: 'none'
};
Traces.push(trace);
Plotly.addTraces(el.id, Traces);
})
}
", data = list(dat=dat))