Создать динамическое количество элементов ввода с R / Shiny
Я пишу блестящее приложение для визуализации планов страховых выплат в моей компании. Вот что я хотел бы случиться:
Я буду иметьselectInput
или жеsliderInput
где пользователь выберет количество людей в своем медицинском планеПоявится соответствующее количество двусторонних ползунков (по одному для каждого участника)Затем они могут ввести свои оценки для наилучших / наихудших медицинских расходов для каждого участника их планаУ меня есть код, который возьмет эти оценки и создаст соседние графики, иллюстрирующие прогнозную стоимость для трех предложений плана, чтобы они могли решить, какой из них является наименее дорогим, основываясь на своих оценкахВот мой токui.R
файл с жестко закодированными входами, имитирующий семью из четырех человек:
shinyUI(pageWithSidebar(
headerPanel("Side by side comparison"),
sidebarPanel(
selectInput(inputId = "class", label = "Choose plan type:",
list("Employee only" = "emp", "Employee and spouse" = "emp_spouse",
"Employee and child" = "emp_child", "Employee and family" = "emp_fam")),
sliderInput(inputId = "ind1", label = "Individual 1",
min = 0, max = 20000, value = c(0, 2500), step = 250),
sliderInput(inputId = "ind2", label = "Individual 2",
min = 0, max = 20000, value = c(0, 2500), step = 250),
sliderInput(inputId = "ind3", label = "Individual 3",
min = 0, max = 20000, value = c(0, 2500), step = 250),
sliderInput(inputId = "ind4", label = "Individual 4",
min = 0, max = 20000, value = c(0, 2500), step = 250)
),
mainPanel(
tabsetPanel(
tabPanel("Side by Side", plotOutput(outputId = "main_plot", width = "100%")),
tabPanel("Summary", tableOutput(outputId = "summary"))
)
)))
Вот как это выглядит (прозрачные конечные разделы являются результатом участия HSA в двух планах. Я подумал, что это хороший способ показать как страховые взносы, так и медицинские расходы, демонстрируя влияние вклада компании HSA. Таким образом, вы просто сравнил длину сплошных цветов).
Я видел примерынравится где сам вход UI является фиксированным (в этом случае одинcheckboxGroupInput
существует, но его содержимое настраивается на основе выбора из другого ввода пользовательского интерфейса), но я не видел примеров адаптацииномер (или, скажем, тип) элементов ввода, порожденных в результате содержимого другого входа пользовательского интерфейса.
Есть предложения по этому поводу (возможно ли это)?
Моим последним средством будет, скажем, создать 15 ползунков ввода и инициализировать их нулями. Мой код будет работать просто отлично, но я бы хотел очистить интерфейс, не создавая столько ползунков только для случайного пользователя, у которого очень большая семья.
Обновление на основе ответа Кевина Ушая
Я пытался пойтиserver.R
маршрут и есть это:
shinyServer(function(input, output) {
output$sliders <- renderUI({
members <- as.integer(input$members) # default 2
max_pred <- as.integer(input$max_pred) # default 5000
lapply(1:members, function(i) {
sliderInput(inputId = paste0("ind", i), label = paste("Individual", i),
min = 0, max = max_pred, value = c(0, 500), step = 100)
})
})
})
Сразу после этого я пытаюсь извлечь значения изinput
для каждого человека расходы:
expenses <- reactive({
members <- as.numeric(input$members)
mins <- sapply(1:members, function(i) {
as.numeric(input[[paste0("ind", i)]])[1]
})
maxs <- sapply(1:members, function(i) {
as.numeric(input[[paste0("ind", i)]])[2]
})
expenses <- as.data.frame(cbind(mins, maxs))
})
Наконец, у меня есть две функции, которые создают объекты для хранения фрейма данных для построения графиков на основе оценок низких и высоких медицинских расходов. Они называютсяbest_case
а такжеworst_case
и оба нужныexpenses
объект для работы, поэтому я называю это своей первой строкой, как я узнал изэтот вопрос
best_case <- reactive({
expenses <- expenses()
...
)}
Я получил несколько ошибок, поэтому я использовалbrowser()
пройти черезexpenses
немного и заметил странные вещи, такие какinput$ind1
не кажется существующим изнутриexpenses
функция.
Я также играл с различнымиprint()
Заявления в нем, чтобы увидеть, что происходит. Самое поразительное, когда я делаюprint(names(input))
как самая первая строка в функции:
[1] "class" "max_pred" "members"
[1] "class" "ind1" "ind2" "max_pred" "members"
я получилдва выходы, которые я считаю, связано с определениемexpenses
и последующий вызов этого. Странно ... Я не получаю третий, когдаworst_case
использует точно такой жеexpenses <- expense()
линия.
Если я сделаю что-то вродеprint(expenses)
внутри моегоexpenses
функция, я также получаю дубликаты:
# the first
mins maxs
1 NA NA
2 NA NA
# the second
mins maxs
1 0 500
2 0 500
Любые советы о том, почему мойinput
элементы дляind1
а такжеind2
не появится доexpenses
вызывается во второй раз и, таким образом, препятствует правильному созданию фрейма данных?