【问题标题】:Clear event_data from plotly select after processing it处理后从 plotly select 中清除 event_data
【发布时间】:2019-10-18 08:26:41
【问题描述】:

在下面的虚拟应用程序中,用户可以通过拖动一个区域围绕 1 个或多个点来选择/取消选择点。 这导致将这些点的状态更改为从 data.table 中的 T F 翻转。

我现在要解决的是,处理完event_data后如何清空,

或者至少确保用户可以连续两次选择同一组点。

即:现在,选择底部的三个点会将它们变成十字, 选择相同的三个点并打算将它们转回圆形当前不起作用,因为 event_data 与先前的选择相同。

我以为我可以让它工作,但事实证明我没有。

Plotly 允许通过双击清除事件数据,但我希望通过代码中的自动功能来实现相同的效果,以便在处理后立即清除它。 我也尝试使用这个解决方案来处理点击事件,但我无法让它为我的选择事件工作HERE

  useShinyjs(),

    extendShinyjs(text = "shinyjs.resetSelect = function() { Shiny.onInputChange('.clientValue-plotly_click-A', 'null'); }"),

在用户界面和js$resetSelect()在服务器块中

GIF 显示了在拖动选择操作之间双击和不双击的行为之间的差异。

library(shiny)
library(plotly)
library(dplyr)
library(data.table)

testDF <- data.table( MeanDecreaseAccuracy =  runif(10, min = 0, max = 1), Variables = letters[1:10])
testDF$Selected <- T

ui <- fluidPage(
  plotlyOutput('RFAcc_FP1',  width = 450)
)

server <- function(input, output, session) {

  values <- reactiveValues(RFImp_FP1 = testDF)

  observe({
    if(!is.null( values$RFImp_FP1)) {
      values$Selected <- event_data("plotly_selected", source = 'RFAcc_FP1')$y
    }
  })


  observeEvent(values$Selected, {
    parsToChange <- event_data("plotly_selected", source = 'RFAcc_FP1')$y
    if(!is.null(event_data("plotly_selected", source = 'RFAcc_FP1'))){
      data_df <- values$RFImp_FP1
      data_df <- data_df %>% .[, Selected := if_else(Variables %in% parsToChange, !Selected, Selected)]
      values$RFImp_FP1 <- NULL
      values$RFImp_FP1 <- data_df
    }

  })


  output$RFAcc_FP1 <- renderPlotly({

    RFImp_score <- values$RFImp_FP1[order(MeanDecreaseAccuracy)]
    plotheight <- length(RFImp_score$Variables) * 80
    colors <- if(length(unique(RFImp_score$Selected)) > 1) { c('#F0F0F0', '#1b73c1') } else { '#1b73c1' }
    symbols <- if(length(unique(RFImp_score$Selected)) > 1) {  c('x', 'circle') } else { 'circle' }    

    p <- plot_ly(data = RFImp_score,
                 source = 'RFAcc_FP1',
                 height = plotheight,
                 width = 450)  %>%
      add_trace(x = RFImp_score$MeanDecreaseAccuracy,
                y = RFImp_score$Variables,
                type = 'scatter',
                mode = 'markers',
                color = factor(RFImp_score$Selected),
                colors = colors,
                symbol = factor(RFImp_score$Selected),
                symbols = symbols,
                marker = list(size  = 6),
                hoverinfo = "text",
                text = ~paste ('<br>', 'Parameter: ', RFImp_score$Variables,
                               '<br>',  'Mean decrease accuracy: ', format(round(RFImp_score$MeanDecreaseAccuracy*100, digits = 2), nsmall = 2),'%',
                               sep = '')) %>%
      layout(
        margin = list(l = 160, r= 20, b = 70, t = 50),
        hoverlabel = list(font=list( color = '#1b73c1'), bgcolor='#f7fbff'),
        xaxis =  list(title = 'Mean decrease accuracy index (%)',
                      tickformat = "%",
                      showgrid = F,
                      showline = T,
                      zeroline = F,
                      nticks = 5,
                      font = list(size = 8),
                      ticks = "outside",
                      ticklen = 5,
                      tickwidth = 2,
                      tickcolor = toRGB("black")
        ),
        yaxis =  list(categoryarray = RFImp_score$Variables,
                      autorange = T,
                      showgrid = F,
                      showline = T,
                      autotick = T,
                      font = list(size = 8),
                      ticks = "outside",
                      ticklen = 5,
                      tickwidth = 2,
                      tickcolor = toRGB("black")
        ),
        dragmode =  "select"
      ) %>%  add_annotations(x = 0.5,
                             y = 1.05,
                             textangle = 0,
                             font = list(size = 14,
                                         color = 'black'),
                             text = "Contribution to accuracy",
                             showarrow = F,
                             xref='paper',
                             yref='paper')

    p <- p %>% config(displayModeBar = F)
    p
  })


}
shinyApp(ui, server)

【问题讨论】:

  • 附注我正在使用最新的 plotly 包 4.9.0,它与以前的版本相比有很大的不同。
  • 这个例子远非最小。请花更多时间来压缩代码。它使您更容易理解您的问题。
  • 很公平。我可能应该删除情节,但我认为这不是问题,因为情节的代码不是问题的一部分。我找到了另一种解决方案,通过反转跟踪分配,使“选定 = F”点变为跟踪 1,原始/选定 = T 是跟踪 0 颜色 = ~factor(!Selected),颜色 = 颜色,符号 = ~factor( !Selected),符号 = 符号,

标签: javascript r shiny plotly r-plotly


【解决方案1】:

请检查以下内容:

library(shiny)
library(plotly)
library(data.table)

testDF <- data.table(MeanDecreaseAccuracy =  runif(10, min = 0, max = 1), Variables = letters[1:10], Selected = TRUE)
setorder(testDF, MeanDecreaseAccuracy)

ui <- fluidPage(
  plotlyOutput('RFAcc_FP1',  width = 450)
)

server <- function(input, output, session) {

  RFImp_score <- reactive({
    eventData <- event_data("plotly_selected", source = 'RFAcc_FP1_source', session)
    parsToChange <- eventData$y
    testDF[Variables %in% parsToChange, Selected := !Selected]
    testDF
  })

  output$RFAcc_FP1 <- renderPlotly({
    req(RFImp_score())
    plotheight <- length(RFImp_score()$Variables) * 80

    colors <- if (length(unique(RFImp_score()$Selected)) > 1) {
      c('#F0F0F0', '#1b73c1')
    } else {
      if (unique(RFImp_score()$Selected)) {
        '#1b73c1'
      } else {
        '#F0F0F0'
      }
    }

    symbols <-
      if (length(unique(RFImp_score()$Selected)) > 1) {
        c('x', 'circle')
      } else {
        if (unique(RFImp_score()$Selected)) {
          'circle'
        } else {
          'x'
        }
      }

    p <- plot_ly(data = RFImp_score(),
                 source = 'RFAcc_FP1_source',
                 height = plotheight,
                 width = 450) %>%
      add_trace(x = ~MeanDecreaseAccuracy,
                y = ~Variables,
                type = 'scatter',
                mode = 'markers',
                color = ~factor(Selected),
                colors = colors,
                symbol = ~factor(Selected),
                symbols = symbols,
                marker = list(size  = 6),
                hoverinfo = "text",
                text = ~paste('<br>', 'Parameter: ', ~Variables,
                              '<br>',  'Mean decrease accuracy: ', format(round(MeanDecreaseAccuracy*100, digits = 2), nsmall = 2),'%',
                              sep = '')) %>%
      layout(
        margin = list(l = 160, r= 20, b = 70, t = 50),
        hoverlabel = list(font=list( color = '#1b73c1'), bgcolor='#f7fbff'),
        xaxis =  list(title = 'Mean decrease accuracy index (%)',
                      tickformat = "%",
                      showgrid = F,
                      showline = T,
                      zeroline = F,
                      nticks = 5,
                      font = list(size = 8),
                      ticks = "outside",
                      ticklen = 5,
                      tickwidth = 2,
                      tickcolor = toRGB("black")
        ),
        yaxis =  list(categoryarray = ~Variables,
                      autorange = T,
                      showgrid = F,
                      showline = T,
                      autotick = T,
                      font = list(size = 8),
                      ticks = "outside",
                      ticklen = 5,
                      tickwidth = 2,
                      tickcolor = toRGB("black")
        ),
        dragmode =  "select"
      ) %>%  add_annotations(x = 0.5,
                             y = 1.05,
                             textangle = 0,
                             font = list(size = 14,
                                         color = 'black'),
                             text = "Contribution to accuracy",
                             showarrow = F,
                             xref='paper',
                             yref='paper')

    p <- p %>% config(displayModeBar = F)
    p
  })


}
shinyApp(ui, server)

结果:

【讨论】:

  • 感谢 ismirsehregal 的回答。我找到了另一种解决方案,而无需切换到响应式,我在下面解释这在 lapply 方法中一次为多个地块构建此代码有点麻烦。
  • @Mark,在reactiveValues 上使用reactive 只是为了降低示例的复杂性(这不是说明问题所必需的)。如需更多动力,请参阅this
  • 刚刚再次更新了我的答案。关于您的初始代码的逻辑,似乎只是缺少颜色和符号的 if 语句(为了完整起见)。
【解决方案2】:

通常反应式方法可能更好,但由于我的原因,我选择坚持观察

 lapply(plotlist, function(THEPLOT) {
values[[paste('RFImp', THEPLOT, sep = '')]]   #..... etc
#......
})

最后我设法通过反转跟踪顺序来解决问题以实现所需的行为。 通过设置selected == TcurveNumber 0selected == FcurveNumber 1,每次进行相同的选择并反转时,event_data

之间切换
  curveNumber pointNumber         x y
1           0           0 0.3389429 g
2           0           1 0.3872325 j

  curveNumber pointNumber         x y
1           1           0 0.3389429 g
2           1           1 0.3872325 j

这是通过!前面的颜色和符号语句实现的:

                mode = 'markers',
                color = ~factor(!Selected), 
                colors = colors,
                symbol = ~factor(!Selected), 

if(!is.null( values$RFImp_FP1)) { ...} 语句导致observe({...}) 触发两次,但这没有进一步的含义,因为 values$Selected 仅在第一次更改。如果没有此语句,如果绘图不在您打开的第一页上(即在另一个选项卡或下拉按钮上),新的 Plotly 版本会导致应用程序抛出以下错误

警告:“plotly_selected”事件绑定了“RFAcc_FP1”的源 ID 未注册。为了获取此事件数据,请添加 event_register(p, 'plotly_selected') 到你想要的情节 (p) 从中获取事件数据。

正在运行的应用程序:

library(shiny)
library(plotly)
library(dplyr)
library(data.table)

testDF <- data.table( MeanDecreaseAccuracy =  runif(10, min = 0, max = 1), Variables = letters[1:10])
testDF$Selected <- T

ui <- fluidPage(
  plotlyOutput('RFAcc_FP1',  width = 450)
)

server <- function(input, output, session) {

  values <- reactiveValues(RFImp_FP1 = testDF)

  observe({

      values$Selected <- event_data("plotly_selected", source = 'RFAcc_FP1')

  })


  observeEvent(values$Selected, {
    parsToChange <- event_data("plotly_selected", source = 'RFAcc_FP1')$y
    if(!is.null(event_data("plotly_selected", source = 'RFAcc_FP1'))){
      data_df <- values$RFImp_FP1
      data_df[Variables %in% parsToChange, Selected := !Selected]
      values$RFImp_FP1 <- NULL
      values$RFImp_FP1 <- data_df
    }

  })


  output$RFAcc_FP1 <- renderPlotly({

    RFImp_score <- values$RFImp_FP1[order(MeanDecreaseAccuracy)]
    plotheight <- length(RFImp_score$Variables) * 80
    colors <- if(length(unique(RFImp_score$Selected)) > 1) { c( '#1b73c1', '#F0F0F0') } else { '#1b73c1' }
    symbols <- if(length(unique(RFImp_score$Selected)) > 1) {  c( 'circle', 'x') } else { 'circle' }    

    p <- plot_ly(data = RFImp_score,
                 source = 'RFAcc_FP1',
                 height = plotheight,
                 width = 450)  %>%
      add_trace(x = RFImp_score$MeanDecreaseAccuracy,
                y = RFImp_score$Variables,
                type = 'scatter',
                mode = 'markers',
                color = ~factor(!Selected), 
                colors = colors,
                symbol = ~factor(!Selected), 
                symbols = symbols,
                marker = list(size  = 6),
                hoverinfo = "text",
                text = ~paste ('<br>', 'Parameter: ', RFImp_score$Variables,
                               '<br>',  'Mean decrease accuracy: ', format(round(RFImp_score$MeanDecreaseAccuracy*100, digits = 2), nsmall = 2),'%',
                               sep = '')) %>%
      layout(
        margin = list(l = 160, r= 20, b = 70, t = 50),
        hoverlabel = list(font=list( color = '#1b73c1'), bgcolor='#f7fbff'),
        xaxis =  list(title = 'Mean decrease accuracy index (%)',
                      tickformat = "%",
                      showgrid = F,
                      showline = T,
                      zeroline = F,
                      nticks = 5,
                      font = list(size = 8),
                      ticks = "outside",
                      ticklen = 5,
                      tickwidth = 2,
                      tickcolor = toRGB("black")
        ),
        yaxis =  list(categoryarray = RFImp_score$Variables,
                      autorange = T,
                      showgrid = F,
                      showline = T,
                      autotick = T,
                      font = list(size = 8),
                      ticks = "outside",
                      ticklen = 5,
                      tickwidth = 2,
                      tickcolor = toRGB("black")
        ),
        dragmode =  "select"
      ) %>%  add_annotations(x = 0.5,
                             y = 1.05,
                             textangle = 0,
                             font = list(size = 14,
                                         color = 'black'),
                             text = "Contribution to accuracy",
                             showarrow = F,
                             xref='paper',
                             yref='paper')

    p <- p %>% config(displayModeBar = F)
    p
  })


}
shinyApp(ui, server)

【讨论】:

  • 也是解决这个问题的好方法!特别是以 lapply-approach 作为背景(我不知道这是在您的实际应用中使用的),使用 reactiveValues 当然更方便。
猜你喜欢
  • 2018-07-10
  • 2014-08-10
  • 2012-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多