Edit: The Plotly.plot()
function has been deprecated - now using Plotly.update()
instead:
First of all you can have multiple lasso selections in plotly via pressing shift
.
The following is a modification of my answer here - so it's plot_ly
/ plotlyProxy
based, modifying the existing plotly object (without re-rendering) not using ggplotly
. As there is some related work going on in a GitHub issue and PR the below answer might not be 100% reliable (e.g. zooming seems to mess things up - you might want to deactivate it) and may become obsolete.
Nevertheless, please check the following:
library(plotly)
library(shiny)
library(htmlwidgets)
ui <- fluidPage(
plotlyOutput("myPlot"),
verbatimTextOutput("click")
)
server <- function(input, output, session) {
js <- "
function(el, x){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
var d3 = Plotly.d3;
Plotly.update(id).then(attach);
function attach() {
gd.addEventListener('click', function(evt) {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var bb = evt.target.getBoundingClientRect();
var x = xaxis.p2d(evt.clientX - bb.left);
var y = yaxis.p2d(evt.clientY - bb.top);
var coordinates = [x, y];
Shiny.setInputValue('clickposition', coordinates);
});
gd.addEventListener('mousemove', function(evt) {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var bb = evt.target.getBoundingClientRect();
var x = xaxis.p2d(evt.clientX - bb.left);
var y = yaxis.p2d(evt.clientY - bb.top);
var coordinates = [x, y];
Shiny.setInputValue('mouseposition', coordinates);
});
};
}
"
output$myPlot <- renderPlotly({
plot_ly(type = "scatter", mode = "markers") %>% layout(
xaxis = list(range = c(0, 100)),
yaxis = list(range = c(0, 100))) %>%
onRender(js, data = "clickposition")
})
myPlotProxy <- plotlyProxy("myPlot", session)
followMouse <- reactiveVal(FALSE)
traceCount <- reactiveVal(0L)
observeEvent(input$clickposition, {
followMouse(!followMouse())
if(followMouse()){
plotlyProxyInvoke(myPlotProxy, "addTraces", list(x = list(input$clickposition[1]), y = list(input$clickposition[2])))
traceCount(traceCount()+1)
}
})
observe({
if(followMouse()){
plotlyProxyInvoke(myPlotProxy, "extendTraces", list(x = list(list(input$mouseposition[1])), y = list(list(input$mouseposition[2]))), list(traceCount()))
}
})
}
shinyApp(ui, server)

If you rather want to work with a single trace:
library(plotly)
library(shiny)
library(htmlwidgets)
ui <- fluidPage(
plotlyOutput("myPlot"),
verbatimTextOutput("click")
)
server <- function(input, output, session) {
js <- "
function(el, x){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
Plotly.update(id).then(attach);
function attach() {
gd.addEventListener('click', function(evt) {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var bb = evt.target.getBoundingClientRect();
var x = xaxis.p2d(evt.clientX - bb.left);
var y = yaxis.p2d(evt.clientY - bb.top);
var coordinates = [x, y];
Shiny.setInputValue('clickposition', coordinates);
});
gd.addEventListener('mousemove', function(evt) {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var bb = evt.target.getBoundingClientRect();
var x = xaxis.p2d(evt.clientX - bb.left);
var y = yaxis.p2d(evt.clientY - bb.top);
var coordinates = [x, y];
Shiny.setInputValue('mouseposition', coordinates);
});
};
}
"
output$myPlot <- renderPlotly({
plot_ly(type = "scatter", mode = "markers") %>% layout(
xaxis = list(range = c(0, 100)),
yaxis = list(range = c(0, 100))) %>%
onRender(js, data = "clickposition")
})
myPlotProxy <- plotlyProxy("myPlot", session)
followMouse <- reactiveVal(FALSE)
clickCount <- reactiveVal(0L)
observeEvent(input$clickposition, {
followMouse(!followMouse())
clickCount(clickCount()+1)
if(clickCount() == 1){
plotlyProxyInvoke(myPlotProxy, "addTraces", list(x = list(input$clickposition[1]), y = list(input$clickposition[2])))
}
})
observe({
if(followMouse()){
plotlyProxyInvoke(myPlotProxy, "extendTraces", list(x = list(list(input$mouseposition[1])), y = list(list(input$mouseposition[2]))), list(1))
} else {
plotlyProxyInvoke(myPlotProxy, "extendTraces", list(x = list(list(NA)), y = list(list(NA))), list(1))
}
})
}
shinyApp(ui, server)