Nice programing

R / Shiny로 다이나믹 한 수의 입력 요소 생성

nicepro 2020. 12. 25. 22:58
반응형

R / Shiny로 다이나믹 한 수의 입력 요소 생성


회사에서 보험 혜택 계획을 시각화하기 위해 Shiny 앱을 작성하고 있습니다. 내가 원하는 것은 다음과 같습니다.

  • 나는이있을 것이다 selectInput또는 sliderInput사용자가 자신의 의료 보험에 개인의 수를 위치를 선택합니다
  • 일치하는 수의 양면 슬라이더가 나타납니다 (각 구성원에 대해 하나씩).
  • 그런 다음 플랜에있는 각 가입자의 최고 / 최악의 의료 비용에 대한 추정치를 입력 할 수 있습니다.
  • 나는 그 추정치를 취하고 세 가지 계획 오퍼링에 대한 예측 비용을 보여주는 나란히 플롯을 생성하는 코드를 가지고 있으므로 추정치를 기반으로 어느 것이 가장 저렴한 지 결정할 수 있습니다.

다음 ui.R은 하드 코딩 된 입력이있는 현재 파일이며, 4 개의 패밀리를 시뮬레이션합니다.

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존재하지만 그 내용은 다른 UI 입력의 선택에 따라 맞게 조정됩니다),하지만 난 재봉의 예를 볼 수없는 한 수를 (또는 , 예를 들어, 유형)의 다른 UI 입력 내용의 결과로 생성되는 입력 요소입니다.

이것에 대한 제안이 있습니까 (가능합니까?)?


마지막 수단은 15 개의 입력 슬라이더를 만들어 0으로 초기화하는 것입니다. 내 코드는 잘 작동하지만 매우 큰 가족이있는 사용자를 위해 그렇게 많은 슬라이더를 만들지 않아도되므로 인터페이스를 정리하고 싶습니다.


Kevin Ushay의 답변을 기반으로 한 업데이트

나는 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()라인을 사용할 때 3 분의 1을 얻지 못합니다 .

print(expenses)expenses함수 내부 와 같은 작업을 수행 하면 중복도 발생합니다.

# the first
  mins maxs
1   NA   NA
2   NA   NA

# the second
  mins maxs
1    0  500
2    0  500

Any tips on why my input elements for ind1 and ind2 wouldn't show up until expenses is called the second time and thus prevent the data frame from being created correctly?


You could handle generation of the UI element in server.R, so you have something like:

ui.R
----

shinyUI( pageWithSideBar(
    ...
    selectInput("numIndividuals", ...)
    uiOutput("sliders"),
    ...
))

and

server.R
--------

shinyServer( function(input, output, session) {

  output$sliders <- renderUI({
    numIndividuals <- as.integer(input$numIndividuals)
    lapply(1:numIndividuals, function(i) {
      sliderInput(...)
    })
  })


})

When I have UI elements that depend on values from other UI elements, I find it easiest to generate them in server.R.

It's useful to understand that all of the _Input functions just generate HTML. When you want to generate that HTML dynamically it makes sense to move it to server.R. And perhaps the other thing worth emphasizing is that it's okay to return a list of HTML 'elements' in a renderUI call.


다음 구문을 사용하여 shiny에서 동적으로 명명 된 변수에 액세스 할 수 있습니다.

input[["dynamically_named_element"]]

따라서 위의 예에서 슬라이더 요소를 초기화하면

# server.R

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

# ui.R

selectInput("num", "select number of inputs", choices = seq(1,10,1))
uiOutput("input_ui")

다음을 사용하여 값을 테이블에 인쇄 할 수 있습니다.

# server.R

output$table <- renderTable({
    num <- as.integer(input$num)

    data.frame(lapply(1:num, function(i) {
      input[[paste0("ind", i)]]
    }))
  })

# ui.R

tableOutput("table")

작동하는 Shiny 예제는 여기참조 하십시오 . 여기서 일하는 요지 .

출처 : Joe Cheng의 첫 번째 답변, 이 스레드의 절반 정도


당신은과 사이드 바 생성 할 수 do.calllapply, 같은 뭔가를 :

# create the first input, which isn't dynamic
sel.input = 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"))

num.individuals = 5  # determine the number of individuals here

# concatenate the select input and the other inputs
inputs = c(list(sel.input), lapply(1:num.individuals, function(i) {
    sliderInput(inputId = paste0("ind", i), label = paste("Individual", i), min = 0, max = 20000, value = c(0, 2500), step = 250)
}))

sidebar.panel = do.call(sidebarPanel, inputs)

참조 URL : https://stackoverflow.com/questions/19130455/create-dynamic-number-of-input-elements-with-r-shiny

반응형