在R DT(数据表)中用斜体和红色字体格式化行向量

时间:2019-04-06 14:34:50

标签: r shiny datatables dt

与此问题有点类似:How to give color to a given interval of rows of a DT table?

但是在我的情况下,我想让用户选择表中的行,然后单击按钮取消选择行,然后将先前选择的行变成提交删除的行列表的一部分,将其变灰字体(颜色:浅灰色)和斜体。这表明这些将被排除在进一步分析之外。 其次,撤消整个选择的按钮应将所有行更改回正常格式

我已经记录了选定的行并添加了取消选择功能,但是在重置行之前重新设置行的样式会使我逃脱。...

我希望实现的

输出: enter image description here

不确定这是否是正确的方法,但我想同时使用 values$selected_rowsvalues$removed_rows,其中第一个保留选择直到提交,然后删除(保留),如果用户决定删除另一个提交的更多行,则被删除的行可能会被选择删除。

removed_rows也是需要设置样式的行的列表(以斜体显示为灰色)

library(shiny)
library(DT)


ui <- fluidPage(
    actionButton('SubmitRemoval', 'Exclude selected rows'),
    actionButton('UndoRemoval', 'Include full data'),
  verbatimTextOutput('Printresult'),
    DT::dataTableOutput('mytable')

)

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

  values <- reactiveValues()

  observe({
    values$selected_rows <- input$mytable_rows_selected
  })


  observeEvent(input$SubmitRemoval, { 
        values$removed_rows <- c(values$removed_rows,input$mytable_rows_selected)


    dataTableProxy('mytable') %>% selectRows(NULL)
    values$selected_rows <- NULL
    removeTab("tabs", "mytable")
    })

  Remaining_mtcars <- reactive({ 
    req( values$removed_rows)
    mtcarsR <- mtcars[-c(values$removed_rows), ]
    mtcarsR
    })

  output$Printresult <- renderText({ nrow(Remaining_mtcars()) })

  observeEvent(input$UndoRemoval, {
    values$removed_rows <- NULL

    })

  output$mytable <- DT::renderDataTable({
    DT::datatable(mtcars,  
                  extensions = c('Buttons', 'ColReorder', 'FixedHeader', 'Scroller'),
                  options = list(pageLength = 25,
                                 selection = c('multiple'),
                                 dom = 'frtipB'
    )
  )
  })
}
runApp(list(ui = ui, server = server))

更新 @SL:我试图将您的JavaScript函数移至嵌入式按钮的DT :: JS()部分内进行提交和撤消,但无法正常工作。我想我已经接近了,但是不知道问题出在哪里。

表输出代码将遵循以下结构:

 output[["mytable"]] <- renderDT({
    datatable(dat, 
              escape = -2, 
              extensions = c('Buttons', 'ColReorder', 'FixedHeader', 'Scroller'),
              callback = JS(callback),
              options = list(
                dom = 'frtipB',
                initComplete = JS(initComplete),
                rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(dat)),
                  list(className = "dt-center", targets = "_all")
                ),
                buttons = list('copy', 'csv',
                               list(
                                 extend = "collection",
                                 text = 'Deselect', 
                                 action = DT::JS("function ( e, dt, node, config ) {
                                       Shiny.setInputValue('SubmitRemoval', true, {priority: 'event'});
                                     }")
                                   ## move the submit javascript here
                                ),
                               list(
                                 extend = "collection",
                                 text = 'Restore', 
                                 action = DT::JS("function ( e, dt, node, config ) {
                                       Shiny.setInputValue('UndoRemoval', true, {priority: 'event'});
 ## move the undo removal javascript here
                                     }")
                               )
                )
              )
    )
  })

3 个答案:

答案 0 :(得分:1)

这是一个更好的解决方案(花了我几个小时)。单击此按钮不会重绘表格,按列对表格进行排序也不会出错。

library(shiny)
library(DT)

initComplete <- c(
  "function(settings) {",
  "  var table=settings.oInstance.api();", 
  "  $('#SubmitRemoval').on('click', function(){",
  "    table.$('tr.selected').addClass('x');",
  "  });",
  "  $('#UndoRemoval').on('click', function(){",
  "    table.$('tr').removeClass('x');",
  "  });",
  "}"
)

callback <- "
var xrows = [];
table.on('preDraw', function(e, settings) {
  var tbl = settings.oInstance.api();
  var nrows = tbl.rows().count();
  var rows = tbl.$('tr');
  var some = false; var r = 0;
  while(!some && r<nrows){
    if($(rows[r]).hasClass('x')){
      some = true
    }
    r++;
  }
  if(some){
    xrows = [];
    for(var i = 0; i < nrows; i++){
      if($(rows[i]).hasClass('x')){
        xrows.push(rows[i].getAttribute('id'));
      }
    }
  }
}).on('draw.dt', function(){
  for(var i=0; i<xrows.length; i++){
    var row = $('#' + xrows[i]);
    row.addClass('x');
  }
  xrows = [];
});
"

ui <- fluidPage(
  tags$head(
    tags$style(HTML(
      ".x { background-color: rgb(211,211,211) !important; font-style: italic}
       table.dataTable tr.selected.x td { background-color: rgb(211,211,211) !important;}"
    ))
  ),
  actionButton('SubmitRemoval', 'Exclude selected rows'),
  actionButton('UndoRemoval', 'Include full data'),
  br(),
  DTOutput('mytable')

)

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

  dat <- cbind(mtcars[1:6,], id=1:6)

  output[["mytable"]] <- renderDT({
    datatable(dat, 
              callback = JS(callback),
              options = list(
                initComplete = JS(initComplete),
                rowId = JS(sprintf("function(a){return a[%d];}", ncol(dat))), 
                columnDefs = list(list(visible=FALSE, targets=ncol(dat)))
              )
    )
  })

  proxy <- dataTableProxy("mytable")

  observeEvent(input[["UndoRemoval"]], { 
    proxy %>% selectRows(NULL)
  })

}

shinyApp(ui, server)

enter image description here

更新

以下是包含图标的版本:

library(shiny)
library(DT)

initComplete <- c(
  "function(settings) {",
  "  var table = settings.oInstance.api();", 
  "  var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'",
  "  var checkmark = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-ok\"></i></span>'",
  "  $('#SubmitRemoval').on('click', function(){",
  "    table.$('tr.selected').addClass('x');",
  "    table.$('tr.selected')",
  "      .each(function(){$(this).find('td').eq(1).html(cross);});",
  "  });",
  "  $('#UndoRemoval').on('click', function(){",
  "    table.$('tr').removeClass('x');",
  "    table.$('tr')",
  "      .each(function(i){$(this).find('td').eq(1).html(checkmark);});",
  "  });",
  "}"
)

callback <- "
var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'
var xrows = [];
table.on('preDraw', function(e, settings) {
  var tbl = settings.oInstance.api();
  var nrows = tbl.rows().count();
  var rows = tbl.$('tr');
  var some = false; var r = 0;
  while(!some && r<nrows){
    if($(rows[r]).hasClass('x')){
      some = true
    }
    r++;
  }
  if(some){
    xrows = [];
    for(var i = 0; i < nrows; i++){
      if($(rows[i]).hasClass('x')){
        xrows.push(rows[i].getAttribute('id'));
      }
    }
  }
}).on('draw.dt', function(){
  for(var i=0; i<xrows.length; i++){
    var row = $('#' + xrows[i]);
    row.addClass('x').find('td').eq(1).html(cross);
  }
  xrows = [];
});
"

ui <- fluidPage(
  tags$head(
    tags$style(HTML(
      ".x { background-color: rgb(211,211,211) !important; font-style: italic}
       table.dataTable tr.selected.x td { background-color: rgb(211,211,211) !important;}"
    ))
  ),
  actionButton('SubmitRemoval', 'Exclude selected rows'),
  actionButton('UndoRemoval', 'Include full data'),
  br(),
  DTOutput('mytable')

)

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

  dat <- cbind(Selected = '<span style="color:red; font-size:18px"><i class="glyphicon glyphicon-ok"></i></span>', 
               mtcars[1:6,], id = 1:6)

  output[["mytable"]] <- renderDT({
    datatable(dat, 
              escape = -2, 
              callback = JS(callback),
              options = list(
                initComplete = JS(initComplete),
                rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(dat)),
                  list(className = "dt-center", targets = "_all")
                )
              )
    )
  })

  proxy <- dataTableProxy("mytable")

  observeEvent(input[["UndoRemoval"]], { 
    proxy %>% selectRows(NULL)
  })

}

shinyApp(ui, server)

enter image description here

更新

要获取input$excludedRows中排除的行的索引:

initComplete <- c(
  "function(settings) {",
  "  var table = settings.oInstance.api();", 
  "  var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'",
  "  var checkmark = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-ok\"></i></span>'",
  "  $('#SubmitRemoval').on('click', function(){",
  "    table.$('tr.selected').addClass('x');",
  "    table.$('tr.selected')",
  "      .each(function(){$(this).find('td').eq(1).html(cross);});",
  "    var excludedRows = [];",
  "    table.$('tr').each(function(i, row){",
  "      if($(this).hasClass('x')){excludedRows.push(parseInt($(row).attr('id')));}",
  "    });",
  "    Shiny.setInputValue('excludedRows', excludedRows);",
  "  });",
  "  $('#UndoRemoval').on('click', function(){",
  "    table.$('tr').removeClass('x');",
  "    table.$('tr')",
  "      .each(function(i){$(this).find('td').eq(1).html(checkmark);});",
  "    Shiny.setInputValue('excludedRows', null);",
  "  });",
  "}"
)

更新

使用server = FALSE中的renderDT选项可以更容易:

library(shiny)
library(DT)

initComplete <- c(
  "function(settings) {",
  "  var table = settings.oInstance.api();", 
  "  $('#SubmitRemoval').on('click', function(){",
  "    table.$('tr.selected').addClass('x').each(function(){",
  "      var td = $(this).find('td').eq(1)[0];", 
  "      var cell = table.cell(td);", 
  "      cell.data('remove');",
  "    });",
  "    table.draw(false);",
  "    table.rows().deselect();",
  "    var excludedRows = [];",
  "    table.$('tr').each(function(i, row){",
  "      if($(this).hasClass('x')){excludedRows.push(parseInt($(row).attr('id')));}",
  "    });",
  "    Shiny.setInputValue('excludedRows', excludedRows);",
  "  });",
  "  $('#UndoRemoval').on('click', function(){",
  "    table.$('tr').removeClass('x').each(function(){",
  "      var td = $(this).find('td').eq(1)[0];", 
  "      var cell = table.cell(td);", 
  "      cell.data('ok');",
  "    });",
  "    Shiny.setInputValue('excludedRows', null);",
  "  });",
  "}"
)

render <- c(
  'function(data, type, row, meta){',
  '  if(type === "display"){',
  '    return "<span style=\\\"color:red; font-size:18px\\\"><i class=\\\"glyphicon glyphicon-" + data + "\\\"></i></span>";',
  '  } else {',
  '    return data;',
  '  }',
  '}'
)

ui <- fluidPage(
  tags$head(
    tags$style(HTML(
      ".x { color: rgb(211,211,211); font-style: italic; }"
    ))
  ),
  verbatimTextOutput("excludedRows"),
  actionButton('SubmitRemoval', 'Exclude selected rows'),
  actionButton('UndoRemoval', 'Include full data'),
  br(),
  DTOutput('mytable')
)

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

  dat <- cbind(Selected = "ok", mtcars[1:6,], id = 1:6)

  output[["mytable"]] <- renderDT({
    datatable(dat, 
              extensions = "Select",
              options = list(
                initComplete = JS(initComplete),
                rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(dat)),
                  list(className = "dt-center", targets = "_all"),
                  list(
                    targets = 1,
                    render = JS(render)
                  ) 
                )
              )
    )
  }, server = FALSE)

  proxy <- dataTableProxy("mytable")

  observeEvent(input[["UndoRemoval"]], { 
    proxy %>% selectRows(NULL)
  })

  output$excludedRows <- renderPrint({
    input[["excludedRows"]]
  })

}

shinyApp(ui, server)

答案 1 :(得分:0)

这是尝试。

library(shiny)
library(DT)

rowCallback <- function(rows){
  c(
    "function(row, data, num, index){",
    sprintf("  var rows = [%s];", paste0(rows-1, collapse = ",")),
    "  if(rows.indexOf(index) > -1){",
    "    for(var i=1; i<data.length; i++){",
    "      $('td:eq('+i+')', row)",
    "        .css({'background-color': 'rgb(211,211,211)', 'font-style': 'italic'});",
    "    }",
    "  }",
    "}"  
  )
}

ui <- fluidPage(
  actionButton('SubmitRemoval', 'Exclude selected rows'),
  actionButton('UndoRemoval', 'Include full data'),
  br(),
  DTOutput('mytable')

)

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

  output[["mytable"]] <- renderDT({
    input[["SubmitRemoval"]]
    input[["UndoRemoval"]]
    rows <- isolate(input[["mytable_rows_selected"]])
    datatable(mtcars, 
              options = list(
                rowCallback = JS(rowCallback(rows))
              )
    )
  })

  proxy <- dataTableProxy("mytable")

  observeEvent(input[["UndoRemoval"]], { 
    proxy %>% selectRows(NULL)
  })

}

shinyApp(ui, server)

enter image description here

答案 2 :(得分:0)

这是一个变体。用户无需单击按钮即可将选定的行标记为已删除,而是单击图标。

library(shiny)
library(DT)

callback <- c(
  "table.on('click', 'td:nth-child(2)', function(){",
  "  var td = this;",
  "  var cell = table.cell(td);",
  "  if(cell.data() === 'ok'){",
  "    cell.data('remove');",
  "  } else {",
  "    cell.data('ok');",
  "  }",
  "  var $row = $(td).closest('tr');",
  "  $row.toggleClass('excluded');",
  "  var excludedRows = [];",
  "  table.$('tr').each(function(i, row){",
  "    if($(this).hasClass('excluded')){",
  "      excludedRows.push(parseInt($(row).attr('id')));",
  "    }",
  "  });",
  "  Shiny.setInputValue('excludedRows', excludedRows);",
  "})"
)

restore <- c(
  "function(e, table, node, config) {",
  "  table.$('tr').removeClass('excluded').each(function(){",
  "    var td = $(this).find('td').eq(1)[0];", 
  "    var cell = table.cell(td);", 
  "    cell.data('ok');",
  "  });",
  "  Shiny.setInputValue('excludedRows', null);",
  "}"
)

render <- c(
  'function(data, type, row, meta){',
  '  if(type === "display"){',
  '    return "<span style=\\\"color:red; font-size:18px\\\"><i class=\\\"glyphicon glyphicon-" + data + "\\\"></i></span>";',
  '  } else {',
  '    return data;',
  '  }',
  '}'
)

ui <- fluidPage(
  tags$head(
    tags$style(HTML(
      ".excluded { color: rgb(211,211,211); font-style: italic; }"
    ))
  ),
  fluidRow(
    column(
      6, 
      tags$label("Excluded rows"),
      verbatimTextOutput("excludedRows")
    ),
    column(
      6, 
      tags$label("Included rows"),
      verbatimTextOutput("includedRows")
    )
  ),
  br(),
  DTOutput('mytable')
)

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

  dat <- cbind(Selected = "ok", mtcars[1:6,], id = 1:6)

  output[["mytable"]] <- renderDT({
    datatable(dat, 
              extensions = c("Select", "Buttons"), 
              selection = "none", 
              callback = JS(callback),
              options = list(
                rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(dat)),
                  list(className = "dt-center", targets = "_all"),
                  list(className = "notselectable", targets = 1),
                  list(targets = 1, render = JS(render)) 
                ),
                dom = "Bt",
                buttons = list("copy", "csv",
                               list(
                                 extend = "collection",
                                 text = 'Select all rows', 
                                 action = JS(restore)
                               )
                ),
                select = list(style = "single", selector = "td:not(.notselectable)")
              )
    )
  }, server = FALSE)

    output$excludedRows <- renderPrint({
      input[["excludedRows"]]
    })

    output$includedRows <- renderPrint({
      setdiff(1:nrow(dat), input[["excludedRows"]])
    })

}

shinyApp(ui, server)

enter image description here