```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, error = F,
message = F, warning = F)
library(shiny)
library(emoji)
library(shinyjs)
```
```{css echo=FALSE}
pre {
max-height: 700px;
overflow-y: auto;
}
pre[class] {
max-height: 500px;
}
.scroll-100 {
max-height: 500px;
overflow-y: auto;
background-color: inherit;
}
```
## Shiny app logic I {.build}
`ui` (**U**ser **I**nterface)
The container, whatever sees the user
`server`
It gets the work done
`server` and `ui` talks to each other in a flow:
> `ui` (input) $\rightarrow$ `server` (elaborate and compute) $\rightarrow$ `ui` (output)
>
> - Define something in the `ui` and not using in the server: nothing happens, it just doesn't exist
>
- Calling something in the server that has not been defined in the `ui`: errors everywhere
## Shiny app logic II {.build}
First things first:
```{r eval = FALSE}
install.packages("shiny") # install
library(shiny) # use it
```
And then:
```{r eval = FALSE}
ui = fluidPage( # Define the ui
[...]
)
server = function(input, output){ # Define the server
[...]
}
shinyApp(ui, server) # create the App
```
Yes... it's **that** easy
## Be tidy, be consistent, save time
- Use `R` projects with the default for shiny app creations
- 10 minutes coding $=$ 1 hour of debugging
- If the app is particularly complex and long, it's better to save `ui` and `server` in two different scripts
## To each its own: Input in UI
```{r eval=FALSE, class.source="myClass"}
sliderInput() # Slider input widget
numericInput() # Numeric input control
selectInput() # Select list input control
checkboxInput() # Checkbox input control
checkboxGroupInput()
dateInput() # Date input
fileInput() # File upload control
radioButtons() # Radio buttons
textInput() # Text input control
passwordInput() # Password input control
actionButton() # Action button
dateInput() # Date input
dateRangeInput() # Input a data range
```
[Complete list](https://shiny.rstudio.com/gallery/widget-gallery.html) (with code)
```{r eval=FALSE, class.source="myClass"}
selectInput("mySelection", label = h3("Select box"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1)
```
## To each its own: Output in UI
```{r eval=FALSE}
plotOutput() # Plot output element
textOutput() # Text output element
verbatimTextOutput() # Verbatim text output element
tableOutput() # Table output element
dataTableOutput() # Data table output element
htmlOutput() # HTML output element
uiOutput() # user interface element
downloadButton() # Download button
Progress() # Reporting progress (object oriented)
withProgress() # Reporting progress (functional)
outputOptions() # Set options for an output object
```
Labels:
```{r eval = FALSE}
verbatimTextOutput(
outputId = "myOutput"
)
```
## To each its own: Output containers in server
```{r, eval =FALSE}
renderPlot() # Plot output
renderText() # Text output
renderPrint() # Printable output
renderTable() # Table output
renderDataTable() # Data table output
renderImage() # Image file output
renderUI() # UI output
downloadHandler() # File downloads
```
```{r eval=FALSE}
server = function(input, output) {
output$myOutput = renderText({
paste(paste("This is my choice"), input$mySelection)
})
}
```
## App layout
```{r eval=FALSE}
fluidPage() # rows with columns within 12-unit
# wide grid
fluidRow( # custom the page in two columns
column(6, ), # of width 6 out of the 12-unit
column(6) # on a single row
)
sidebarLayout( # automatic layout with
sidebarPanel(...), # sidebar and
mainPanel(...) # main area
)
# and many more!
```
[Complete list](https://shiny.rstudio.com/gallery/) (look for "Application layout")
## Let's start with an easy (ugly) one: Practice
```{r, eval = TRUE, echo=FALSE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset", # name of the input (for the server)
label = "Choose a dataset:", # name of the input (for the users)
choices = c("rock", "pressure", "cars")) # options (for both
# users & server)
),
mainPanel(
plotOutput( # define the graphical output (we're telling R that this output
"graph" # container must contain a plot)
),
verbatimTextOutput( # define the graphical output (we're telling R that
"summary" # this output container must contain a Verbatim output)
)
)
)
),
server = function(input, output){
output$graph <- renderPlot({
if(input$dataset == "rock"){ # call the input and its options with their label
data <- rock
} else if (input$dataset == "pressure" ){
data <- pressure
} else if (input$dataset == "cars") {
data <- cars
}
plot(data[, c(1:2)])
})
output$summary <- renderPrint({
if(input$dataset == "rock"){
data <- rock
} else if (input$dataset == "pressure" ){
data <- pressure
} else if (input$dataset == "cars") {
data <- cars
}
summary(data[, c(1:2)])
})
},
options = list(height = 800)
)
```
## Let's start with an easy (ugly) one: Code
```{r, echo = TRUE, message = FALSE, eval = FALSE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset", # name of the input (for the server)
label = "Choose a dataset:", # name of the input (for the users)
choices = c("rock", "pressure", "cars")) # options (for both
# users & server)
),
mainPanel(
plotOutput( # define the graphical output (we're telling R that this output
"graph" # container must contain a plot)
),
verbatimTextOutput( # define the graphical output (we're telling R that
"summary" # this output container must contain a Verbatim output)
)
)
)
),
server = function(input, output){
output$graph <- renderPlot({
if(input$dataset == "rock"){ # call the input and its options with their label
data <- rock
} else if (input$dataset == "pressure" ){
data <- pressure
} else if (input$dataset == "cars") {
data <- cars
}
plot(data[, c(1:2)])
})
output$summary <- renderPrint({
if(input$dataset == "rock"){
data <- rock
} else if (input$dataset == "pressure" ){
data <- pressure
} else if (input$dataset == "cars") {
data <- cars
}
summary(data[, c(1:2)])
})
},
options = list(height = 800)
)
```
## Don't repeat yourself, use the "shelf" solution
```{r, eval = FALSE}
shinyApp(
ui = fluidPage( # the UI didn't change at all
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars"))
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues() # create the shelf with reactive values
dataInput <- reactive({ # create a reactive envrinoment (it reacts to whatever input receives)
if(input$dataset == "rock"){ # this part is the same as before
data <- rock
} else if (input$dataset == "pressure" ){
data <- pressure
} else if (input$dataset == "cars") {
data <- cars
}
})
observe({ # ta-da, the shelf is in action. To make it works,telling R
values$data <- data.frame(dataInput()) # it has to be called inside an observe function,
}) # we're using a reactive object
output$graph <- renderPlot({
plot(values$data[, c(1:2)]) # call the shelf and you're all set
})
output$summary <- renderPrint({
summary(values$data)
})
},
options = list(height = 800)
)
```
## Take things slowly and use the action buttons
There are two ways of using the action buttons:
1. Use `eventReactive()`
2. Use the shelf we have seen before and adding the action button
(Throughout the course $\rightarrow$ solution number 2)
## Action button solution 1: Practice
```{r, echo = FALSE, eval= TRUE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3)),
actionButton("load", "Select dataset")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)))),
server = function(input, output){
dataInput = eventReactive(input$load, {
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
}
}
)
output$graph <- renderPlot({
data = dataInput()
plot(data[, c(1:2)])
})
output$summary <- renderPrint({
data = dataInput()
summary(data[, c(1:2)])
})
},
options = list(height = 800)
)
```
## Action button solution 1: Code
```{r, echo = TRUE, eval= FALSE}
shinyApp(
ui = fluidPage( # same as before
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1, # we add numbers to the choices
"pressure" = 2, # (more convenient)
"cars" = 3)),
actionButton("load", "Select dataset")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)))),
server = function(input, output){ # new shelf
dataInput = eventReactive(input$load, { # here's the action for the button
if(input$dataset == 1){ # call the input and its options with their label
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
}
}
)
output$graph <- renderPlot({
data = dataInput()
plot(data[, c(1:2)])
})
output$summary <- renderPrint({
data = dataInput()
summary(data[, c(1:2)])
})
},
options = list(height = 800)
)
```
## Action button solution 2: Practice
```{r, echo = FALSE, eval= TRUE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3)),
actionButton("load", "Upload data")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
})
output$graph <- renderPlot({
plot(values$data[, c(1:2)])
})
output$summary <- renderPrint({
summary(values$data)
})
},
options = list(height = 800)
)
```
## Action button solution 2: Code
```{r, echo = TRUE, eval= FALSE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3)),
actionButton("load", "Upload data")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
}
})
observeEvent(input$load, { # Use the observeEvent function to make the UI and
values$data <- data.frame(dataInput()) # server communicate again
})
output$graph <- renderPlot({
plot(values$data[, c(1:2)])
})
output$summary <- renderPrint({
summary(values$data)
})
},
options = list(height = 800)
)
```
## Don't scare the users: Practice
```{r echo=FALSE, eval=TRUE}
shinyApp(
ui = fluidPage( # same as before
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3)),
actionButton("load",
"Upload data")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
})
output$graph <- renderPlot({
validate(
need(input$load > 0,
"Waiting for data")
)
plot(values$data[, c(1:2)])
})
output$summary <- renderPrint({
validate(
need(input$load > 0, "Waiting for data")
)
summary(values$data)
})
},
options = list(height = 800)
)
```
## Don't scare the users: Code
```{r echo=TRUE, eval=FALSE}
shinyApp(
ui = fluidPage( # same as before
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3)),
actionButton("load",
"Upload data")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
})
output$graph <- renderPlot({
validate( # validate function: I need something to be validated for letting
need(input$load > 0, # you see what's hidden behind me
"Waiting for data") # If it's not validated, I'll show you this message
)
plot(values$data[, c(1:2)])
})
output$summary <- renderPrint({
validate(
need(input$load > 0, "Waiting for data") # Waiting message
)
summary(values$data)
})
},
options = list(height = 800)
)
```
## Let the users use their own data: Practice
```{r echo = FALSE,eval=TRUE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3,
"I want to use my data!!" =4)), # we add an option
# Let me introduce you Mr. Conditional Panel
conditionalPanel(
condition = "input.dataset == '4'", # What is the condition for which I should show up?
# What should be displayed inside me once I show up?
fileInput("example", # label for the server
"Wow my data set!",
accept = c("csv")) # what format do we accept?
),
actionButton("load", "Upload data")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
)
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
} else if (input$dataset == 4) {
data <- read.csv(input$example$datapath) # we call the input for the data
#import by its label and we ask for the data path selected by the user
}
})
observeEvent(input$load, # we load the data set (whatever it is only once the
# user has hit the button)
{
values$data <- data.frame(dataInput())
})
output$graph <- renderPlot({
validate(
need(input$load > 0, "Waiting for data")
)
if (any(colnames(values$data) == "condition") ){ # I had to change the code
#just for the new data set, which is different from all the others
# check if there are characters
if (any(sapply(values$data, is.character)) == TRUE) {
values$data[, sapply(values$data, is.character) == T] = lapply(values$data[, sapply(values$data, is.character) == T],
as.factor)
} else {
values$data = values$data
}
plot(values$data$tr ~ values$data$condition,
xlab = "Condition", ylab = "TR")
} else {
plot(values$data[, c(1:2)])
}
})
output$summary <- renderPrint({
validate(
need(input$load > 0, "Waiting for data")
)
if (any(colnames(values$data) == "condition") ){
summary(values$data[, c(2:3)])
} else {
summary(values$data[, c(1:2)])
}
})
},
options = list(height = 800)
)
```
## Let the users use their data: Code
```{r echo = TRUE,eval=FALSE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3,
"I want to use my data!!" =4)), # we add an option
# Let me introduce you Mr. Conditional Panel
conditionalPanel(
condition = "input.dataset == '4'", # What is the condition for which I should show up?
# What should be displayed inside me once I show up?
fileInput("example", # label for the server
"", # no displayed label for users
accept = c("csv")) # what format do we accept?
),
actionButton("load", "Upload data")
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){ # now we use the number associated with each dataset
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
} else if (input$dataset == 4) {
data <- read.csv(input$example$datapath) # we call the input for the data
#import by its label and we ask for the data path selected by the user
}
})
observeEvent(input$load, # we load the data set (whatever it is only once the
# user has hit the button)
{
values$data <- data.frame(dataInput())
})
output$graph <- renderPlot({
validate(
need(input$load > 0, "Waiting for data")
)
if (any(colnames(values$data) == "condition") ){ # I had to change the code
#just for the new data set, which is different from all the others
# check if there are characters
if (any(sapply(values$data, is.character)) == TRUE) {
values$data[, sapply(values$data, is.character) == T] = lapply(values$data[, sapply(values$data, is.character) == T],
as.factor)
} else {
values$data = values$data
}
plot(values$data$tr ~ values$data$condition,
xlab = "Condition", ylab = "TR")
} else {
plot(values$data[, c(1:2)])
}
})
output$summary <- renderPrint({
validate(
need(input$load > 0, "Waiting for data")
)
if (any(colnames(values$data) == "condition") ){
summary(values$data[, c(2:3)])
} else {
summary(values$data[, c(1:2)])
}
})
},
options = list(height = 800)
)
```
## Code has to be fluid and adapt to everything (like a cat)
```{r, out.width = "15%", fig.align='center', echo = FALSE}
knitr::include_graphics("liquid-cats1.jpg")
```
We have the code for uploading a data frame.
The code I provided for the previous app is specifically designed to work for that specific data frame
If only we had a way to explore the data frame columns and choose the ones we would like to plot `r emoji("thinking")`
## Practice
```{r echo=FALSE, eval=TRUE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3,
"I want to use my data!!" =4)),
conditionalPanel(
condition = "input.dataset == '4'",
fileInput("example",
"", accept = c("csv"))
),
actionButton("load", "Upload data"), # This is the button for uploading
# the data
conditionalPanel( # It appears only when the data are
condition = "input.load >= '1'", # loaded
uiOutput("var1"), # contains the name for variable 1
uiOutput("var2"), # contains the name for variable 2
actionButton("select", "Select & Display") # This is the button for
), # selecting the variables and actually see
# something
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
} else if (input$dataset == 4) {
data <- read.csv(input$example$datapath)
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
# check the characters
if (any(sapply(values$data, is.character)) == TRUE) {
values$data[, sapply(values$data, is.character) == T] = lapply(values$data[, sapply(values$data, is.character) == T], as.factor)
} else {
values$data = values$data
}
})
output$var1 <- renderUI({ # remember variable 1? here it is how we extract it
nam <- colnames(values$data) # from the data set
selectInput("var1", label = "Select x:", # create the input
choices = c(nam), multiple = FALSE,
selected = nam[1])
})
output$var2 <- renderUI({
nam2 <- colnames(values$data) # create the input for variable 2
selectInput("var2", label = "Select y:",
choices = c(nam2), multiple = FALSE,
selected = nam2[1])
})
newdata <- observeEvent(input$select, # use observe event so that the app will
{ # wait for you to decide before acting
# Besides, you're creating a new (smaller) object
values$df <- values$data[c(input$var1, input$var2)]
})
output$graph <- renderPlot({
validate(
need(input$select > 0, "Waiting for data") # I changed the validation from
) # load to select
df <- values$df # store the new object into an R object
plot(df[, c(1:2)]) # use it normally
})
output$summary <- renderPrint({
validate(
need(input$select > 0, "Waiting for data")
)
df <- values$df # same
summary(df[, c(1:2)])
})
},
options = list(height = 800)
)
```
## Code
```{r echo=TRUE, eval=FALSE}
shinyApp(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3,
"I want to use my data!!" =4)),
conditionalPanel(
condition = "input.dataset == '4'",
fileInput("example",
"", accept = c("csv"))
),
actionButton("load", "Upload data"), # This is the button for uploading
# the data
conditionalPanel( # It appears only when the data are
condition = "input.load >= '1'", # loaded
uiOutput("var1"), # contains the name for variable 1
uiOutput("var2"), # contains the name for variable 2
actionButton("select", "Select & Display") # This is the button for
), # selecting the variables and actually see
# something
),
mainPanel(
plotOutput(
"graph"
),
verbatimTextOutput(
"summary"
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
} else if (input$dataset == 4) {
data <- read.csv(input$example$datapath)
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
# check the characters
if (any(sapply(values$data, is.character)) == TRUE) {
values$data[, sapply(values$data, is.character) == T] = lapply(values$data[, sapply(values$data, is.character) == T], as.factor)
} else {
values$data = values$data
}
})
output$var1 <- renderUI({ # remember variable 1? here it is how we extract it
nam <- colnames(values$data) # from the data set
selectInput("var1", label = "Select x:", # create the input
choices = c(nam), multiple = FALSE,
selected = nam[1])
})
output$var2 <- renderUI({
nam2 <- colnames(values$data) # create the input for variable 2
selectInput("var2", label = "Select y:",
choices = c(nam2), multiple = FALSE,
selected = nam2[1])
})
newdata <- observeEvent(input$select, # use observe event so that the app will
{ # wait for you to decide before acting
# Besides, you're creating a new (smaller) object
values$df <- values$data[c(input$var1, input$var2)]
})
output$graph <- renderPlot({
validate(
need(input$select > 0, "Waiting for data") # I changed the validation from
) # load to select
df <- values$df # store the new object into an R object
plot(df[, c(1:2)]) # use it normally
})
output$summary <- renderPrint({
validate(
need(input$select > 0, "Waiting for data")
)
df <- values$df # same
summary(df[, c(1:2)])
})
},
options = list(height = 800)
)
```
## Interactive plots: Practice
```{r echo = FALSE, eval=TRUE}
library(shinyjs)
shinyApp(
ui = fluidPage(
useShinyjs(), # Set up shinyjs (this is just for nice visual effects)
sidebarLayout(
sidebarPanel(style = "background-color: #e1e9f9;",
a(id = "imp_det",
h3("Choose a dataset",
style = "font-style: normal; font-size: 14pt;"),
href = "#"),
shinyjs::hidden(div(
id = "details_import",
helpText(
h5("You can also upload your data!")
)
)),
selectInput(inputId = "dataset",
label = "",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3,
"I want to use my data!!" =4)),
conditionalPanel(
condition = "input.dataset == '4'",
fileInput("example",
"", accept = c("csv"))
),
actionButton("load", "Upload data"),
conditionalPanel(
condition = "input.load >= '1'",
uiOutput("var1"),
uiOutput("var2"),
actionButton("select", "Select & Display")
),
),
mainPanel(
plotOutput(
"graph",
click = clickOpts(id = "plot_click"), # when we click we select a point
brush = brushOpts(id = "plot_brush") # when we highlight an area we select
), # many rows
fluidRow( # it displays on the same row multiple arguments
column(4, # first column with the summary verbatim output
verbatimTextOutput(
"summary"
)),
column(4, # second column with another verbatim output for the points
verbatimTextOutput(
"points"
)
),
column(4,
verbatimTextOutput(
"brush"
))
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
} else if (input$dataset == 4) {
data <- read.csv(input$example$datapath)
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
# check the characters
if (any(sapply(values$data, is.character)) == TRUE) {
values$data[, sapply(values$data, is.character) == T] = lapply(values$data[, sapply(values$data, is.character) == T], as.factor)
} else {
values$data = values$data
}
})
shinyjs::onclick("imp_det", # here the nice visual effect
shinyjs::toggle(id = "details_import", anim = TRUE))
output$var1 <- renderUI({
nam <- colnames(values$data)
selectInput("var1", label = "Select x:",
choices = c(nam), multiple = F,
selected = nam[1])
})
output$var2 <- renderUI({
nam2 <- colnames(values$data)
selectInput("var2", label = "Select y:",
choices = c(nam2), multiple = F,
selected = nam2[1])
})
newdata <- observeEvent(input$select,
{ # wait for you to decide before acting
# Besides, you're creating a new (smaller) object
values$df <- values$data[c(input$var1, input$var2)]
})
output$graph <- renderPlot({
validate(
need(input$select > 0, "Waiting for data")
) # load to select
df = values$df
plot(df[, c(1:2)]) # use it normally
})
output$summary <- renderPrint({
validate(
need(input$select > 0, "Waiting for data")
)
df <- values$df # same
summary(df[, c(1:2)])
})
output$points <- renderPrint({
df <- values$df # store the data frame in an object
pointID <- nearPoints(df, # the data frame
input$plot_click, # the command for a reaction
xvar = names(df)[colnames(df) == input$var1], # xvar of the graph
yvar = names(df)[colnames(df) == input$var2], # yvar of the graph,
addDist = FALSE)
validate(
need(nrow(pointID) != 0, "Click on a point") # Waiting message
)
pointID
})
output$brush <- renderPrint({
df <- values$df # store the data frame in an object
brushID <- brushedPoints(df,# the data frame
input$plot_brush, # the command for a reaction
xvar = names(df)[colnames(df) == input$var1], # xvar of the graph
yvar = names(df)[colnames(df) == input$var2], # yvar of the graph
)
validate(
need(nrow(brushID) != 0, "Highlight Area") # Waiting message
)
brushID
})
},
options = list(height = 800)
)
```
## Interactive plots: Code
```{r echo = TRUE, eval=FALSE, message=FALSE, warning=FALSE}
library(shinyjs)
shinyApp(
ui = fluidPage(
useShinyjs(), # Set up shinyjs (this is just for nice visual effects)
sidebarLayout(
sidebarPanel(style = "background-color: #e1e9f9;",
a(id = "imp_det",
h3("Choose a dataset",
style = "font-style: normal; font-size: 14pt;"),
href = "#"),
shinyjs::hidden(div(
id = "details_import",
helpText(
h5("You can also upload your data!")
)
)),
selectInput(inputId = "dataset",
label = "",
choices = list("rock" = 1,
"pressure" = 2,
"cars" = 3,
"I want to use my data!!" =4)),
conditionalPanel(
condition = "input.dataset == '4'",
fileInput("example",
"", accept = c("csv"))
),
actionButton("load", "Upload data"),
conditionalPanel(
condition = "input.load >= '1'",
uiOutput("var1"),
uiOutput("var2"),
actionButton("select", "Select & Display")
),
),
mainPanel(
plotOutput(
"graph",
click = clickOpts(id = "plot_click"), # when we click we select a point
brush = brushOpts(id = "plot_brush") # when we highlight an area we select
), # many rows
fluidRow( # it displays on the same row multiple arguments
column(4, # first column with the summary verbatim output
verbatimTextOutput(
"summary"
)),
column(4, # second column with another verbatim output for the points
verbatimTextOutput(
"points"
)
),
column(4,
verbatimTextOutput(
"brush"
))
)
) # display output
)
),
server = function(input, output){
values <- reactiveValues()
dataInput <- reactive({
if(input$dataset == 1){
data <- rock
} else if (input$dataset == 2 ){
data <- pressure
} else if (input$dataset == 3) {
data <- cars
} else if (input$dataset == 4) {
data <- read.csv(input$example$datapath)
}
})
observeEvent(input$load, {
values$data <- data.frame(dataInput())
# check the characters
if (any(sapply(values$data, is.character)) == TRUE) {
values$data[, sapply(values$data, is.character) == T] = lapply(values$data[, sapply(values$data, is.character) == T], as.factor)
} else {
values$data = values$data
}
})
shinyjs::onclick("imp_det", # here the nice visual effect
shinyjs::toggle(id = "details_import", anim = TRUE))
output$var1 <- renderUI({
nam <- colnames(values$data)
selectInput("var1", label = "Select x:",
choices = c(nam), multiple = F,
selected = nam[1])
})
output$var2 <- renderUI({
nam2 <- colnames(values$data)
selectInput("var2", label = "Select y:",
choices = c(nam2), multiple = F,
selected = nam2[1])
})
newdata <- observeEvent(input$select,
{ # wait for you to decide before acting
# Besides, you're creating a new (smaller) object
values$df <- values$data[c(input$var1, input$var2)]
})
output$graph <- renderPlot({
validate(
need(input$select > 0, "Waiting for data")
) # load to select
df <- values$df # store the new object into an R object
plot(df[, c(1:2)]) # use it normally
})
output$summary <- renderPrint({
validate(
need(input$select > 0, "Waiting for data")
)
df <- values$df # same
summary(df[, c(1:2)])
})
output$points <- renderPrint({
df <- values$df # store the data frame in an object
pointID <- nearPoints(df, # the data frame
input$plot_click, # the command for a reaction
xvar = names(df)[colnames(df) == input$var1], # xvar of the graph
yvar = names(df)[colnames(df) == input$var2], # yvar of the graph,
addDist = FALSE)
validate(
need(nrow(pointID) != 0, "Click on a point") # Waiting message
)
pointID
})
output$brush <- renderPrint({
df <- values$df # store the data frame in an object
brushID <- brushedPoints(df,# the data frame
input$plot_brush, # the command for a reaction
xvar = names(df)[colnames(df) == input$var1], # xvar of the graph
yvar = names(df)[colnames(df) == input$var2], # yvar of the graph
)
validate(
need(nrow(brushID) != 0, "Highlight Area") # Waiting message
)
brushID
})
},
options = list(height = 800)
)
```
## Useful things
- [Shiny Gallery](https://shiny.rstudio.com/gallery/): You can find a gallery of different apps developed and deployed with `shiny`
- [Shiny widgets](https://shiny.rstudio.com/gallery/widget-gallery.html): All the possible inputs you can use in `shiny`
- [Shiny server](https://rstudio.com/products/shiny/shiny-server/): How to deploy your `shiny` app
- [Shiny server for dummies](https://deanattali.com/2015/05/09/setup-rstudio-shiny-server-digital-ocean/#shiny-git) How to deploy your `shiny` app **for free** on your own server (but not necessarily in an easy way, sorry)
- [shinjs](https://deanattali.com/shinyjs/example): Animate your `shiny` app with some Javascript without knowing **anything** about Java
- [CSS for dummies](https://www.w3schools.com/css/): Make your app looks better with css