【问题标题】:How to show data summary by dotplot/barlpot in Rshiny on hover of cell value如何在单元格值悬停时在 R Shiny 中通过点图/箱线图显示数据摘要
【发布时间】:2023-03-11 19:02:02
【问题描述】:

我在 RShiny 中有一个数据表,如下所示。

ID  num_express dene    trans   a_dd_s.1    a_de_s.2    a_dd_s.3    a_de_s.4    a_de_s.5    a_dd_s.6    a_dd_s.100
id1 6   .   -1  2   5   0   7   1   2   9
id2 3   .   -1  6   2   0   1   0   0   0
id3 7   .   -1  3   8   6   12  10  12  9
id4 7   .   -1  3   14  4   10  17  22  10
id5 4   .   -1  0   8   0   4   0   4   4

实际数据表有 >1000 列。第二列中的值是a_dd_s.1到a_dd_s.100和b_dd_s.1到b_dd_s.100.....z_dd_s.1到z_dd_s.100列中值>0的列数。分隔符“_”之前的第一个字母对应于组。这里a,b,c....z 是组。

大量的列对用户导航/滚动数据表不灵活。因此,我只想在数据表中显示第 1-4 列。当在每一行中单击或悬停第二列中的值时,将 a_dd_s.1 到 z_dd_s.100 列中的数值数据显示为按组着色的条形图/点图。

这可以在 Shiny 中完成吗?如果是这样,有人可以帮忙。

【问题讨论】:

    标签: r plot shiny datatable


    【解决方案1】:

    这是第一个“onclick”方法,使用 dataTable 中的回调来提取我们所在的行 ID,然后在 observeEvent 语句中使用此 ID 到 filter 数据并在模式内创建一个图带有showModal(modalDialog()) 的页面。

    更新
    根据OP的cmets,我现在:

    1. 使用 {ggiraph} 向绘图添加显示变量名称和值的工具提示

    2. 添加的变量组 (a:c) 允许相应地为数据点着色

    3. 通过添加css 使模态页面更宽(modalDialog 有一个size 参数,但这里"l" 仍然不够大)。

    4. 为了显示变量名称,将图放大,但是,显示它们仍然很混乱(有超过 1000 个变量),所以我认为更好的选择是只显示工具提示和按组着色。

         library(shiny)
         library(DT)
         library(data.table)
         library(forcats)
         library(ggplot2)
         library(waiter)
         library(plotly)
      
      
         modalActionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {
      
           value <- restoreInput(id = inputId, default = NULL)
           tags$button(id = inputId, type = "button", style = if (!is.null(width)) 
             paste0("width: ", validateCssUnit(width), ";"), type = "button", 
             class = "btn btn-default action-button", `data-dismiss` = "modal", `data-val` = value, 
             list(shiny:::validateIcon(icon), label), ...)
      
         }
      
         # more realistic toy data which mimics your actual data
         # we will transform it later
         dat <- tibble::tribble(
           ~ID,  ~num_express, ~dene,    ~trans,
           "id1", 6,   ".",   -1,
           "id2", 3,   ".",   -1,
           "id3", 7,   ".",   -1,
           "id4", 7,   ".",   -1,
           "id5", 4,   ".",   -1) %>%
           tidyr::expand_grid(group = letters[1:3],
                              no = 1:100) %>%
           dplyr::mutate(var_nm = paste0(group, "_dd_s.", no),
                         var_val = round(runif(1500, min = 0, max = 99), 0)) %>%
           tidyr::pivot_wider(.,
                              id_cols = c(ID, num_express, dene, trans),
                              names_from = var_nm,
                              values_from = var_val)
      
         dat <- as.data.table(dat)
         # data preparation no using {data.table} starts here
         # before starting the data preparation with your real data
         # save it as .csv and it read in at the start of the app with
         # `dat <- fread("yourdata.csv")` 
         dat_dt <- dat[, -c(2:4), with=FALSE]
         dat_dt <- melt(dat_dt,
                        id.vars = "ID",
                        variable.name = "col_nm",
                        value.name = "val")
         dat_dt[, c("group", "col_nm1", "col_nm2", "col_no") := tstrsplit(col_nm, "[\\._]")
                ][,
                  ttip := paste0("var: ", col_nm, "<br>",
                                 "value: ", val)
                  ][,
                    col_nm := as.factor(col_nm)
                    ]
      
       shinyApp(
         ui = fluidPage(
           use_waiter(),
      
        # make modal page wider
           tags$head(
             tags$style(HTML("
      
          .modal-dialog {
             width: 80%;
          }
        "))
           ),
      
           DT::dataTableOutput('table')
      
         ), # close FluidPage
      
      
         server = function(input, output, session) {
      
           w <- Waiter$new(id = "plot",
                           html = spin_whirly(),
                           color = "#FFFFFF")
      
           output$table <- DT::renderDataTable({
             datatable(dat[, .(ID, num_express, dene, trans)],
                       rownames = FALSE,
                       selection = 'none',
                       # get ID of clicked row
                       callback = JS(
                         'table.on("click.dt","tr", function() {
                   var data=table.row(this).data();
                   Shiny.onInputChange("rows",data[0]);
                    });')
             )
             })
      
           data_row <- reactive({
      
             dat_dt[ID == input$rows & val != 0,]
      
           })
      
           flag <- reactiveValues(val = 0)
      
           observeEvent(input$close, {
      
             flag$val <- flag$val - 1
      
           })
      
           observeEvent(input$rows, {
      
             flag$val <- flag$val + 1
      
           })
      
           temp_plot <- reactive({
      
             w$show()
      
             if (flag$val == 0) {
      
               p <- plotly_empty() %>% config(displayModeBar = FALSE,
                                         displaylogo = FALSE)
      
             } else {
      
             p <- ggplot(data_row(),
                         aes(x = fct_reorder(col_nm, val, min, .desc = TRUE),
                             y = val,
                             fill = group
                         )) +
               geom_col(position = "dodge") +
               scale_y_continuous(expand = c(0,0)) +
               theme(axis.text.x = element_blank(),
                     axis.ticks.x = element_blank())
      
             p <- ggplotly(p)
      
             }
      
             w$hide()
      
             p
      
           })
      
           output$plot <- renderPlotly({
      
             print(flag$val)
      
             temp_plot()
      
           })
      
           observeEvent(input$rows, {
             showModal(modalDialog(
               title = paste("Plot:", input$rows),
               plotlyOutput("plot",
                            width = "100%"),
               size = "l",
               easyClose = FALSE,
               footer = modalActionButton("close",
                                          "Close")
             ))
           })
      
      
         }
       )
      

    【讨论】:

    • 它有效。但是,x 轴名称(“col_name”)是聚集的,并且对于具有约 1000 列的实际数据集不可见。将theme(axis.text.x=element_text(angle=90, hjust=1)) 添加到情节中不起作用。 1) 可以增加绘图大小以使 x 轴名称可见 2) 可以将绘图中的数据点悬停以查看“col_name” 3) 可以将点图着色为组,例如通过 a、b、 c 如果列的格式为 a.1,a.2,...a.10, b.1, b.2...b.9, c.1...c.10
    • @chas:我更新了我的答案,请看一下。它仍然有很多变量,因此我宁愿只显示工具提示和组颜色而不显示每个变量名称。
    • 我收到错误Warning: Expected 2 pieces. Additional pieces discarded in 635 rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...]. Warning in f(names[[col]]) : NAs introduced by coercion。这可能是由于实际的列名格式类似于 a_dd_s.1、a_dd_s.2 ......其中第一个“_”之前的第一个字母是这里的“a”组?
    • 其次,为了减少变量,是否可以从每一行中删除值=0的变量进行绘图。并按val 的值按降序绘制x = val,y = col_nm 和y 轴名称?这应该可以解决需求,因为数据集太大而无法进行更好的可视化。
    • @chas:是的,错误消息来自pivot_longer,可能是因为列名不同。我将通过您更新的问题进行调查。过滤和排序变量没问题,我稍后会发布更新。
    猜你喜欢
    • 1970-01-01
    • 2017-11-16
    • 2021-09-02
    • 2014-02-24
    • 2014-08-23
    • 2015-09-11
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多