【问题标题】:R package DT - how to highlight maximum per rowR包DT - 如何突出显示每行的最大值
【发布时间】:2017-09-17 05:49:18
【问题描述】:

在 R 中使用 DT 包,我想突出显示每行的最大/最小值,用于数字数据帧。

假设我们用 6 个集群构建了分割,然后我们想用描述性变量来描述这些集群:

library(DT)
library(tidyverse)
df <- iris[1:6, 1:4] %>% t()
(df)

#                1   2   3   4   5   6
# Sepal.Length 5.1 4.9 4.7 4.6 5.0 5.4
# Sepal.Width  3.5 3.0 3.2 3.1 3.6 3.9
# Petal.Length 1.4 1.4 1.3 1.5 1.4 1.7
# Petal.Width  0.2 0.2 0.2 0.2 0.2 0.4

我们希望可视化哪些集群具有最高的 Sepal.Length,哪些集群具有最高的 Sepal.Width,等等。解决方案将是每行的颜色最大值。

如果我使用 DT 包的 formatStyle() 函数,我可以按列(突出最大值,根据特定间隔的颜色值,...) ,但我不能每行都这样做。即使我使用参数target = 'row',整个行也会被着色,而不仅仅是最大值或我想要的单元格。

df %>% datatable() %>% 
   formatStyle('1', background = styleEqual(max(df[,1]), 'green'))

另一种方法是转换我的数据框的行和列,但我更喜欢使用 50 行和 5 列的数据框,而不是名称很长的 5 行和 50 列的数据框。

提前感谢您的帮助和建议。

【问题讨论】:

    标签: r dt


    【解决方案1】:

    为此,您需要一个自定义的 rowCallback 函数。这是一个例子:

    iris[1:6, 1:4] %>% datatable(options=list(rowCallback = JS(
      'function(row, data) {
        var num_data = data.slice(1,data.length)
        var row_max = Math.max.apply(Math,num_data);
        var row_min = Math.min.apply(Math,num_data);
        for(i=1;i < data.length; i++) {
          if(data[i]==row_max) {
            $("td:eq("+i+")", row).css("background-color", "green")
          } else if(data[i]==row_min) {
            $("td:eq("+i+")", row).css("background-color", "yellow")
          }
        }
      }')))
    

    请注意,您需要过滤掉 num_data 中的所有文本列,包括具有行名的第一个列。

    如果要突出显示第二高的值,可以对num_data 进行排序,并将 JS 代码中的 if/else 调整为您想要的颜色。对num_data 排序后,num_data[num_data.length-1] 是最大值,num_data[0] 是最小值,num_data[num_data.length-2]` 是第二个最大值,以此类推。

    iris[1:6, 1:4] %>% datatable(options=list(rowCallback = JS(
      'function(row, data) {
        var num_data = data.slice(1,data.length)
        num_data.sort(function (a, b) {  return a - b;  });
        for(i=1;i < data.length; i++) {
        if(data[i]==num_data[num_data.length-1]) {
          $("td:eq("+i+")", row).css("background-color", "green")
        } else if(data[i]==num_data[0]) {
          $("td:eq("+i+")", row).css("background-color", "yellow")
        } else if(data[i]==num_data[num_data.length-2]) {
          $("td:eq("+i+")", row).css("background-color", "orange")
        }
        }
      }')))
    

    【讨论】:

    • 有趣,我从没想过只将选择的列和行传递给 dplyr
    • 谢谢@NicE,真的很有帮助!我有关于 JS() 部分的评论(它是 javascript 代码吗?),如果我还想突出显示第二高的值(除了最大值),我想我可以添加类似 var row_max2 = Math ..... 的内容。也许有一个排序函数,比如Math.sort.apply(Math, num_data)[2]
    • 我编辑了,如果你没有太多的列和行,你可以对num_data进行排序并使用if/else中的任何值来为javascript中的单元格着色。
    • 再次感谢您。我不知道我是否仍然可以在这里询问有关 javascript 的问题,但不是使用只有开始和结束索引列的切片函数var num_data = data.slice(1,data.length),而是有一个替代函数可以选择列数(例如实例列 1、2、4、5 和 8) ?
    【解决方案2】:

    @NicE 的回答是正确的,很棒。他提到需要从数据中过滤掉任何文本列,在我的用例中,我确实将文本与数字混合在一起,所以我想提供一个基于他的解决方案,但也增加了额外的步骤,以防有人将来需要它:

    library(shiny)
    
    ui <- fluidPage(
      actionButton("reset", "New data"),
      DT::DTOutput("table")
    )
    
    server <- function(input, output, session) {
      output$table <- DT::renderDT({
        input$reset
    
        df <- data.frame(
          a = sample(letters, 5),
          b = runif(5),
          c = runif(5),
          d = sample(letters, 5),
          e = runif(5),
          f = runif(5)
        )
    
        DT::datatable(df, options = list(rowCallback = DT::JS(
          'function(row, data) {
            function filterNumbersFromArray(arr) {
              arr = arr.filter((item) => {
                return (typeof item == "number")
              })
              return arr;
            }
            var num_data = filterNumbersFromArray(data);
            var row_max = Math.max.apply(Math, num_data);
            var row_min = Math.min.apply(Math, num_data);
            for(i = 1; i < data.length; i++) {
              if(data[i] == row_max) {
                $("td:eq(" + i + ")", row).css("background-color", "lightgreen");
              } else if(data[i] == row_min) {
                $("td:eq(" + i + ")", row).css("background-color", "lightblue");
              }
            }
          }')))
      })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

      猜你喜欢
      • 2022-11-22
      • 1970-01-01
      • 2021-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 2021-10-04
      • 1970-01-01
      相关资源
      最近更新 更多