Search code examples
rshinyshiny-servermethod-call

How to extract element name, not value, from a list in R Shiny selectInput()?


I would like to extract the element name, and not the specific value, from a list used for the choices argument in selectInput() from R Shiny.

The selectInput function looks like this:

# ...
selectInput("xvar", "What is the predictor variable?",
                        choices = list("MPG" = "mpg",
                                       "Cylinders" = "cyl",
                                       "Engine Displacement" = "disp",
                                       "Horse Power" = "hp",
                                       "Gears" = "gear"),
# ...

In my server.R code I would like to use, for example, "Cylinders" and not "cyl" as an axis label. For example (using ggplot2):

# ...
labs(x = input$xvar, y = input$yvar) +
# ...

names(input$xvar) returns NULL. Is there any way to call input$xvar and return the name?


Solution

  • Thanks to Paul's comments, the links he provided, and this SO thread, I was able to answer my question.

    Below I provide the old ui.R and server.R scripts which generated axis labels I was not happy with, as well as new ui.R and server.R scripts where the axis labels are improved. (Changes in the new scripts are marked with # diff)

    old ui.R:

    shinyUI(fluidPage(
        titlePanel("Fit Regression Line for Chosen Variables and Points"),
        sidebarLayout(
            sidebarPanel(
                h2("Model Specifics"), br(),
                selectInput("xvar", "What is the predictor variable?",
                            choices = list("MPG" = "mpg",
                                           "Cylinders" = "cyl",
                                           "Engine Displacement" = "disp",
                                           "Horse Power" = "hp",
                                           "Gears" = "gear"),
                            multiple = FALSE),
                selectInput("yvar", "What is the outcome variable?",
                            choices = list("MPG" = "mpg",
                                           "Cylinders" = "cyl",
                                           "Engine Displacement" = "disp",
                                           "Horse Power" = "hp",
                                           "Gears" = "gear"),
                            multiple = FALSE, selected = "cyl"),
                h4("Intercept"), textOutput("int"),
                h4("Slope"), textOutput("slope")
            ),
            mainPanel(
                br(), h2("Display"), h4("Drag to select which points to include in model"),
                plotOutput("plot", brush = brushOpts(id = "brush1"))
            )
        )
    ))
    

    old server.R:

    shinyServer(function(input, output) {
            model <- reactive({
                    points <- brushedPoints(mtcars, brush = input$brush1,
                                            xvar = input$xvar,
                                            yvar = input$yvar)
                    if(nrow(points) <= 1) {
                            return(NULL)
                    } else {
                            lm(as.formula(paste0(input$yvar,
                                                 "~", input$xvar)),
                               data = points)
                    }
            })
            output$int <- renderText({
                    if(is.null(model())) {
                            "Too few data points selected"
                    } else {
                            round(model()[[1]][1], 2)
                    }
            })
            output$slope <- renderText({
                    if(is.null(model())) {
                            "Too few data points selected"
                    } else {
                            round(model()[[1]][2], 2)
                    }
            })
            output$plot <- renderPlot({
                    library(ggplot2)
                    ggplot(mapping = aes(x = mtcars[, input$xvar],
                                         y = mtcars[, input$yvar])) +
                            theme_minimal() +
                            geom_point() +
                            labs(x = input$xvar, y = input$yvar) +
                            coord_cartesian(x = c(0, 1.2*max(mtcars[, input$xvar])),
                                            y = c(0, 1.2*max(mtcars[, input$yvar]))) +
                    if(!is.null(model())) {
                            geom_abline(intercept = model()[[1]][1], slope = model()[[1]][2],
                                        colour = "red", lwd = 2, alpha = 0.3)
                    }
            })
    })
    

    Changes in the scripts are marked with # diff

    new ui.R:

    shinyUI(fluidPage(
        titlePanel("Fit Regression Line for Chosen Variables and Points"),
        sidebarLayout(
            sidebarPanel(
                h2("Model Specifics"), br(),
                uiOutput("si_xvar"), # diff
                uiOutput("si_yvar"), # diff
                h4("Intercept"), textOutput("int"),
                h4("Slope"), textOutput("slope")
            ),
            mainPanel(
                br(), h2("Display"), h4("Drag to select which points to include in model"),
                plotOutput("plot", brush = brushOpts(id = "brush1"))
            )
        )
    ))
    

    new server.R:

    shinyServer(function(input, output) {
        varlist <- list("MPG" = "mpg",  # diff
                        "Cylinders" = "cyl",
                        "Engine Displacement" = "disp",
                        "Horse Power" = "hp",
                        "Gears" = "gear")
        output$si_xvar <- renderUI(     # diff
            selectInput("xvar", "What is the predictor variable?",
                        choices = varlist,
                        multiple = FALSE)
        )
        output$si_yvar <- renderUI(     # diff
            selectInput("yvar", "What is the outcome variable?",
                        choices = varlist,
                        multiple = FALSE, selected = "cyl")
        )
        model <- reactive({
            points <- brushedPoints(mtcars, brush = input$brush1,
                                    xvar = input$xvar,
                                    yvar = input$yvar)
            if(nrow(points) <= 1) {
                return(NULL)
            } else {
                lm(as.formula(paste0(input$yvar,
                                     "~", input$xvar)),
                   data = points)
            }
        })
        output$int <- renderText({
            if(is.null(model())) {
                "Too few data points selected"
            } else {
                round(model()[[1]][1], 2)
            }
        })
        output$slope <- renderText({
            if(is.null(model())) {
                "Too few data points selected"
            } else {
                round(model()[[1]][2], 2)
            }
        })
        output$plot <- renderPlot({
            library(ggplot2)
            ggplot(mapping = aes(x = mtcars[, input$xvar],
                                 y = mtcars[, input$yvar])) +
                theme_minimal() +
                geom_point() +
                labs(x = names(which(input$xvar == varlist)),       # diff
                     y = names(which(input$yvar == varlist))) +     # diff
                coord_cartesian(x = c(0, 1.2*max(mtcars[, input$xvar])),
                                y = c(0, 1.2*max(mtcars[, input$yvar]))) +
                if(!is.null(model())) {
                    geom_abline(intercept = model()[[1]][1], slope = model()[[1]][2],
                                colour = "red", lwd = 2, alpha = 0.3)
                }
        })
    })