0

I am challenged trying to implement a feature into my Shiny app. The problem is two-fold:

  1. Is it possible to have 2 inputs from the same variable? I have one variable that is a list of indicators. I want the user to be able to select 2 indicators with selectInput, and then draw a scatter plot. There has to be 2 selectInputs because other parts of the app will rely on only the first selectInput. My data is long. I don't think it will work if I make it wide because my data includes latitude and longitude information so it wouldn't make sense to create a selectInput with names(data), for example.

  2. If I can have 2 selectInputs from the same variable, how would I call the values in my plot, since the value is called 'value' for both the inputs?

EDIT: Following Gregor's suggestion to reference the inputs with aes_string, I would expect the following example of mtcars gathered into long format to work, but I instead get an aesthetics or object not found error. I think I probably need to filter the data, but I don't understand how I can do that since my variable indicators now refers to both 'indicators' and 'indicators2'. I.e., I can't have

filtered <- 
      cars %>%
      filter(indicators == input$indicators,
             indicators == input$indicators2) 

Maybe I need to create a reactive expression that creates a new data frame instead? This is my non-working reproducible code with long-form mtcars:

library(ggplot2)
library(shiny)

cars <- mtcars %>%
  gather(indicators, value, mpg:carb)


ui <- fluidPage(

  # Application title
  titlePanel("mtcars"),

  sidebarLayout(
    sidebarPanel(
      selectInput("indicators",
                  label = "select indicator:",
                  choices = c("mpg", "cyl",  "disp", "hp",  "drat", "wt",   "qsec", "vs",   "am",   "gear", "carb")
                    ),
      selectInput("indicators2",
                  label = "select indicator:",
                  choices = c("mpg", "cyl",  "disp", "hp",  "drat", "wt",   "qsec", "vs",   "am",   "gear", "carb")
                  )
    ),

    mainPanel(
      plotOutput("carsPlot")
    )
  )
)

server <- function(input, output) {

  output$carsPlot <- renderPlot({
    ggplot(cars, aes_string(x = input$indicators, y = input$indicators2)) +
      geom_point(shape = 1)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

3 Answers 3

1

You can use aes_string to pass input$indicators and input$indicators2 to ggplot like this. There is no need to cast your data into wide format since ggplot can actually handle long data better.

library(ggplot2)
library(shiny)

ui <- fluidPage(
  # Application title
  titlePanel("mtcars"),
  sidebarLayout(
    sidebarPanel(
      selectInput("indicators",
                  label = "select indicator:",
                  choices = names(mtcars)),
      selectInput("indicators2",
                  label = "select indicator:",
                  choices = names(mtcars))
    ),
    mainPanel(
      plotOutput("carsPlot")
    )
  )
)

server <- function(input, output) {
  output$carsPlot <- renderPlot({
    ggplot(mtcars, aes_string(x = input$indicators, y = input$indicators2)) +
      geom_point(shape = 1)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
Sign up to request clarification or add additional context in comments.

3 Comments

Fantastic! Thank you. I think that this is what I was looking for. I know know that: a) we can have 2 inputs for the same variable, and b) how to reference them in the plot. I am still fairly new at this and didn't know about aes_string.
Actually it looks like I spoke to soon. This answer works because ggplot is calling mtcars, not the long format cars. In long format, it gives object not found errors.
The thing is I am not really sure what you want. Please update your reproducible example if you want better answers. Maybe take a look at this to create a long version of the mtcars dataset.
0

Here another solution with a selectInput in multiple mode.

library(dplyr)
library(tidyr)
library(ggplot2)
library(shiny)

cars <- mtcars %>%
  gather(indicators, value, mpg:carb)


ui <- fluidPage(

  titlePanel("mtcars"),

  sidebarLayout(
    sidebarPanel(
      uiOutput("ui_indicators")
    ),

    mainPanel(
      plotOutput("carsPlot")
    )
  )
)

server <- function(input, output) {

  output$ui_indicators <- renderUI({
    choices <- unique(cars$indicators)
    selectInput("indicators",
                label = "select indicators :",
                choices = choices,
                multiple = TRUE)
  })


  output$carsPlot <- renderPlot({

    filtered <- cars %>% filter(indicators %in% input$indicators)

    ggplot(filtered, aes(x = indicators, y = value)) +
      geom_point(shape=1)

  })
}

# Run the application 
shinyApp(ui = ui, server = server)

1 Comment

Thank you, this works for the scatter plot. I didn't want to use this technique, however, because I have some other plots as a part of the app that rely on only one input.
0

Building on the tip from Gregor on aes_string, I managed to fix this. I ended up using the wide data and adding a proper reactive statement that creates a new data frame out of the selected indicators.

My server function now looks like this:

server <- function(input, output) {

  selectedVars <- reactive({
    cars[, c(input$indicators, input$indicators2)]
  })

  output$carsPlot <- renderPlot({
    ggplot(selectedVars(), aes_string(x = input$indicators, y = input$indicators2)) +
      geom_point(shape = 1)
  })
}

All works beautifully, and I am beginning to learn more about the utility of reactive functions in Shiny :)


Gregor de Cillia provided the answer I was looking for. The two inputs (which are not a problem) can be referenced using aes_string.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.