gpt4 book ai didi

r - 为输入的动态数量生成观察者

转载 作者:行者123 更新时间:2023-12-04 07:51:07 26 4
gpt4 key购买 nike

我有一个我认为无法解决的非常简单的用户案例:我希望Shiny生成用户指定数量的输入,并为每个输入动态创建一个观察者。

在下面的最小可重复代码中,用户通过键入textInput小部件来指示所需的操作按钮的数量;然后他或她按下“提交”,这将生成操作按钮。

我想要的是让用户能够单击任何操作按钮并生成特定于其的输出(例如,在最小的情况下,只需打印按钮的名称)即可:

library("shiny")

ui <- fluidPage(textInput("numButtons", "Number of buttons to generate"),
actionButton("go", "Submit"), uiOutput("ui"))

server <- function(input, output) {

makeObservers <- reactive({

lapply(1:(as.numeric(input$numButtons)), function (x) {

observeEvent(input[[paste0("add_", x)]], {

print(paste0("add_", x))

})

})
})

observeEvent(input$go, {

output$ui <- renderUI({

num <- as.numeric(isolate(input$numButtons))

rows <- lapply(1:num, function (x) {

actionButton(inputId = paste0("add_", x),
label = paste0("add_", x))

})

do.call(fluidRow, rows)

})

makeObservers()

})


}

shinyApp(ui, server)

上面的代码的问题在于,以某种方式创建了多个观察者,但是它们都只将传递给 lapply的列表中的最后一项作为输入。因此,如果我生成四个操作按钮,然后单击第4个操作按钮,则Shiny将打印其名称四次,而其他所有按钮均不起作用。

使用 lapply生成观察者的想法来自 https://github.com/rstudio/shiny/issues/167#issuecomment-152598096

最佳答案

在您的示例中,只要仅按下一次actionButton,一切就可以正常工作。例如,当我创建3按钮/观察者时,我会在控制台中打印出正确的ID-每个新生成的actionButton都有一个观察者。 √

[1] "add_1"
[1] "add_2"
[1] "add_3"

但是,当我选择 3以外的数字然后再次按 submit时,您所描述的问题就开始了。

说,我现在要 4 actionButtons-我输入 4并按 submit。之后,我按下每个新生成的按钮一次,然后得到以下输出:
[1] "add_1"
[1] "add_1"
[1] "add_2"
[1] "add_2"
[1] "add_3"
[1] "add_3"
[1] "add_4"

通过单击 submit按钮,我再次为第三个按钮创建了观察者-我对前三个按钮有两个观察者,对于新的第四个按钮只有一个。

我们可以不断地玩这个游戏,并且每个按钮都会吸引越来越多的观察者。当我们创建比以前更少的按钮时,这非常相似。

的解决方案将是跟踪已定义了哪些操作按钮,然后仅为新按钮生成观察者。在下面的示例中,我描述了如何执行此操作。它可能不是最好的编程方法,但它应该很好地展示了这个想法。

完整示例:
library("shiny")

ui <- fluidPage(
numericInput("numButtons", "Number of buttons to generate",
min = 1, max = 100, value = NULL),
actionButton("go", "Submit"),
uiOutput("ui")
)

server <- function(input, output) {

# Keep track of which observer has been already created
vals <- reactiveValues(x = NULL, y = NULL)

makeObservers <- eventReactive(input$go, {

IDs <- seq_len(input$numButtons)

# For the first time you press the actionButton, create
# observers and save the sequence of integers which gives
# you unique identifiers of created observers
if (is.null(vals$x)) {
res <- lapply(IDs, function (x) {
observeEvent(input[[paste0("add_", x)]], {
print(paste0("add_", x))
})
})
vals$x <- 1
vals$y <- IDs
print("else1")

# When you press the actionButton for the second time you want to only create
# observers that are not defined yet
#

# If all new IDs are are the same as the previous IDs return NULLL
} else if (all(IDs %in% vals$y)) {
print("else2: No new IDs/observers")
return(NULL)

# Otherwise just create observers that are not yet defined and overwrite
# reactive values
} else {
new_ind <- !(IDs %in% vals$y)
print(paste0("else3: # of new observers = ", length(IDs[new_ind])))
res <- lapply(IDs[new_ind], function (x) {
observeEvent(input[[paste0("add_", x)]], {
print(paste0("add_", x))
})
})
# update reactive values
vals$y <- IDs
}
res
})


observeEvent(input$go, {

output$ui <- renderUI({

num <- as.numeric(isolate(input$numButtons))

rows <- lapply(1:num, function (x) {

actionButton(inputId = paste0("add_", x),
label = paste0("add_", x))

})

do.call(fluidRow, rows)

})
makeObservers()
})

}
shinyApp(ui, server)

关于r - 为输入的动态数量生成观察者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38950886/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com