0

I'm trying to create a shiny app that generates plots based on the user selection of a subset of a loaded dataframe. For example, I have the following dataset:

library(shiny)
library(data.table)

df <- rbind(
  data.table( cat = rep('X', 40), grp = rep(LETTERS[1:4], each=10), x = rep(1:10, times=4), y = rnorm(40) ),
  data.table( cat = rep('Y', 30), grp = rep(LETTERS[1:3], each=10), x = rep(1:10, times=3), y = rnorm(30) ),  
  data.table( cat = rep('Z', 20), grp = rep(LETTERS[4:6], each=10), x = rep(1:10, times=2), y = rnorm(20) )
)

Based on the value for cat that the user selects in the UI, I want shiny to produce charts for each value of grp. So, if the user selects 'X', then there will be 4 plots produced; if they select 'Y' there will be three, and if they select 'Z' there will be 3.

I also want to specify how each chart is generated based on the value of grp. So if grp is A,D or E I want it produce a line plot, otherwise it should produce a scatterplot (only if that grp has that value of course).

Below is the code for my (broken) shiny app:

server <- function(input, output) {

  rv <- reactiveValues(
    i  = NULL,
    df = NULL
  )

  observe({ rv$i <- input$i })

  observe({ rv$df <- df[cat == rv$i] })

  output$test <- renderUI({
    plotList <- lapply( LETTERS[1:6], function(x) plotOutput(x) )

    do.call( tagList, unlist(plotList, recursive=FALSE))
  })

  for(i in LETTERS[1:6]){
    local({
      my_i <- i

      output[[my_i]] <- renderPlot({
        if( my_i %in% c('A','D','E')) {
          with(rv$df[grp == my_i], plot(x,y, type='l'))
        } else {
          with(rv$df[grp == my_i], plot(x,y))
        }
      })
    })
  }

}

ui <- fluidPage(
  titlePanel('Title'),

  sidebarLayout(
    sidebarPanel(
      helpText('Select the Category you would like to view.'),

      selectInput('i', 'Category', c('X','Y','Z'), selectize=TRUE)
    ),

    mainPanel(
      uiOutput('test')
    )
  )
)

shinyApp(ui, server)
1
  • 1
    does the answer work for you? Commented Dec 11, 2018 at 10:37

1 Answer 1

4
+50

A reproducible example can be found at the bottom.

A few hints:

1) Using reactive contexts:

In your for Loop at the bottom of the Server Code you are using the reactive variable rv, so you will have to run the Code in a reactive Content. So wrap it in observe().

2) Create a list of Outputs:

If I am not mistaken you used some of the Code in this answer: dynamically add plots to web page using shiny.

It is a good starting Point. For the part of the taglist it might be easier to simplify to:

output$test <- renderUI({
    lapply(unique(rv$df$grp), plotOutput)
})

You can also add tagList(), but it is not necessary here,...

3) Correcting the sample data:

You might want to update the df variable:

  data.table(cat = rep('Z', 20), grp = rep(LETTERS[4:6], each=10), 
             x = rep(1:10, times=2), y = rnorm(20) )

Here your have three letters, so you might change it to LETTERS[5:6] or update the other numbers.

Full reproducible example:

library(shiny)
library(data.table)

df <- rbind(
  data.table( cat = rep('X', 40), grp = rep(LETTERS[1:4], each=10), x = rep(1:10, times=4), y = rnorm(40) ),
  data.table( cat = rep('Y', 30), grp = rep(LETTERS[1:3], each=10), x = rep(1:10, times=3), y = rnorm(30) ),  
  data.table( cat = rep('Z', 30), grp = rep(LETTERS[4:6], each=10), x = rep(1:10, times=3), y = rnorm(30) )
)
server <- function(input, output) {

  rv <- reactiveValues(
    i  = NULL,
    df = NULL
  )

  observe({ rv$i <- input$i })

  observe({ rv$df <- df[cat == rv$i] })

  observe({
    for(letter in unique(rv$df$grp)){
      local({
        let <- letter
        output[[let]] <- renderPlot({
          if( let %in% c('A','D','E')) {
            with(rv$df[grp == let], plot(x, y, type='l'))
          } else {
            with(rv$df[grp == let], plot(x,y))
          }
        })
      })
    }
  })

  output$test <- renderUI({
    lapply(unique(rv$df$grp), plotOutput)
  })

}

ui <- fluidPage(
  titlePanel('Title'),
  sidebarLayout(
    sidebarPanel(
      helpText('Select the Category you would like to view.'),
      selectInput('i', 'Category', c('X','Y','Z'), selectize=TRUE)
    ),

    mainPanel(
      uiOutput('test')
    )
  )
)

shinyApp(ui, server)
Sign up to request clarification or add additional context in comments.

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.