【问题标题】:Reactive ggplot with reactive data frame in ShinyShiny中具有反应性数据框的反应性ggplot
【发布时间】:2020-06-29 06:13:49
【问题描述】:

这是我在here 发的帖子的后续帖子。最初的问题要求用户在一些文本框/数字框中输入一些值,计算一些函数,然后在数据框中显示结果。 可以使用以下 R 代码(其中还包括我还想添加的 ggplot2 图)来计算它。

R 代码:

someFunction <- function(S, K, type){
  
  # call option
  if(type=="C"){
    d1 <- S/K
    value <- S*pnorm(d1) - K*pnorm(d1)
    return(value)}
  
  # put option
  if(type=="P"){
    d1 <- S*K
    value <-  (K*pnorm(d1) - S*pnorm(d1))
    return(value)}
}


SInput <- 20
KInput <- 25
Seq <- seq(from = KInput - 1, to = KInput + 1, by = 0.25)

C <- someFunction(
  S = SInput,
  K = Seq,                                                  
  type = "C"
)

P <- someFunction(
  S = SInput,
  K = Seq,
  type = "P"
)

df <- data.frame(C, P, Seq)         # create the data frame for the ggplot and Shiny output


df %>%                              # plot that data frame
  ggplot(aes(x = Seq)) +
  geom_line(aes(y = C)) +
  geom_line(aes(y = P))

我想在 Shiny 中创建相同的 ggplot - 反应图。我拥有的闪亮代码如下。

library(shiny)
library(shinydashboard)

#######################################################################
############################### Functions #############################

someFunction <- function(S, K, type){
    
    # call option
    if(type=="C"){
        d1 <- S/K
        value <- S*pnorm(d1) - K*pnorm(d1)
        return(value)}
    
    # put option
    if(type=="P"){
        d1 <- S*K
        value <-  (K*pnorm(d1) - S*pnorm(d1))
        return(value)}
}


############################### Header ###############################
header <- dashboardHeader()

#######################################################################
############################### Sidebar ###############################
sidebar <- dashboardSidebar()

#######################################################################
############################### Body ##################################

body <- dashboardBody(
    fluidPage(
        numericInput("SInput", "Input S:", 10, min = 1, max = 100),
        numericInput("KInput", "Input K:", 10, min = 1, max = 100),
        tableOutput("S_K_Output")
    )
)

#######################################################################

ui <- dashboardPage(header, sidebar, body)

#######################################################################

server <- function(input, output) {
    output$S_K_Output <- renderTable({
        Seq <- seq(from = input$KInput - 1, to = input$KInput + 1, by = 0.25)    # create a sequence going from K-1 to K+1
        C <- someFunction(
            S = input$SInput,
            K = Seq,                                                    # Apply this sequence to the function
            type = "C"
        )
        P <- someFunction(
            S = input$SInput,
            K = Seq,
            type = "P"
        )
        data.frame(C, P, Seq)                                               # Extract the results and put side-by-side 
    })
}

shinyApp(ui, server)

上面的 Shiny 代码可用于生成表格,但我也想包含情节。我发现这很困难,因为上面的代码将结果输出到 renderTable({}) 函数中(即返回 HTML 表并简单地添加 ggplot 代码不起作用。)

我已经尝试renderPlot 并再次将以上所有代码从renderTable 粘贴到同一个函数中,但我不想重复不必要的计算。所以我的问题是如何将data.frame(C, P, Seq) 从两个不同的renderTablerenderPlot 导出为ggplot2 图形?我可以在代码的fluidPage 部分的tableOutput 下方添加tablePlot,但我无法获得结果。

【问题讨论】:

    标签: r shiny


    【解决方案1】:

    开始考虑依赖和消除冗余。也就是说,如果您正在创建某种数据,并且您甚至认为它将被多个“事物”使用,那么将其分解为“反应性数据”,然后依赖它在多个位置。

    哦,如果你想显示一个情节,你需要使用plotOutput

    与您之前的代码的更改:

    • 如果你想要一个情节,你需要添加一个plotOutput;
    • renderTable 中的代码转换为reactive 块,只计算数据,无需考虑如何显示或过滤它;
    • 重新添加renderTable来处理前面提到的块中创建的数据;
    • 添加renderPlot(与plotOutput配对);最后
    • 在绘图输出中添加了req(mydata()),这样如果数据为空或NULL(无论出于何种原因),绘图代码将不会触发。如果您对此有任何疑问,请参阅?req,或者它的配套功能validateneed

    请注意,当使用响应式数据时,您必须像调用函数一样调用它。因此,mydata 响应式数据块在称为mydata() 时使其数据可用于其他响应式组件。不要试图“查看”mydata(没有括号),它对你没有任何作用。

    library(shiny)
    library(shinydashboard)
    
    #######################################################################
    ############################### Functions #############################
    
    someFunction <- function(S, K, type){
        
        # call option
        if(type=="C"){
            d1 <- S/K
            value <- S*pnorm(d1) - K*pnorm(d1)
            return(value)}
        
        # put option
        if(type=="P"){
            d1 <- S*K
            value <-  (K*pnorm(d1) - S*pnorm(d1))
            return(value)}
    }
    
    
    ############################### Header ###############################
    header <- dashboardHeader()
    
    #######################################################################
    ############################### Sidebar ###############################
    sidebar <- dashboardSidebar()
    
    #######################################################################
    ############################### Body ##################################
    
    body <- dashboardBody(
        fluidPage(
            numericInput("SInput", "Input S:", 10, min = 1, max = 100),
            numericInput("KInput", "Input K:", 10, min = 1, max = 100),
            tableOutput("S_K_Output"),
            plotOutput("Plot_Output")
        )
    )
    
    #######################################################################
    
    ui <- dashboardPage(header, sidebar, body)
    
    #######################################################################
    
    server <- function(input, output) {
      mydata <- reactive({
        Seq <- seq(from = input$KInput - 1, to = input$KInput + 1, by = 0.25)    # create a sequence going from K-1 to K+1
        C <- someFunction(
          S = input$SInput,
          K = Seq,                                                    # Apply this sequence to the function
          type = "C"
        )
        P <- someFunction(
          S = input$SInput,
          K = Seq,
          type = "P"
        )
        data.frame(C, P, Seq)                                               # Extract the results and put side-by-side 
      })
      output$S_K_Output <- renderTable({ mydata() })
      output$Plot_Output <- renderPlot({
        req(mydata())
        # plot that data frame
        ggplot(mydata(), aes(x = Seq)) +
          geom_line(aes(y = C)) +
          geom_line(aes(y = P))
      })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 只是好奇(我为坦率而道歉),你有没有看过shiny.rstudio.com 的任何教程?您的一些代码表明您仍在学习反应性/依赖性的概念。我知道我经常需要通过尝试/打破/修复/做来学习,所以我可以与工作流程相关联,但其中大部分内容(例如)在他们的反应性课程(writtenvideo)中涵盖。
    • 是的,我目前正在阅读教程。我没有阅读您指出的书面教程,但我已经阅读了视频和其他一些在线教程。我只是想开始我自己的迷你项目,我从你关于反应性的两个答案中学到的东西比我从所学课程中学到的更多,所以谢谢你。我会查看书面教程,因为它们看起来非常有用。
    • 很高兴这有帮助,让他们继续前进。
    猜你喜欢
    • 1970-01-01
    • 2016-07-12
    • 2021-03-12
    • 2019-03-22
    • 2014-06-25
    • 2014-12-14
    • 2014-04-14
    • 2015-11-21
    • 1970-01-01
    相关资源
    最近更新 更多