Flexdashboard: use of several inputs to create dynamic boxplot

I'm building a R Markdown flexdashboard and I'm having a problem to make an interactive boxplot, ...

Background:

The database "yield" includes:

  1. Four continuous variables named First.Step, Second.Step , Third.Step , Overall.process and to be selected separetaly as y-axis in my box plot using selectInput Response;

  2. Two categorical variables named Flavor and Plasma and to be selected to change the values of my box plot with selectInput Flavor and selectInput Plasma;

  3. One categorical variable Line used as x-axis (fixed anytime).

In total, I have three selectInputs placed in a side column to modify my boxplot.

Issue:

I can indeed use the selectInput Response to select one of the four continuous variables. the box plot automatically changes and it's great! Now I would like to do the same with the other selectinputs ... but I'm struggling to find the answers here or there.

Code:

---
title: Dashboard
output: 
  flexdashboard::flex_dashboard:
    vertical_layout: fill
runtime: shiny
---

```{r load}
library(xlsx)
library(ggplot2)
yield <- read.csv("test.csv")
```

```{r inputs}
selectInput("Response", label = "Yield:",
            choices = c("First.Step", "Second.Step", "Third.Step", "Overall.process"), selected = "Overall.process")

selectInput("Flavor", label = "P Flavor:",
            choices = c("LA", "VN", "RI", "SQ"), selected = "LA")

selectInput("Plasma", label = "P Type:",
            choices = c("SRC", "REC"), selected = "REC")
```

```{r boxplot}
renderPlot(
    ggplot(yield,aes_string(yield$Line,y=input$Response, fill=yield$Line)) +
    geom_boxplot(varwidth = TRUE, alpha=0.2) +
    geom_jitter(color="black", width= 0.15, size=0.4, alpha=0.9) +
    labs(fill="")
)
```

My guess is that I need to use the function reactive() and create a subset including the other selectInputs. I've tried so many things. Currently my boxplot code only contains the selectInputs "Response" .. so no wonder it can't be changed with the two other selectInputs.

Being newbie, your help is more than welcome to answer the question and/or improve my coding skills. KR

I am not sure what you want the plot to look like. Can you post the ggplot code that you would use to make one of the plots outside of shiny, that is, non-reactively?

ggplot(yield, x= Line, y= First.step) + geom_boxplot
#Line is either Line A or Line B
#First.step is quantitative output measured after step 1

Using flexdashboard, i want to be able to change the y axis using the selectinput response But also use the two other inputs (Flavor and Plasma) to only select part of the dataset.

So:

  1. Get boxplot for First.step continuous output for LA and SRC categories
  2. Or after changing the inputs in the side column, get boxplot for third.step continuous output for VN and REC categories,etc

Hope it is clear. Thanks

I adapted a shiny app I had at hand to demonstrate using reactive() to filter a data frame on two variables and plotting two other variables. You would want to also change the variable on the y axis but it seems you have that in hand. Note that I use Tbl() as the data argument of ggplot() and Tbl is the value returned by reactive().

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

set.seed(3)
DF <- data.frame(Date = seq.Date(from = as.Date("2019-01-01"), 
                                 to = as.Date("2019-01-24"), by = "day"),
                 Company = rep(c("A", "B"), 12), 
                 ApprovalID = sample(c("AD", "GF"), 24, replace = TRUE),
                 State = sample(c("NY", "CO"), 24, replace = TRUE),
                 Value = rnorm(24, mean = 10, sd = 3))
ui <- fluidPage(
  fluidRow(
  column(width = 3, selectInput("Comp", label = "Company",
                                choices = list("A", "B") )),
  column(width = 3), selectInput("State", "State", 
                                 choices = list("NY", "CO"))
  ),
  fluidRow(
  column(width = 4, tableOutput("TBL"), tableOutput("AG")),
  column(width = 8, plotOutput("Plot"))
  )
)

server <- function(input, output) {
  Tbl <- reactive({
    DF %>% filter(Company == input$Comp, State == input$State)
  })
  
  output$AG <- renderTable({
    Tbl() 
  })
  output$Plot <- renderPlot({
    ggplot(Tbl(), aes(x = ApprovalID, y = Value)) + geom_boxplot()
  })
}

# Return a Shiny app object
shinyApp(ui = ui, server = server)

Thanks a lot for sharing ! Super useful I can use now my two categorical variables Flavor Plasma to change the boxplot.

selectedData <- reactive({
    yield %>% filter(Flavor == input&input2, Plasma == input&input3)
})
Plot <- renderPlot({
    ggplot(selectedData(),aes(Line, First.step))+
    geom_boxplot()
})

Note that if input$Response from selectInput Responseis used in the aes to change my y axis then I have a error message ... missing aes for y.

My guess is selectInput Response contains the following variables First.step Second.step``Third.stepd``Overall.stepwhich are in four different columns in the dataset .. unlike selectInput Flavor or selectInput Plasma.

I'll try this workaround: gather() the four numeric columns in order to get one column with the values (numeric) and one column with the steps name (category). I'll include steps name (category) in the reactive() and include the values (numeric) in the boxplot aes. Should work right?

  1. Do you know why you needed to use tbl() and not tbl ?

  2. What are the class / nature of selectInput ? Input&Comp ?

Thanks again for the codes and for helping me finding new solutions and ideas !

1 Like

The object returned by selectInput() is a vector of characters, with a length of one unless multiple is TRUE. aes_string() will take string arguments. To use the value of input$Response in ggplot, try

Plot <- renderPlot({
    ggplot(selectedData(), aes_string ("Line", input$Response)) +
    geom_boxplot()
})

Great it works perfectly !!!

Many Thanks for your quick help !

I tried to apply the pattern you showed above to create a timeseries plot with ggplot (after sorting my observation by date)

yield <- read.csv("test.csv",stringsAsFactors = F) %>% mutate(date=mdy(Date)) %>% arrange(date)

```{r}
renderPlot({
    ggplot(selectedData(),aes_string("Date", input$input1)) +
    geom_line(aes(color="Line"))
})

Using this code, I can see the plot (y-axis, x-axis etc ..) but there is no y values / no datapoint.
Is there anything specific to timeseries ? I thought applying the same code structure will work for each ggplot plot / graph.


Many thanks ! Michael

It is hard to say without knowing more about your data set. I would change your call to geom_line() to either

geom_line(aes(color = Line))

or

geom_line(aes_string(color = "Line"))

Then I would get the data manipulation and plotting to work outside of a reactive environment. Debugging is just easier if you are not dealing with reactive elements. Filter and plot your data with the same functions but substitute one of the possible input values. For example, if you have

%>% filter(input$Plasma == ColName)

use

%>% filter("SRC" == ColName)

If you cannot get that to work, post a small data set and your non-reactive code and it will be easier to figure out. Adapting a functioning set of code to a reactive environment should be easier.

I've tried to use either aes() or aes_string() without succes ...

Here is the non reactive code (it's working at least :slight_smile:)
Note: it is the same dataset than the one used for the boxplots.

library(tidyverse)
library(lubridate)
yield <- read.csv("test.csv")
newdate <- mdy(yield$Date)
ggplot(yield,aes(x=newdate, y=CM.Step)) + geom_line(aes(color=Line)) + xlab("") + facet_wrap(~ Line)

Here is my full code and the latest I've tried for the timeseries plot but it seems that there is an issue with the x aes (Date?):

---
title: Global IG Efficiencies Dashboard
output: 
  flexdashboard::flex_dashboard:
    vertical_layout: fill
runtime: shiny
---

```{r load-packages}
library(xlsx)
library(ggplot2)
library(magrittr)
library(lubridate)
library(tidyverse)
yield <- read.csv("test.csv")
selectInput("input1", label = "IG Yield:",
            choices = c("CM.Step", "ANX.Step", "Sterile.Step", "Overall.downstream"), selected = "Overall.downstream")

selectInput("input2", label = "P Flavor:",
            choices = c("LA", "VN", "RI", "SQ"), selected = "LA")

selectInput("input3", label = "P Type:",
            choices = c("Source", "Recovered"), selected = "Source")
selectedData <- reactive({
  yield %>% filter(Flavor == input$input2, Plasma == input$input3)
})
renderPlot({
    ggplot(selectedData(),aes_string("Line", input$input1, fill="Line")) +
    geom_boxplot(varwidth = TRUE, alpha=0.2) +
    stat_summary(fun.y=mean, geom="point", shape=20, size=3, color="black", fill="black") +
    geom_jitter(color="black", width= 0.15, size=0.4, alpha=0.9) +
    labs(fill="")
})
newdate <- mdy(yield$Date)
renderPlot({
    ggplot(selectedData(),aes_string("newdate", input$input1)) + geom_line(aes_string(color="Line")) + xlab("") + facet_wrap(~ Line)
})

PS: I cannot upload my csv file / ma dataset.
i will create an example with a new dataset using R functions if my code above is not helping

Thanks !

I am not seeing the problem, so a data set would be very helpful. Please put the code to make the data set within the document and copy the entire code of the document in one piece so there is no doubt that we are looking at the same thing you are. Thanks!

I've created a simple dataset (quite close to my original dataset) and posted the entire code for non reactive and reactive timeseries below. You know what .. it works with it haha ! I can change the inputs nicely.
Now I need to compare the two codes / datasets. Well we are progressing :slight_smile:

---
title: Global IG Efficiencies Dashboard
output: 
  flexdashboard::flex_dashboard:
    vertical_layout: fill
runtime: shiny
---

```{r load-packages}
library(ggplot2)
library(magrittr)
library(tidyverse)
a<-LETTERS[seq(from = 1, to = 26)]
b<-seq(as.Date("2016/1/1"), by="month",length.out=26)
c<-c((rep("L1",13)),rep("L4",13))
d<-c((rep("LA",8)),rep("SQ",6),rep("VI",6),rep("RI",6))
e<-c((rep("SRC",13)),rep("REC",13))
f<-seq(20,200,length.out=26)
g<-seq(60,180,length.out=26)
h<-seq(65,85,length.out=26)
DF<- data.frame("Lot"=a, "Date"=b, "Line"=c, "Flavor"=d, "Plasma"=e, "Yield1"=f, "Yield2"=g, "Yield3"=h)
selectInput("input1", label = "Step",
            choices = c("Yield1", "Yield2", "Yield3"), selected = "Yield3")

selectInput("input2", label = "Facility",
            choices = c("LA", "VI", "RI", "SQ"), selected = "LA")

selectInput("input3", label = "Type",
            choices = c("SRC", "REC"), selected = "SRC")
selectedData <- reactive({
  DF %>% filter(Flavor == input$input2, Plasma == input$input3)
})

ggplot(DF,aes(Date, Yield3)) + geom_line(aes(color=Line)) + facet_wrap(~ Line)

renderPlot({
    ggplot(selectedData(),aes_string("Date", input$input1)) + geom_line(aes_string(color="Line")) + facet_wrap(~ "Line")
})

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.