如何使用用户输入来更改 rhandsontable 表中的行数和列数?

问题描述 投票:0回答:1

我是 Shiny 的新手,我正在开发一个应用程序,用户可以在其中输入他们希望在每个年龄(由用户指定)储存的鱼的数量,持续用户指定的年数。目前,该应用程序打开时会显示一个默认的常用值表,但我希望用户能够轻松编辑该表,包括行数和列数。用户使用滑块选择库存年数,我希望所选值根据所选数字更新表中的列数。还应该有一列代表年龄,一列代表月份。每年的列应命名为“yr1”、“yr2”等。类似地,用户使用滑块选择年龄数,我希望此选定值来更新行数。我开发的代码如下:

library(rhandsontable)
library(shiny)
library(shinydashboard)

    #stocking.dat <- data.frame(matrix(nrow=1,ncol=7))
    #yrnum <- sprintf("yr%d",seq(1:5))
    #colnames(stocking.dat) <- c("age","month",yrnum)
    
    stocking.dat <- data.frame(age=c(1), month=c(5), yr1=c(250000), yr2=c(250000), yr3=c(250000),     yr4=c(250000), yr5=c(250000))
    
    
    ui <- dashboardPage(skin = "blue",
                      dashboardHeader(title = "PVA",titleWidth = 450),
                      dashboardSidebar(id="",width=450,
                                       sidebarMenu(
                                                    menuItem("Welcome",tabName = "menuWelcome", icon = shiny::icon("face-smile")),
                                                    menuItem("Stocking",tabName = "menuStocking", icon = shiny::icon("fish")),
                                                    menuItem("Review",tabName = "menuReview", icon = shiny::icon("magnifying-glass-chart")))),
                      dashboardBody(
                            tabItems(
                                    tabItem(tabName="menuWelcome",
                                            valueBox("Population Viability Analysis","Welcome",icon = shiny::icon("face-smile"),width=8)),
                                    tabItem(tabName="menuStocking",
                                            fluidRow(valueBox("Proposed Stocking","Enter Data",icon = shiny::icon("fish"),width=8)),
                                            fluidRow(box(sliderInput("n.stockyrs","Number years to stock",value=5,min=0,max=25,step=1),width=8)),
                                            fluidRow(box(sliderInput("n.stockage","Number ages to stock",value=1,min=0,max=5,step=1),width=8)),
                                            fluidRow(box(title="Enter data",status="primary",solidHeader=TRUE,width=8,rHandsontableOutput("hot")))),
                                    tabItem(tabName="menuReview",
                                            fluidRow(valueBox("Review","Review Input",icon = shiny::icon("fish"),width=8)),
                                            fluidRow(box(title="Stocking Data",status="primary",solidHeader=TRUE,width=8,rHandsontableOutput("rvw.hot")))
    
                            )
                      )
    ))

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

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

    values <- reactiveValues(data = stocking.dat)
    
    observe({
      if(!is.null(input$hot)){
        values$data <- as.data.frame(hot_to_r(input$hot))
        print(values$data)
        output$hot <- renderRHandsontable({
          rhandsontable(values$data)
        })
      }
    })
    
    output$hot <- renderRHandsontable({
      rhandsontable(values$data)
    })
    
    output$rvw.hot <- renderRHandsontable({
      rhandsontable(values$data,readOnly=TRUE)
    })
    
    session$onSessionEnded(stopApp)

}

shinyApp(ui, server)

该表应该在“库存”选项卡中可编辑,在“审阅”选项卡中只读,我认为我已经按预期工作了。我不确定如何根据输入滑块更新行数(年龄)和列数(放养年数)。我也不确定如何动态命名以“yr1”开头的列,依此类推,具体取决于所选的年数。

r shiny rhandsontable
1个回答
0
投票

这并不是一件小事,因为您需要保留用户编辑的值(至少在保留已编辑值的行/列时)。

我将您的库存和年龄输入更改为最小值 1,以避免出现空表错误。

使用

stocking.dat
数据框初始化表格后,您可以观察滑块随
observeEvent
的变化,并使用
df = hot_to_r(input$hot)
检索(最终编辑的表格),就像您已经做的那样(检查它是否已加载,使用
if(!is.null(input$hot))
).

之后,您必须考虑用户添加列或行的情况以及用户删除列或行的情况,并根据现有表相应地构建数据框。最后更新

reactiveValues
对象,并重新渲染
output$hot
表。


library(rhandsontable)
library(shiny)
library(shinydashboard)

#stocking.dat <- data.frame(matrix(nrow=1,ncol=7))
#yrnum <- sprintf("yr%d",seq(1:5))
#colnames(stocking.dat) <- c("age","month",yrnum)

stocking.dat <- data.frame(age=c(1), month=c(5), yr1=c(250000), yr2=c(250000), yr3=c(250000),     yr4=c(250000), yr5=c(250000))


ui <- dashboardPage(skin = "blue",
                    dashboardHeader(title = "PVA",titleWidth = 450),
                    dashboardSidebar(id="",width=450,
                                     sidebarMenu(
                                       menuItem("Welcome",tabName = "menuWelcome", icon = shiny::icon("face-smile")),
                                       menuItem("Stocking",tabName = "menuStocking", icon = shiny::icon("fish")),
                                       menuItem("Review",tabName = "menuReview", icon = shiny::icon("magnifying-glass-chart")))),
                    dashboardBody(
                      tabItems(
                        tabItem(tabName="menuWelcome",
                                valueBox("Population Viability Analysis","Welcome",icon = shiny::icon("face-smile"),width=8)),
                        tabItem(tabName="menuStocking",
                                fluidRow(valueBox("Proposed Stocking","Enter Data",icon = shiny::icon("fish"),width=8)),
                                fluidRow(box(sliderInput("n.stockyrs","Number years to stock",value=5,min=1,max=25,step=1),width=8)),
                                fluidRow(box(sliderInput("n.stockage","Number ages to stock",value=1,min=1,max=5,step=1),width=8)),
                                fluidRow(box(title="Enter data",status="primary",solidHeader=TRUE,width=8,rHandsontableOutput("hot")))),
                        tabItem(tabName="menuReview",
                                fluidRow(valueBox("Review","Review Input",icon = shiny::icon("fish"),width=8)),
                                fluidRow(box(title="Stocking Data",status="primary",solidHeader=TRUE,width=8,rHandsontableOutput("rvw.hot")))
                                
                        )
                      )
                    ))

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

server <- function(input, output, session) {
  
  values <- reactiveValues(data = stocking.dat)
  

  observeEvent(input$n.stockyrs, {
    if(!is.null(input$hot)){
    df = hot_to_r(input$hot)
    dfyrs = df[,-(1:2)]
    # add new columns if input > number of existing columns
    if(input$n.stockyrs > ncol(dfyrs)) {
      newcols = as.data.frame(matrix(250000, ncol = input$n.stockyrs - ncol(dfyrs)))
      dfyrs = cbind(dfyrs, newcols)
    } else { # else remove columns
      dfyrs = dfyrs[,1:input$n.stockyrs]
    }
    names(dfyrs) = paste0("yr", 1:input$n.stockyrs)
    df = cbind(df[,1:2], dfyrs)
    values <- reactiveValues(data = df)
    output$hot <- renderRHandsontable({
      rhandsontable(values$data)
    })
    }
  })

  observeEvent(input$n.stockage, {
    if(!is.null(input$hot)){
      df = hot_to_r(input$hot)
      dfam = df[,1:2]
      # add new rows if input > number of existing rows
      if(input$n.stockage > nrow(df)) {
      # new rows
      newrows = as.data.frame(matrix(250000, nrow = input$n.stockage - nrow(dfyrs), ncol = input$n.stockyrs))
      names(newrows) = paste0("yr", 1:input$n.stockyrs)
      highestexistingage = dfam[length(dfam$age),1]
      dfamnewrows = data.frame(age = seq(highestexistingage + 1, input$n.stockage), month = rep(5))
      newrows = cbind(dfamnewrows, newrows)
      df = rbind(df, newrows)
      } else { #remove rows
        df = df[1:input$n.stockage,]
      }
      values <- reactiveValues(data = df)
      print(values$data)
      output$hot <- renderRHandsontable({
        rhandsontable(values$data)
      })
    }
  })
  
  observe({
    if(!is.null(input$hot)){
      values$data <- as.data.frame(hot_to_r(input$hot))

      output$hot <- renderRHandsontable({
        rhandsontable(values$data)
      })
    }
  })
  
  output$hot <- renderRHandsontable({
    rhandsontable(values$data)
  })
  
  output$rvw.hot <- renderRHandsontable({
    rhandsontable(values$data,readOnly=TRUE)
  })
  
  session$onSessionEnded(stopApp)
  
}

shinyApp(ui, server)

© www.soinside.com 2019 - 2024. All rights reserved.