在我的小型Shiny应用程序中,我问用户:您希望将时间序列缩短到多少个时间段?例如,用户选择3.我想使用此输入来获取固定的日期向量,并使用户可以从中选择所需的时间段1的最后日期(在选择框1中)和时间段2(在选择框2中)。 (时间段3的最后日期将是最后一个日期,所以我不需要问)。
我不知道该怎么做。我理解,因为我事先并不知道所需的时间段数,所以我必须创建一个列表。但是,如何从这些选择框中收集输入?
非常感谢!
library(shiny)
### UI #######################################################################
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
# Sidebar:
sidebarLayout(
sidebarPanel(
# Slider input for the number of time periods:
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 1, max = 10, value = 2),
uiOutput("period_cutpoints")
),
# Show just the number of periods so far.
mainPanel(
textOutput("nr_of_periods")
)
)
))
### SERVER ##################################################################
server = shinyServer(function(input, output, session) {
library(lubridate)
output$nr_of_periods <- renderPrint(input$num_periodsnr)
# Define our dates vector:
dates <- seq(ymd('2016-01-02'), ymd('2017-12-31'), by = '1 week')
# STUCK HERE:
# output$period_cutpoints<-renderUI({
# list.out <- list()
# for (i in 1:input$num_periodsnr) {
# list.out[[i]] <- renderPrint(paste0("Sometext", i), ,
# )
# }
# return(list.out)
# })
})
# Run the application
shinyApp(ui = ui, server = server)
这类似于我提出的一个问题,随后找出了here的答案。服务器中的(可预测)发生了很大的变化。
在UI中没有什么需要改变,但正如你将在下面看到的,我已经包含了另一个textOutput
,以便你可以看到你最终选择的日期,并且我还添加了一个actionButton
,我将在稍后解释。
服务器功能有几个附加功能,我将首先描述,然后在最后汇总。你是对的,你需要在renderUI
中创建一个输入对象列表,你可以通过lapply
来做。在这一步,你创建了尽可能多的selectInput
s,因为你有切割点,减一,因为你说你不需要最后一个:
output$period_cutpoints<-renderUI({
req(input$num_periodsnr)
lapply(1:(input$num_periodsnr-1), function(i) {
selectInput(inputId=paste0("cutpoint",i),
label=paste0("Select cutpoint for Time Period ", i, ":"),
choices=dates)
})
})
接下来,您需要使用您首先创建的reactiveValues
对象访问在每个中选择的值,您可以使用相同的方式执行这些值,并为其分配新值。在我的这个问题的版本中,我无法弄清楚如何在不使用actionButton
来触发它的情况下更新列表。简单的reactive()
或observe()
没有做到这一点,但我真的不知道为什么。
seldates <- reactiveValues(x=NULL)
observeEvent(input$submit, {
seldates$x <- list()
lapply(1:(input$num_periodsnr-1), function(i) {
seldates$x[[i]] <- input[[paste0("cutpoint", i)]]
})
})
完整的应用程序代码然后如下所示:
library(shiny)
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
sidebarLayout(
sidebarPanel(
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 1, max = 10, value = 2),
uiOutput("period_cutpoints"),
actionButton("submit", "Submit")
),
mainPanel(
textOutput("nr_of_periods"),
textOutput("cutpoints")
)
)
))
server = shinyServer(function(input, output, session) {
library(lubridate)
output$nr_of_periods <- renderPrint(input$num_periodsnr)
dates <- seq(ymd('2016-01-02'), ymd('2017-12-31'), by = '1 week')
output$period_cutpoints<-renderUI({
req(input$num_periodsnr)
lapply(1:(input$num_periodsnr-1), function(i) {
selectInput(inputId=paste0("cutpoint",i),
label=paste0("Select cutpoint for Time Period ", i, ":"),
choices=dates)
})
})
seldates <- reactiveValues(x=NULL)
observeEvent(input$submit, {
seldates$x <- list()
lapply(1:(input$num_periodsnr-1), function(i) {
seldates$x[[i]] <- input[[paste0("cutpoint", i)]]
})
})
output$cutpoints <- renderText({as.character(seldates$x)})
})
shinyApp(ui = ui, server = server)
你可以在lapply中动态创建框,并将它们作为1输出对象发送到ui
require("shiny")
require('shinyWidgets')
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
# Sidebar:
sidebarLayout(
sidebarPanel(
# Slider input for the number of time periods:
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 1, max = 10, value = 2),
uiOutput("period_cutpoints")
),
# Show just the number of periods so far.
mainPanel(
textOutput("nr_of_periods")
)
)
))
# Define server logic ----
server <- function(session, input, output) {
output$period_cutpoints<- renderUI({
req(input$num_periodsnr > 0)
lapply(1:input$num_periodsnr, function(el) {
airDatepickerInput(inputId = paste('PeriodEnd', el, sep = ''), label = paste('Period End', el, sep = ' '), clearButton = TRUE, range = F, update_on = 'close')
})
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
由于您没有提供数据集来应用输入,并且我不知道您的数据的日期范围,我没有添加代码来设置日期选择器的最小/最大值,并且不确定要提供什么样的代码供您使用数据。您需要写一些东西才能将它们放入列表中
values <- reactiveValues(datesplits = list(),
previous_max = 0)
observeEvent(input$num_periodsnr, {
if(input$num_periodsnr > values$previous_max) {
lapply(values$previous_max:input$num_periodsnr, function(el) {
observeEvent(input[[paste(paste('PeriodEnd', el, sep = '')]], {
values$datesplits[el] <- input[[paste(paste('PeriodEnd', el, sep = '')]]
})
values$previous_max <- max(values$previous_max, input$num_periodsnr)
})
}
})
然后使用日期列表,我想你需要做些什么。
我使用从enter code here
运行lapprevious_max
ply到input$num_periodsnr
if(input$num_periodsnr > values$previous_max){}
的技巧,以避免你为同一个observers
input
重复创建element
时创建的问题。当ui
元素在循环中创建时被覆盖,而observeEvents
被制作为副本,因此每次你的循环触发时,你都会制作observers
1:n
的另一个副本。这导致所有副本每次都会发射,直到你有一百万个observers
全部射击,造成可能的奇怪错误,不必要的效果和速度损失。