roptimizationshinynested-if

Optimizing nested ifelse in shiny


This post is not much of a cry for help as my script works exactly as intended, but I was wondering if there was maybe a better way to write it given that it's quite heavy, I may need to make changes in the future and I've started a personal project for which the method I used here would probably be way too time-consuming and less practical (as the personal project is even bigger...)

Basically, I'm making an app to help my coworked choose the best statistic test for their analysis.

the UI looks like this :

    ui <- fixedPage(
  titlePanel("Choisir son test statistique"),
  fluidRow(
    column(3,selectInput("choix","Que voulez-vous faire ?", c('a1',
                                                              'b1',
                                                              'c1',
                                                              'd1'))),
    column(3,conditionalPanel(
      condition="input.choix=='stat'",
      selectInput("type","Quel type d'analyse ?", c('a2',
                                                    "b2",
                                                    "c2",
                                                    "d2")))),
    column(3,conditionalPanel(
      condition="input.choix=='d1'&&input.type=='b2'||input.choix=='d1'&&input.type=='c2'",
      selectInput("groupe","Combien de groupes ?", c('a3',
                                                     "b3",
                                                     "c3",
                                                     "d3"))),
      conditionalPanel(
        condition = "input.type=='Lien entre Variable'",
        selectInput("variable","Quel type de variables ?", c('a4',
                                                             "b4",
                                                             "c4",
                                                             "d4")))),
    column(3, conditionalPanel(
      condition = "input.choix=='d1'&&input.type=='b2'||input.choix=='d1'&&input.type=='c2'",
      selectInput("indep", "Indépendance des données ?",c('a5',
                                                          "b5",
                                                          "c5"))),
      conditionalPanel(
        condition = "input.choix=='d1'&&input.type=='b2'||input.choix=='d1'&&input.type=='c2'",
        selectInput("param", "Normalité des données ?",c('a6',
                                                         "b6",
                                                         "c6",
                                                         "d6")))),
    
    mainPanel(htmlOutput("texte"))))

My "problem" starts with the server part that I wrote with a LOT of nested if_else. I'm a complete newb when it comes to shiny so this was really the only way I knew how to tackle it. Let's have a quick look :

server <- function(input, output) {   output$texte <- renderText({ 
    if(input$choix=="a1"){
      paste(analyse_desc)}
    else{if(input$choix=="b1" ){
      paste(shapiro, levene, bartlett)}
      else{if(input$choix=="c1"){
        groupe<-input$groupe
        param<-input$param
        indep<-input$indep
        type<-input$type
        if(input$param=="d6"){
          paste(shapiro, levene, bartlett)}
        else{if(input$groupe=="b3" &&
                input$param=="b6" && 
                input$type=="b2"){
          paste(student1)}
          else{if(input$groupe=="c3" &&
                  input$param=="b6" && 
                  input$indep=="b5"&&
                  input$type=="b2"){
            paste(student2, welch)}
            else{if(input$groupe=="d3" &&
                    input$param=="b6" &&  
                    input$indep=="b5"&&
                    input$type=="b2"){
              paste(anova1)}
              else{if(input$groupe=="b3" &&
                      input$param=="c6" && 
                      input$type=="b2"){
                paste(wilcoxon1)}
                else{if(.........)}

I won't put the entire script, you've got the general idea : I need to implement an ifelse for every possible choice from the user and there is like 20 of them.

Just that is already huge (for me at least) and my other project might need even more.

I've seen something about case_when() but when I tried to use it, I couldn't put several of them in a row (or maybe I just didn't do it properly, I don't know).

So basically my question is : do any of you guys would know if there are a more optimized way of doing those kind of nested ifelse (which would make it easier to implement changes later) or if it's just brute strenght all the way ?

Thank you very much !


Solution

  • I would try to have all the conditions stored neatly in a dataframe, and then retrieve the answer from there, as it would make more evident the underlying logic. You could create a simple dataframe with all conditions as columns (type of analysis, type of variable, independence, normality, etc.) and then a column for methods that satisfy those conditions. Then you could just filter that dataframe in order to get the possible methods.

    methods <- tribble(~group, ~type_variable, ~independence, ~normality, ~method,
                       "a",    "numeric",      FALSE,         TRUE,       "method1",
                       "a",    "numeric",      TRUE,          TRUE,       "method2",
                       "a",    "numeric",      TRUE,          FALSE,      "method3",
                       "b",    "factor",       FALSE,         TRUE,       "method1",
                       "b",    "logical",      FALSE,         TRUE,       "method2",
    )
    
    # A tibble: 5 × 5
    #  type_analysis type_variable independence normality method 
    #  <chr>         <chr>         <lgl>        <lgl>     <chr>  
    #1 a             numeric       FALSE        TRUE      method1
    #2 a             numeric       TRUE         TRUE      method2
    #3 a             numeric       TRUE         FALSE     method3
    #4 b             factor        FALSE        TRUE      method1
    #5 b             logical       FALSE        TRUE      method2
    
    methods |> 
      filter(group == input$group,
             type_variable == input$type_variable) |>
      pull(method)