Utwórz dynamiczną liczbę elementów wejściowych za pomocą R / Shiny

Piszę aplikację Shiny do wizualizacji planów świadczeń ubezpieczeniowych w mojej firmie. Oto, co chciałbym zrobić:

Będę miećselectInput lubsliderInput gdzie użytkownik wybierze liczbę osób na swoim planie medycznymPojawi się odpowiednia liczba suwaków dwustronnych (po jednym dla każdego członka)Następnie mogą wprowadzić swoje szacunki dla najlepszego / najgorszego przypadku kosztów medycznych dla każdego członka w ich planieMam kod, który pobiera te szacunki i tworzy wykresy obok siebie, ilustrując prognozowany koszt trzech ofert planu, aby mogli zdecydować, który z nich jest najtańszy na podstawie ich szacunków

Oto mój prądui.R plik z kodowanymi danymi wejściowymi, symulujący czteroosobową rodzinę:

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"))
  )
)))

Oto, jak to wygląda (przezroczyste części końcowe są wynikiem wkładu HSA z dwóch planów. Pomyślałem, że to dobry sposób na pokazanie zarówno składek, jak i kosztów leczenia, pokazując jednocześnie wpływ wkładu HSA firmy. wystarczy porównać długość jednolitych kolorów).

Widziałem przykładylubię to gdzie samo wejście interfejsu użytkownika jest poprawione (w tym przypadku jednocheckboxGroupInput istnieje, ale jego zawartość jest dostosowana do wyboru z innego wejścia UI), ale nie widziałem przykładów krawiectwanumer (lub, powiedzmy, typ) elementów wejściowych powstałych w wyniku zawartości innego wejścia interfejsu użytkownika.

Wszelkie sugestie na ten temat (czy jest to możliwe)?

Moją ostatnią deską ratunku będzie utworzenie, powiedzmy, 15 suwaków wejściowych i zainicjowanie ich do zera. Mój kod będzie działać dobrze, ale chciałbym oczyścić interfejs, nie tworząc wielu suwaków tylko dla sporadycznych użytkowników, którzy mają bardzo dużą rodzinę.

Aktualizacja oparta na odpowiedzi Kevina Ushaya

Próbowałem iśćserver.R trasa i mieć to:

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)
    })

  })

})

Zaraz potem próbuję wydobyć wartości zinput dla każdego z osobna:

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))
})

Wreszcie, mam dwie funkcje, które tworzą obiekty do przechowywania ramki danych do kreślenia w oparciu o niskie i wysokie szacunki wydatków medycznych. Nazywają siębest_case iworst_case i obie potrzebująexpenses obiekt do pracy, więc nazywam go moją pierwszą linią, z której dowiedziałem sięto pytanie

best_case <- reactive({

    expenses <- expenses()

    ...

)}

Mam pewne błędy, więc użyłembrowser() przejść przezexpenses trochę i zauważyłem dziwne rzeczy jakinput$ind1 nie wydaje się istnieć z wnętrzaexpenses funkcjonować.

Grałem też z różnymiprint() oświadczenia w nim, aby zobaczyć, co się dzieje. Najbardziej uderzające jest to, kiedy to robięprint(names(input)) jako pierwsza linia w funkcji:

[1] "class"    "max_pred" "members" 

[1] "class"    "ind1"     "ind2"     "max_pred" "members" 

dostajędwa wyjścia, które moim zdaniem wynikają z definicjiexpenses a następnie wywołanie go. O dziwo ... Nie dostaję trzeciej, kiedyworst_case używa tego samegoexpenses <- expense() linia.

Jeśli coś zrobięprint(expenses) wewnątrz mojegoexpenses funkcja, otrzymuję również duplikaty:

# the first
  mins maxs
1   NA   NA
2   NA   NA

# the second
  mins maxs
1    0  500
2    0  500

Jakieś wskazówki, dlaczego mójinput elementy dlaind1 iind2 nie pojawił się, dopókiexpenses jest wywoływany po raz drugi i tym samym uniemożliwia prawidłowe utworzenie ramki danych?

questionAnswers(3)

yourAnswerToTheQuestion