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ówOto 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?