【问题标题】:Shiny - elements are not being rendered once function is complete闪亮 - 一旦功能完成,元素就不会被渲染
【发布时间】:2022-08-05 00:10:14
【问题描述】:

我正在动态创建要插入fluidRow 的元素,我面临的问题是所有元素都被同时渲染。因此,它们不是在其renderUI 函数结束时渲染每个元素,而是一直等到最后一个renderUI 完成。因此,my_dataset 中有很多元素会使渲染变得非常缓慢。

我预计一旦显示print(str_glue(\'End: {i}\')),该元素就会被渲染。然而,情况并非如此,它一直在等待所有元素(包括那些在屏幕上不可见的元素)。

我尝试使用outputOptions(..., suspendWhenHidden = TRUE),但没有任何区别(正如预期的那样,因为这是默认设置)。

MWE

library(shiny)
library(shinydashboard)
library(dplyr)
library(tidyr)
library(purrr)
library(stringr)
library(shinycssloaders)

qtd <- 500

my_dataset <- data.frame(
  stringsAsFactors = F,
  Name = rep(\'Sample\', qtd),
  Value = runif(qtd)
)

ui <- function() {
  fluidPage(
    fluidRow(
      column(12, textInput(inputId = \'my_text_input\', label = NULL, placeholder = \'Search\', width = \'100%\')),
      uiOutput(\'custom_ui\')
    )
  )
}

server <- function(input, output, session) {
  output[[\'custom_ui\']] <- renderUI({
    filtered_dataset <- my_dataset %>%
      filter(grepl(input[[\'my_text_input\']], Name, ignore.case = T)) %>%
      arrange(Name)
    
    map(1:nrow(filtered_dataset), function(i) {
      item <- filtered_dataset[i,]
      custom_id <- str_glue(\'custom_id_{i}\')
      output[[custom_id]] <- renderUI({
        print(str_glue(\'Start: {i}\'))
        print(item)
        result <- box(
          width = 3,
          title = item$Name,
          item$Value
        )
        print(str_glue(\'End: {i}\'))
        result
      })
      
      column(width = 3, uiOutput(custom_id, style = \'height: 350px;\') %>% withSpinner(type = 6))
    })
  })
}


runApp(shinyApp(ui = ui, server = server), launch.browser = T)

  • 你没有给我们 MWE,所以很难确定,但是...renderUI 是一个函数。它只会在它包含的所有代码都执行后才返回。因此,在你看到一切之前,你什么都看不到。提高速度的选项: (1) 将数据集的构建移到 renderUI 之外。 (这是一个很好的做法,我怀疑你无论如何都必须这样做。) 2 由于你有效地复制相同的接口(具有不同的数据)定义一个模块来表示接口并创建多个实例的模块以显示不同的数据切割。
  • @Limey 我添加了一个 MWE

标签: r shiny shiny-server


【解决方案1】:

您所描述的是预期的行为。在所有计算完成之前,服务器不会向 UI 返回任何内容。

我看到你非常依赖renderUI。这往往会使 Shiny 应用程序变慢。当应用程序启动时,它必须加载,意识到它缺少部分 UI,请求服务器创建 UI - 然后服务器将为您的所有框创建 HTML 并在显示任何内容之前将它们发送到 UI。您应该尽量保持 UI 静态。

取决于您想要实现的目标,可能有很多不同的方法可以在没有renderUI 的情况下做到这一点。

下面是一个示例,其中框的 HTML 在 renderUI 之外创建。只要您不需要框中的输入控件或输出,这将起作用 - 因为它们需要自己的 ID。


library(shiny)
library(shinydashboard)
library(dplyr)
library(purrr)

qtd <- 500

my_dataset <- data.frame(
  stringsAsFactors = FALSE,
  Name = rep('Sample', qtd),
  Value = runif(qtd)
) %>%
  mutate(
    x = map2(
      Name,
      Value,
      ~column(
        width = 3,
        box(
          width = 3,
          title = .x,
          .y
        )
      )
    )
  )


ui <- function() {
  fluidPage(
    fluidRow(
      column(
        12,
        textInput(
          inputId = 'my_text_input',
          label = NULL,
          placeholder = 'Search',
          width = '100%'
        )
      ),
      uiOutput('custom_ui')
    )
  )
}

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

  # Only the filtering of the data is done inside `renderUI`
  output[['custom_ui']] <- renderUI({

    filtered_dataset <-
      my_dataset %>%
      filter(grepl(input[['my_text_input']], Name, ignore.case = TRUE)) %>%
      arrange(Name) %>%
      pull(x)

  })

}


runApp(shinyApp(ui = ui, server = server), launch.browser = TRUE)


最后我只想推荐 Hadley Wickham 的 this book。我认为在与 Shiny 合作之前阅读这本书(或这本书的部分内容)会让你的一切变得更轻松。

【讨论】:

  • 感谢您的回答和参考书,我会看看它!您的解决方案确实像我提出的 de MWE 的魅力,但不幸的是,对于我真正的问题,它没有 =/。就像您评论的那样,我确实有一些需要动态设置的输出,但不用担心!我已经找到了解决我的问题的方法 =) 。再次感谢您的宝贵时间!
【解决方案2】:

功能完成后,我的 Shiny 应用程序元素不会被渲染。我有一台带 2 个外接显示器的笔记本电脑。我在监视器 #1 上的 IDE 中进行 Shiny 开发。如果我在监视器 #1 上运行应用程序,则在主要计算(功能)完成后大约需要 20 秒才能完成渲染。如果我在笔记本电脑或显示器 #2 上运行应用程序,完成渲染大约需要 3 秒。

但是,这是应用程序最大化到全屏的时候。如果应用程序未最大化,无论显示如何(大约 3 秒),它都会快速呈现。

我只能在显示 IDE 的屏幕以外的屏幕上与应用程序交互,除非它没有最大化。我知道这听起来很奇怪,但我已经测试了很多次,这是唯一合乎逻辑的解决方案。为什么会这样,我有兴趣找出答案。

我也尝试过启用“在浏览器中打开”,它只会在大约 20 秒后呈现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 2012-12-24
    • 2021-06-19
    • 2011-04-18
    • 2017-07-13
    相关资源
    最近更新 更多