I'm trying to do something seemingly simple: when the user clicks on a data point or select multiple points with lasso selection, I want to draw these points in a different colour. In order to do that, I look at what points are selected, and add a col
variable to the dataframe, and I tell the ggplot to colour the points according to that column.
It does work for the first selection. But whenever there are already selected points, selecting the next set of points doesn't work. I've added debug statements to see what data is returned from plotly, and it seems like it returns different pointNumber
and curveNumber
after the initial selection. I couldn't find any documentation about how these variables work and I'm not sure how to fix this issue.
Here's a GIF showing the issue
And here's code to reproduce:
library(plotly)
library(shiny)
ui <- fluidPage(
plotlyOutput("plot")
)
server <- function(input, output, session) {
output$plot <- renderPlotly({
click_data <- event_data("plotly_click", source = "select")
select_data <- event_data("plotly_selected", source = "select")
data <- mtcars
data$col <- "black"
if (!is.null(select_data)) {
cat(str(select_data))
idx <- select_data$pointNumber + 1
data[idx, "col"] <- "blue"
}
if (!is.null(click_data)) {
cat(str(click_data))
idx <- click_data$pointNumber + 1
data[idx, "col"] <- "red"
}
p <- ggplot(data, aes(mpg, wt, col = I(col))) + geom_point()
ggplotly(p, source = "select")
})
}
shinyApp(ui, server)
I've also been told that perhaps what I need to do is create my own row identifier and pass it to the key
aesthetic. I'm not sure what that means I tried defining key <- row.names(data)
and then passing key=key
to ggplot's aes(), but that didn't seem to change anything.
Carson Sievert answered my question on a gist
Here's the answer:
I know it seems counter-intuitive, but pointNumber isn't a reliable row identifier. Use a key variable like this:
library(plotly)
library(shiny)
mtcars$key <- row.names(mtcars)
mtcars$col <- "black"
ui <- fluidPage(
plotlyOutput("plot")
)
server <- function(input, output, session) {
output$plot <- renderPlotly({
click_data <- event_data("plotly_click")
select_data <- event_data("plotly_selected")
if (!is.null(select_data)) {
mtcars[mtcars$key %in% select_data$key, "col"] <- "blue"
}
if (!is.null(click_data)) {
mtcars[mtcars$key %in% click_data$key, "col"] <- "red"
}
p <- ggplot(mtcars, aes(mpg, wt, col = I(col), key = key)) +
geom_point()
ggplotly(p) %>% layout(dragmode = "lasso")
})
}
shinyApp(ui, server)
Here is the plot_ly
way, using the customdata
attribute:
library(plotly)
library(shiny)
mtcars$key <- row.names(mtcars)
mtcars$col <- "black"
ui <- fluidPage(
plotlyOutput("plot")
)
server <- function(input, output, session) {
output$plot <- renderPlotly({
click_data <- event_data("plotly_click", priority = "event")
select_data <- event_data("plotly_selected", priority = "event")
if (!is.null(select_data)) {
mtcars[mtcars$key %in% select_data$customdata, "col"] <- "blue"
}
if (!is.null(click_data)) {
mtcars[mtcars$key %in% click_data$customdata, "col"] <- "red"
}
p <- plot_ly(mtcars, x = ~mpg, y=~wt, colors = ~sort(unique(col)), color = ~col, customdata = ~key, type = "scatter", mode = "markers") %>% layout(dragmode = "lasso")
})
}
shinyApp(ui, server)
plot_ly
can also handle the key
argument in the same way. However, customdata
is the more official way:
The key attribute is only supported in shiny, but customdata is officially supported by plotly.js, and thus can also be used to attach meta-information to event
The documentation can be seen via:
library(listviewer)
schema(jsonedit = interactive())
Navigate: object ► traces ► scatter ► attributes ► customdata
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With