我想创建一个可响应的数据框架,可以触发该数据框架以填充for循环的结果

时间:2019-04-10 18:53:31

标签: r shiny

基本上,我想使这个R图成为交互式的。 http://rblogbyjordan.com/posts/solving-a-differential-equation-numerically-with-r/

我在结果数据框中遇到了问题


output:html_document

runtime:shiny

library(shiny)
library(ggplot2)

定义应用程序的用户界面

ui <- fluidPage(# Application title
  titlePanel("Pendulum."),

  # Sidebar with a slider input for mass
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        "mass",
        "Mass:",
        min = 1,
        max = 50,
        value = 25
      ),
      sliderInput(
        "length",
        "Length:",
        min = 1,
        max = 50,
        value = 3
      ),
      sliderInput(
        "theta0",
        "Starting Theta:",
        min = 1,
        max = 180,
        value = 60
      ),
      sliderInput(
        "theta_dot0",
        "Starting Theta dot:",
        min = 0,
        max = 10,
        value = 0
      ),
      sliderInput(
        "time",
        "how long do you want to observe the pendulum:",
        min = 1,
        max = 30,
        value = 15
      )
    ),

    # Show a plot of the generated distribution
    mainPanel(plotOutput("linePlot"))
  ))

定义服务器逻辑

server <- function(input, output) {


  #constants 
  g <- 9.82 #Gravitational constant
  mu <- .1 # Mu represents the loss of energy due to air resistance+


  # reactive function that finds theta dub dot
  theta_dubdot <- reactive(function(theta, theta_dot) {
    return(-mu * theta_dot - (input$mass * g / input$length) * sin(theta)) 
  })

  # reactive function that finds theta 
  find_theta <- reactive(function(t.end) {
    theta <- input$theta0
    theta_dot <- input$theta_dot0
    delta.t <- .001
    for (t in seq(from = 0, to = t.end, by = delta.t)) {
      theta <- theta + theta_dot * delta.t
      theta_dot <- theta_dot + theta_dubdot()(theta, theta_dot) * delta.t 
    }
    return(theta)
  })

  # creating a data frame to hold the results
  rv <- reactiveValues(
          result = data.frame("t" = seq(0, input$time , .1),
               "theta" = seq(0, input$time , .1)))

  # fill the data frame with the results every time input$time is changed
  observeEvent(input$time,{
    index <- 0
    for (i in seq(0, input$time, .1)) {
      index <- index + 1
      rv$result()[index, ]$theta <- find_theta()(i) 
    }

  })


  output$linePlot <- renderPlot
  ({
    # draw the plot with the specified parameters
    ggplot(rv$result(), aes_string(t, theta * input$length)) +
      geom_line() +
      theme_dark() +
      xlab("time") +
      ylab("Theta * Length")  # creating the plot

  })
}

运行应用程序

shinyApp(ui = ui, server = server)

预期结果将是一个交互式绘图,该绘图会根据起始参数而改变

实际结果是一个错误:

Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
  59: stop
  58: .getReactiveEnvironment()$currentContext
  57: .subset2(x, "impl")$get
  56: $.reactivevalues
  50: server [#27]
Error in .getReactiveEnvironment()$currentContext() : 
  Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)

1 个答案:

答案 0 :(得分:0)

乔丹

我调试了您的代码,如下所示。有关我所做的修改,请参阅server.R中的注释。基本上,reactiveValues()只能采用静态值,因为它们是反应性源对象。因此,您的rv$result必须用reactive()来定义。有关更多详细信息,请参阅以下文档:https://shiny.rstudio.com/articles/reactivity-overview.html。希望这会有所帮助。

# Load required packages --------------------------------------------------
library(shiny)
library(ggplot2)

# Build ui.R --------------------------------------------------------------
defaultTime <- 1  ## Changed it to 1 for rapid debugging
ui <- fluidPage(# Application title
  titlePanel("Pendulum."),
  # Sidebar with a slider input for mass
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        "mass",
        "Mass:",
        min = 1,
        max = 50,
        value = 25
      ),
      sliderInput(
        "length",
        "Length:",
        min = 1,
        max = 50,
        value = 3
      ),
      sliderInput(
        "theta0",
        "Starting Theta:",
        min = 1,
        max = 180,
        value = 60
      ),
      sliderInput(
        "theta_dot0",
        "Starting Theta dot:",
        min = 0,
        max = 10,
        value = 0
      ),
      sliderInput(
        "time",
        "how long do you want to observe the pendulum:",
        min = 1,
        max = 30,
        value = defaultTime
      )
    ),

    # Show a plot of the generated distribution
    mainPanel(plotOutput("linePlot"))
  ))

# Build server.R ----------------------------------------------------------
server <- function(input, output) {
  #constants 
  g <- 9.82 #Gravitational constant
  mu <- .1 # Mu represents the loss of energy due to air resistance+

  # reactive function that finds theta dub dot
  theta_dubdot <- reactive(function(theta, theta_dot) {
    return(-mu * theta_dot - (input$mass * g / input$length) * sin(theta)) 
  })

  # reactive function that finds theta 
  find_theta <- reactive(function(t.end) {
    theta <- input$theta0
    theta_dot <- input$theta_dot0
    delta.t <- .001
    for (t in seq(from = 0, to = t.end, by = delta.t)) {
      theta <- theta + theta_dot * delta.t
      theta_dot <- theta_dot + theta_dubdot()(theta, theta_dot) * delta.t 
    }
    return(theta)
  })

  # creating a data frame to hold the results
  # rv <- reactiveValues(
  #   result = data.frame("t" = seq(0, input$time , .1),
  #                       "theta" = seq(0, input$time , .1)))

  # fill the data frame with the results every time input$time is changed
  # observeEvent(input$time,{
  #   index <- 0
  #   for (i in seq(0, input$time, .1)) {
  #     index <- index + 1
  #     rvResult()[index, ]$theta <- find_theta()(i) 
  #   }
  #   
  # }) 

  ### rv$result uses input$time so it needs to be reactive() not reactiveValues()
  rvResult <- reactive({
    req(input$time)
    outputDF <- data.frame("t" = seq(0, input$time , .1),
                           "theta" = seq(0, input$time , .1))
    index <- 0
    for (i in seq(0, input$time, .1)) {
      index <- index + 1
      computedTheta <- find_theta()(i)
      print(computedTheta)
      outputDF$theta[index] <- computedTheta 
    }
    return(outputDF)
  })

  output$linePlot <- renderPlot({
    print(rvResult())
    # draw the plot with the specified parameters
    ggplot(rvResult(), aes(t, theta * input$length)) +
      geom_line() +
      theme_dark() +
      xlab("time") +
      ylab("Theta * Length")  # creating the plot
  })
}

# Launch the Shiny app ----------------------------------------------------
shinyApp(ui = ui, server = server, options = list(launch.browser = TRUE))