问题
I am new to r-plotly and trying to figure out how to handle clicks which are not on the data. It seems that using event_data("plotly_click")
I get events that are on points from the data, but so far have not figured out how to do this for clicks which are not close to the data, but just on the white part of the plot.
Shiny click events from plots can do this and I just get the x and y of the click. I want similar, but for plotly plots.
Can I specify click events to be from anywhere on the plotly plot, not just on the data?
EDIT: Surprisingly this does not exist yet in plotly. See this feature request
https://github.com/plotly/plotly.js/issues/2696
https://github.com/ropensci/plotly/issues/1194
So until this feature is added, I guess my question is what options are there to do this? Seems like such a basic feature, that I hope someone with more knowledge of JavaScript/Shiny/Plotly has hacked into.
回答1:
Please check the following workaround based on this codepen I found via this question.
However, there is a small horizontal offset I couldn't get rid of so far - maybe someone knows how to fix it?
library(plotly)
library(shiny)
library(htmlwidgets)
ui <- fluidPage(
plotlyOutput("graph"),
verbatimTextOutput("click")
)
server <- function(input, output, session) {
js <- "
function(el, x, inputName){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
var d3 = Plotly.d3;
Plotly.plot(id).then(attach);
function attach() {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var l = gd._fullLayout.margin.l;
var t = gd._fullLayout.margin.t;
var coordinates = [null, null]
gd.addEventListener('click', function(evt) {
var coordinates = [xaxis.p2c(evt.x - l), yaxis.p2c(evt.y - t)];
Shiny.setInputValue(inputName, coordinates);
});
};
}
"
clickposition_history <- reactiveVal(data.frame(x = 1:10, y = 1:10))
observeEvent(input$clickposition, {
clickposition_history(rbind(clickposition_history(), input$clickposition))
})
output$graph <- renderPlotly({
plot_ly(clickposition_history(), x = ~x, y = ~y, type = "scatter", mode = "markers") %>%
onRender(js, data = "clickposition")
})
output$click <- renderPrint({
input$clickposition
})
}
shinyApp(ui, server)
Edit:
Here is the same approach using plotlyProxy
instead of re-rendering - the offset is even worse:
library(plotly)
library(shiny)
library(htmlwidgets)
ui <- fluidPage(
plotlyOutput("myPlot"),
verbatimTextOutput("click")
)
server <- function(input, output, session) {
js <- "
function(el, x, inputName){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
var d3 = Plotly.d3;
Plotly.plot(id).then(attach);
function attach() {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var l = gd._fullLayout.margin.l;
var t = gd._fullLayout.margin.t;
var coordinates = [null, null]
gd.addEventListener('click', function(evt) {
var coordinates = [xaxis.p2c(evt.x - l), yaxis.p2c(evt.y - t)];
Shiny.setInputValue(inputName, coordinates);
});
};
}
"
clickposition_history <- reactiveVal(data.frame(x = NA, y = NA))
observeEvent(input$clickposition, {
clickposition_history(rbind(clickposition_history(), input$clickposition))
})
output$myPlot <- renderPlotly({
plot_ly(data.frame(x = NA, y = NA), x = ~x, y = ~y, type = "scatter", mode = "markers") %>%
onRender(js, data = "clickposition")
})
myPlotProxy <- plotlyProxy("myPlot", session)
observe({
plotlyProxyInvoke(myPlotProxy, "restyle", list(x = list(clickposition_history()$x), y = list(clickposition_history()$y)))
})
output$click <- renderPrint({
clickposition_history()
})
}
shinyApp(ui, server)
Related GitHub issue and PR.
来源:https://stackoverflow.com/questions/56193127/plotly-click-events-from-anywhere-on-the-plot