【问题标题】:R Shiny: Creating X numbers of numericInput boxes equal to number of variablesR Shiny:创建X个数字输入框等于变量数
【发布时间】:2021-08-02 13:11:19
【问题描述】:

我正在尝试创建一个与金融相关的 R Shiny 应用程序。截至目前,我有一个选项卡来创建自定义投资组合,这要求我为原始source_file 中的每个变量都有一个numericInput。这就是示例 source_file 的样子:

Date CSI500 Shanghai CSI300 HSI STI
2016-01-01 +5% -2% +5% +10% +12%
2016-01-08 +3% +13% -8% -3% +10%
2016-01-15 +2% +11% -3% +4% -15%

目前,我必须为每个变量手动硬编码每个 numericInput 框,如下所示:

tabPanel("Custom Portfolio by Weight",
                           sidebarPanel(
                             tags$h3("Create your own Custom Portfolio by Asset Weight"),
                             tags$h4("Input:"),
                             numericInput(inputId = "custom_csi500", "CSI500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_shanghai", "Shanghai Stock Exchange (%)",  min = 0, max = 100),
                             numericInput(inputId = "custom_csi300", "CSI300 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_hsi", "HSI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sti", "STI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_twse", "TWSE (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_msciw", "MSCI World (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sp500", "S&P500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_n225", "Nikkei 225 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_lse", "London Stock Exchange (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_asx", "ASX (%)", min = 0, max = 100),

但是,我想创建一个可以扩展到具有我指定的不同数量变量的任何数据帧的东西,而无需手动硬编码它们。我希望任何人都能够帮助我编写一个代码能够读取我的数据框中的变量数量(日期列除外)并为每个变量创建那么多 numericInput 框。非常感谢您的帮助!如果需要,我在下面附上了我的 App.R 和 Global.R 以供参考。干杯!

App.R

# Load packages
library(shiny)
library(shinythemes)
source("./global.R")

# Defining UI
ui <- fluidPage(theme = shinytheme("darkly"),
                navbarPage(
                  "Test App",
                  tabPanel("Custom Portfolio by Weight",
                           sidebarPanel(
                             tags$h3("Create your own Custom Portfolio by Asset Weight"),
                             tags$h4("Input:"),
                             numericInput(inputId = "custom_csi500", "CSI500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_shanghai", "Shanghai Stock Exchange (%)",  min = 0, max = 100),
                             numericInput(inputId = "custom_csi300", "CSI300 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_hsi", "HSI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sti", "STI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_twse", "TWSE (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_msciw", "MSCI World (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sp500", "S&P500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_n225", "Nikkei 225 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_lse", "London Stock Exchange (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_asx", "ASX (%)", min = 0, max = 100),
                             mainPanel(
                             plotOutput(outputId = "custom_returns"),
                           ), #mainPanel
                ), #tabpanel
                ) #navbarPage
) #fluidPage

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

#to output custom_returns for Custom Portfolio by Asset Weight
    output$custom_returns <- renderPlot({
      calculate_portfolio_returns(
        customrange = input$customrange,
        asset_weights = c(input$custom_csi500/100,
          input$custom_shanghai/100,                
          input$custom_csi300/100,
          input$custom_hsi/100,
          input$custom_sti/100,
          input$custom_twse/100,
          input$custom_msciw/100,
          input$custom_sp500/100,
          input$custom_n225/100,
          input$custom_lse/100,
          input$custom_asx/100,
          input$custom_custom/100))
    })
}
  
# Create Shiny Object
  shinyApp(ui = ui, server = server)

全球.R

# Load packages
library(tidyverse)
library(ggcorrplot)
library(zoo)
library(xts)
library(testit)
library(PerformanceAnalytics)

#choose source file to work with
file_name = file.choose()
source_file = read_csv(file_name)
source_file$Date = as.Date(source_file$Date, format = "%Y-%m-%d")

########################
calculate_portfolio_returns = function(customrange, asset_weights)
{
  #filter source file by date range specified
  source_file_filtered <- source_file %>% 
    filter(Date >= customrange[1] & Date <= customrange[2])
  
  source_file_filtered_no_date <- source_file_filtered[,2:length(source_file_filtered)]
  
  #create new column called Cumulative_Returns to convert % daily returns
  Cumulative_Returns <- cumsum(source_file_filtered_no_date)
  
  # Extract necessary parameters
  n_cols = ncol(Cumulative_Returns)
  n_assets = n_cols
  
  #To ensure portfolio is always weighted at 100% at all times
  assert(length(asset_weights) == n_assets)
  assert(abs(sum(asset_weights)-1) <= 0.001)
  
  portfolio_returns = data.matrix(Cumulative_Returns) %*% asset_weights
  portfolio_returns_with_date = cbind(source_file_filtered[,1], portfolio_returns)
  g = ggplot(data = portfolio_returns_with_date, mapping = aes(x=Date, y=portfolio_returns)) +
   geom_line(color="blue") + ggtitle(paste("Custom Portfolio Returns from", customrange[1], "to", customrange[2])) +
   geom_hline(yintercept = 0, linetype = "dashed") + theme(plot.title = element_text(hjust=0.5)) +
    ylab("Portfolio Returns (%)")
  print(g)
}

【问题讨论】:

    标签: r shiny finance numeric-input


    【解决方案1】:

    这是一个可能对你有帮助的演示。

    您可以将 .csv 文件上传到闪亮的应用程序。它将忽略第一列(或者您可以修改以专门删除日期列)。

    数字输入将根据读入的标题列名称动态生成。

    该演示有一个calc 按钮,它将存储输入数据并用于进一步处理(计算返回)。还添加了一个表格来显示输入的数据。

    编辑:如果在按下calc 按钮时您想调用您的自定义函数(calculate_portfolio_returns),您可以在eventReactive 中添加对该函数的调用,因为这取决于在输入按钮上。要传递来自数字输入的值,您可以将这些值临时存储在向量 vals 中,然后将 vals 作为参数传递给函数(参见下面的修改代码)。在演示中,我调用了一个自定义函数calc_sum,它将在控制台中打印数字输入的总和。最后一点,我在input_vals() 的末尾添加了一个明确的return,以便vals 可以共享以供output$table 使用。

    library(shiny)
    
    ui <- fluidPage(
      fileInput(inputId = "upload_file", "", accept = '.csv'),
      uiOutput("num_inputs"),
      actionButton("calc", "Calculate"),
      tableOutput("table")
    )
    
    server <- function(input, output, session) {
      
      data <- reactive({
        infile <- input$upload_file
        if (is.null(infile))
          return(NULL)
        read.csv(infile$datapath, header = TRUE, sep = ",")
      })
      
      header_vars <- reactive({
        names(data()[-1])
      })
      
      output$num_inputs <- renderUI({
        vars <- length(header_vars())
        if (vars > 0) {
          div(
            lapply(seq(vars), function(x) {
              numericInput(inputId = paste0("var_", x), label = header_vars()[x], value = 0, min = 0, max = 100)
            })
          )
        }
      })
      
      input_vals <- eventReactive(input$calc, {
        n_vars <- length(header_vars())
        vals <- c()
        if (n_vars > 0) {
          vals <- sapply(seq(n_vars), function(i) {
            input[[paste0("var_", i)]]
          }) 
        }
        calc_sum(vals)
        return(vals)
      })
      
      calc_sum <- function(vals) {
        print(sum(vals))
      }
      
      output$table <- renderTable({
        data.frame(
          vars = header_vars(),
          vals = input_vals()
        )
      })
      
    }
    
    shinyApp(ui = ui, server = server)
    

    【讨论】:

    • 谢谢!它工作得很好!只是必须以某种方式将其合并到我的应用程序中,非常感谢演示
    • 但是,我对此只有 1 个问题。如果我要在 global.R 的另一个函数中引用变量,变量 ID 将是什么?会是 input_vals 吗?
    • 我打算使用输入到您为我创建的反应性数字输入框中的数字(代表列表中每只股票的权重)并创建一个由所有股票组成的加权投资组合以及它们各自的权重。但是,为此,我需要将我的函数的参数asset_weights 设置为之前解决方案中的 numericInput。您认为您知道我如何根据您的代码行定义我的参数asset_weights 吗?欣赏!
    • @honnielemons 查看编辑后的答案 - 我添加了更多解释并更新了代码。将numericInput 值传递给自定义函数应该相对容易。让我知道这是否有帮助。
    猜你喜欢
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    相关资源
    最近更新 更多