2

I'm creating a Shiny application and I've run into a problem when choosing multiple inputs in a selectizeInput box and trying to subset my data using those choices.

Here is the intended output

testDT <- data.table(
    L = (1:32), 
    M = rep(letters[23:26], each = 64), 
    N = rep(LETTERS[1:2], times = 2, each = 512),
    O = rnorm(2048, 1))

testDT$L <- factor(testDT$L, levels = seq(from = 1, to = 32, by = 1))

ggplot(testDT, aes(L,O)) +
    geom_boxplot(aes(fill = N)) +  
    theme_bw() +
    theme(legend.position = "top", legend.title=element_blank()) + 
    facet_grid(M ~ ., scales = "free") +
    labs(x = "L", y = "O")

However, when I create the application, the graph output is not as intended. The more options I select, for example in N, it seems as if the data begins to alternate.

Here's the ui.R file:

# ui.R

shinyUI(fluidPage(

            titlePanel("Test Application"),

            sidebarLayout(
                    sidebarPanel(

                            selectizeInput("N",
                                    label = ("N"),
                                    multiple = TRUE,
                                    choices = NULL,
                                    options = list(
                                            placeholder = 'Select All Desired, Type to Search',
                                            onInitialize = I('function() { this.setValue(""); }')
                                    )),

                            selectizeInput("M", 
                                    label = "M",
                                    multiple = TRUE,
                                    choices = NULL,
                                    options = list(
                                            placeholder = 'Select All Desired, Type to Search',
                                            onInitialize = I('function() { this.setValue(""); }')
                                    ))
                    ),

                    mainPanel(
                            tabsetPanel(
                                    tabPanel("Test Plot 1",
                                            plotOutput("testPlot1")),
                                    tabPanel("Test Plot 2",
                                            plotOutput("testPlot2"))


                    )
            ))))

And here is the server.R file:

# server.R

library(data.table)
library(ggplot2)

testDT <- data.table(
    L = (1:32), 
    M = rep(letters[23:26], each = 64), 
    N = rep(LETTERS[1:2], times = 2, each = 512),
    O = rnorm(2048, 1))

testDT$L <- factor(testDT$L, levels = seq(from = 1, to = 32, by = 1))

shinyServer(function(input, output, session) {

        updateSelectizeInput(session, "N", 
                server = TRUE, 
                choices = sort(unique(testDT$N)),
        )

        updateSelectizeInput(session, "M", 
                server = TRUE, 
                choices = unique(testDT$M),
        )       

        testDT1 <- reactive({
                    subset(testDT, N == input$N)
                })

        testDT2 <- reactive({
                    subset(testDT, N == input$N & M == input$M)
                })

        output$testTable <- renderDataTable(testDT1())

        output$testPlot1 <- renderPlot({

                    p <- ggplot(testDT1(), aes(L,O)) +
                            geom_boxplot(aes(fill = N)) +  
                            theme_bw() +
                            theme(legend.position = "top", legend.title=element_blank()) + 
                            facet_grid(M ~ ., scales = "free") +
                            labs(x = "L", y = "O")
                    print(p)
                })

        output$testPlot2 <- renderPlot({

                    p <- ggplot(testDT2(), aes(L,O)) +
                            geom_boxplot(aes(fill = N)) +  
                            theme_bw() +
                            theme(legend.position = "top", legend.title=element_blank()) + 
                            facet_grid(M ~ ., scales = "free") +
                            labs(x = "L", y = "O")
                    print(p)
                })
    })

I have a strong suspicion that I am subsetting the data incorrectly, but as I am new to the Shiny environment, I don't fully understand the behavior when subsetting using an input$_____ call, like below.

testDT1 <- reactive({
      subset(testDT, N == input$N)
      })
black_sheep07
  • 2,308
  • 3
  • 26
  • 40

1 Answers1

2

I would recommend to use subsetting from [ operator instead of subset function.
Read SO question In R, why is [ better than subset? for more details on that.
In your example:

testDT1 <- reactive({
      testDT[eval(call("==", as.name("N"), input$N))]
})

Change == to %in% for multi value subset.

Also be aware it may be worth to use data.table index as it can dramatically speed up filtering, so gives real-time filtering for your shiny application. For more details see my blog post Scaling data.table using index.
In fact index should be created automatically during the first filtering, you may prepare it after loading your dataset with set2keyv function.

jangorecki
  • 16,384
  • 4
  • 79
  • 160
  • 1
    Can you provide a method to use data.table.index for this example? I'm very curious about it. – black_sheep07 Dec 07 '15 at 00:57
  • 1
    @black_sheep07 there is no specific method, read linked blog post for more details on data.table index, including usage and usage tracking. – jangorecki Dec 07 '15 at 01:17
  • 2
    I am now using `data.table.index` but the speed bottleneck is most definitely in `ggplot2`, not the indexing. I will be using this going forward, so thanks for the heads up! – black_sheep07 Dec 07 '15 at 01:26