R Shiny - 如何从反应函数内部的循环输出文本,该函数本身返回一个图形

时间:2022-03-24 01:50:30

I'm trying to create a Shiny version of a program.

我正在尝试创建一个程序的Shiny版本。

Currently, when an actionButton is pressed the program does some processing inside a loop, then outputs a graph. That works fine.

目前,当按下actionButton时,程序在循环内进行一些处理,然后输出图形。这很好。

What I'd like to do is have the processing loop create a block of HTML output that will change each iteration. Once complete the graph should be displayed.

我想要做的是让处理循环创建一个HTML输出块,它将改变每次迭代。完成后,应显示图表。

I've created simple skeleton code below to demonstrate what I'm trying to do. It fails to display any text, producing an error message saying:

我在下面创建了简单的框架代码来演示我正在尝试做什么。它无法显示任何文本,产生错误消息说:

Error in func() : object 'h' not found

func()出错:找不到对象'h'

Could someone please point me in the right direction?

有人可以指点我正确的方向吗?

Thank you.

app <- shinyApp(
  ui = fluidPage(
    fluidRow(  actionButton("go", "Go!") ),

    fluidRow(htmlOutput("html")),

    fluidRow(plotOutput('plot'))
 ),

server = function(input, output) {

  myPlot <- eventReactive(input$go, {

    for (i in 1:5){
      h <- HTML("some text to be displayed")

      cat(i) # outputs to the console, just for debugging

      Sys.sleep(1) # pause for 1 second
    }

    hist(runif(15))
  })

  output$html <- renderUI({ h }) # This doesn't produce any output

  output$plot <- renderPlot({ myPlot() }) # This displays a graph after the loop terminates
})


runApp(app)

1 个解决方案

#1


Your problem is that you're trying to output a variable that's changed within a reactive context. Those changes go out of scope. What you want is an observer, combined with isolate to achieve the same thing as eventReactive but with persisting variables.

您的问题是您正在尝试输出在被动上下文中更改的变量。这些变化超出了范围。你想要的是一个观察者,结合使用isolate来实现与eventReactive相同但具有持久变量的东西。

try this

app <- shinyApp(
  ui = fluidPage(
    fluidRow(  actionButton("go", "Go!") ),

    fluidRow(htmlOutput("html")),

    fluidRow(plotOutput('plot'))
  ),

  server = function(input, output) {
    theText <- reactiveValues(htmlVar = NULL)
    observe({
      input$go
      isolate({
        for (i in 1:5){
          theText$htmlVar <- HTML("some text to be displayed")

          cat(i) # outputs to the console, just for debugging

          Sys.sleep(.1) # pause for 100ms 
        }
      })
    })
    myPlot <- reactive({input$go
                        print("setting myPlot")
                        return (hist(runif(15)))
      })

    output$html <- renderUI({ theText$htmlVar }) 

    output$plot <- renderPlot({ return (myPlot()) }) # This displays a graph after the loop terminates
  })

runApp(app)

if you're changing the HTML output consistently in your actual program, you can replace the input$go in the myPlot reactive with theText$htmlVar, then order of the functions wouldn't matter, since the text change would trigger the graphing. Depends what you're actually going for.

如果你在实际程序中一致地改变HTML输出,你可以用myTelot $ htmlVar替换myPlot中的输入$ go,然后函数的顺序无关紧要,因为文本更改会触发图形。取决于你的实际目标。

#1


Your problem is that you're trying to output a variable that's changed within a reactive context. Those changes go out of scope. What you want is an observer, combined with isolate to achieve the same thing as eventReactive but with persisting variables.

您的问题是您正在尝试输出在被动上下文中更改的变量。这些变化超出了范围。你想要的是一个观察者,结合使用isolate来实现与eventReactive相同但具有持久变量的东西。

try this

app <- shinyApp(
  ui = fluidPage(
    fluidRow(  actionButton("go", "Go!") ),

    fluidRow(htmlOutput("html")),

    fluidRow(plotOutput('plot'))
  ),

  server = function(input, output) {
    theText <- reactiveValues(htmlVar = NULL)
    observe({
      input$go
      isolate({
        for (i in 1:5){
          theText$htmlVar <- HTML("some text to be displayed")

          cat(i) # outputs to the console, just for debugging

          Sys.sleep(.1) # pause for 100ms 
        }
      })
    })
    myPlot <- reactive({input$go
                        print("setting myPlot")
                        return (hist(runif(15)))
      })

    output$html <- renderUI({ theText$htmlVar }) 

    output$plot <- renderPlot({ return (myPlot()) }) # This displays a graph after the loop terminates
  })

runApp(app)

if you're changing the HTML output consistently in your actual program, you can replace the input$go in the myPlot reactive with theText$htmlVar, then order of the functions wouldn't matter, since the text change would trigger the graphing. Depends what you're actually going for.

如果你在实际程序中一致地改变HTML输出,你可以用myTelot $ htmlVar替换myPlot中的输入$ go,然后函数的顺序无关紧要,因为文本更改会触发图形。取决于你的实际目标。