Shiny if else statement - r

I am having problems using conditional statements in Shiny. I want the user select number of variable. If choose 1 variable then plot chart of 1 variable (ex density plot), if choose 2 variable then plot chart of 2 variables (ex scatter plot). I have tried a few ways, but the output is not as my expected. How can i use if else statement in Shiny server? Tks
UI
df <- mtcars
ui <- fluidPage(
h1("My first app",
style = 'color: green;
font-style: italic'),
hr(),
fluidRow(
sidebarPanel(
radioButtons(inputId = "number",
label = "Select number of variable",
choices = c("1 variable" = 1,
"2 variable" = 2)),
selectInput(inputId = "x",
label = "Variable 1",
choices = names(df)),
conditionalPanel(
condition = "input.number == 2",
selectInput(inputId = "y",
label = "Variable 2",
choices = names(df))
)
),
column(8, plotOutput("plot"))
),
hr(),
plotOutput("plot") )
Server
server <- function(input, output, session){
observeEvent(input$x,
{updateSelectInput(session,
inputId = "y",
label = "Variable 2",
choices = names(df)[names(df) != input$x])
})
data <- reactive({
if(input$number == 1){
data <- df %>%
select(input$x)
} else {
data <- df %>%
select(input$x, input$y)
}
})
output$plot <- renderPlot({
if(input$number == 1){
ggplot(data = data(),
x = get(input$x))+
geom_density()
} else {
ggplot(data = data,
x = get(input$x),
y = get(input$y)) +
geom_point()
}
})
}
shinyApp(ui = ui, server = server)

You can try the following code -
plotOutput("plot") was mentioned twice, removed it to include it only once.
We don't need to check for conditions while creating the dataset in reactive, handle it in the plot code itself.
Use .data to refer column names in ggplot code.
library(shiny)
library(ggplot2)
df <- mtcars
ui <- fluidPage(
h1("My first app",
style = 'color: green;
font-style: italic'),
hr(),
fluidRow(
sidebarPanel(
radioButtons(inputId = "number",
label = "Select number of variable",
choices = c("1 variable" = 1,
"2 variable" = 2)),
selectInput(inputId = "x",
label = "Variable 1",
choices = names(df)),
conditionalPanel(
condition = "input.number == 2",
selectInput(inputId = "y",
label = "Variable 2",
choices = names(df))
)
),
column(8, plotOutput("plot"))
)
)
server <- function(input, output, session){
data <- reactive({
df
})
observeEvent(input$x,
{updateSelectInput(session,
inputId = "y",
label = "Variable 2",
choices = names(df)[names(df) != input$x])
})
output$plot <- renderPlot({
if(input$number == 1){
plot <- ggplot(data = data(), aes(x = .data[[input$x]])) + geom_density()
} else {
plot <- ggplot(data = data(),
aes(x = .data[[input$x]], y = .data[[input$y]])) +
geom_point()
}
plot
})
}
shinyApp(ui = ui, server = server)

You could use aes_string.
Another very important point is never to use the same output twice in UI:
df <- mtcars
library(ggplot2)
library(dplyr)
ui <- fluidPage(
h1("My first app",
style = 'color: green;
font-style: italic'),
hr(),
fluidRow(
sidebarPanel(
radioButtons(inputId = "number",
label = "Select number of variable",
choices = c("1 variable" = 1,
"2 variable" = 2)),
selectInput(inputId = "x",
label = "Variable 1",
choices = names(df)),
conditionalPanel(
condition = "input.number == 2",
selectInput(inputId = "y",
label = "Variable 2",
choices = names(df))
)
),
column(8, plotOutput("plot"))
),
hr()
# Never use output twice : the UI won't work!
#plotOutput("plot")
)
server <- function(input, output, session){
observeEvent(input$x,
{updateSelectInput(session,
inputId = "y",
label = "Variable 2",
choices = names(df)[names(df) != input$x])
})
data <- reactive({
if(input$number == 1){
data <- df %>%
select(input$x)
} else {
data <- df %>%
select(input$x, input$y)
}
})
output$plot <- renderPlot({
cat(input$x)
if(input$number == 1){
ggplot(data = data())+
geom_density(aes_string(x=input$x))
} else {
ggplot(data = data()) +
geom_point(aes_string(x=input$x,y=input$y))
}
})
}
shinyApp(ui = ui, server = server)

Related

dynamic plot layout in shiny

I want the plots (generated by plotly) to be laid out in two columns and n rows. The number of rows depends on the number of plots. For instance, the layout should be 3(row) x 2(col) if there are 5 or 6 plots. However, there are two problems with the following code. First, only one of them is repeated when we have multiple plots. Second, they are stacked on top of each other, although the column width is 6.
Here is the code:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(selectInput(inputId = "y", label = "Y", choices = names(mtcars), selected = names(mtcars)[1], multiple = F),
selectizeInput(inputId = "xvars", label = "X", choices = names(mtcars), selected = names(mtcars)[1],
multiple = T)),
mainPanel(uiOutput("allplots"))
)
)
server <- function(input, output, session) {
output$allplots <- renderUI({
plt_list <- list()
for (x in input$xvars){
plt_list[[x]] <- renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
}
if (length(input$xvars) == 1) {
plottoUI <- fluidRow(column(12, plt_list[1]))
} else {
plottoUI <- fluidRow(column(6, plt_list[1:length(input$xvars)]))
}
return(plottoUI)
})
}
shinyApp(ui, server)
UPDATTE:
#lz100 seems to have resolved the main issue with the layout. Here is a further update on how to prevent one plot being repeated. I replaced the for loop (I don't know the reason why it didn't work) with lapply.
plt_list <- lapply(input$xvars, function(x){
renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
})
So, considering the #lz100 suggestion the final solution will be:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(selectInput(inputId = "y", label = "Y", choices = names(mtcars), selected = names(mtcars)[1], multiple = F),
selectizeInput(inputId = "xvars", label = "X", choices = names(mtcars), selected = names(mtcars)[1],
multiple = T)),
mainPanel(uiOutput("allplots"))
)
)
server <- function(input, output, session) {
output$allplots <- renderUI({
plt_list <- list()
plt_list <- lapply(input$xvars, function(x){
renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
})
if (length(input$xvars) == 1) {
plottoUI <- fluidRow(column(12, plt_list[1]))
} else {
plottoUI <- fluidRow(
lapply(1:length(input$xvars), function(x) column(6, plt_list[x]))
)
}
return(plottoUI)
})
}
shinyApp(ui, server)
You need to wrap each plot with a column, not a column for all plots, see below:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(selectInput(inputId = "y", label = "Y", choices = names(mtcars), selected = names(mtcars)[1], multiple = F),
selectizeInput(inputId = "xvars", label = "X", choices = names(mtcars), selected = names(mtcars)[1],
multiple = T)),
mainPanel(uiOutput("allplots"))
)
)
server <- function(input, output, session) {
output$allplots <- renderUI({
plt_list <- list()
for (x in input$xvars){
plt_list[[x]] <- renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
}
if (length(input$xvars) == 1) {
plottoUI <- fluidRow(column(12, plt_list[1]))
} else {
plottoUI <- fluidRow(
lapply(1:length(input$xvars), function(x) column(6, plt_list[x]))
)
}
return(plottoUI)
})
}
shinyApp(ui, server)

Loading bar from Waiter package doesn't disappear after its use [SHINY]

I am creating a Shiny app and I have started using the Waiter package.
When I load the app, before doing anything, we cannot see anything (at it is expected). When I generate the plot, the loading bar appears but when it finishes, it doesn't disappear. It stays a white box that it still can be seen.
Loading....
It has finished.
Does anyone know how to remove it?
Thanks in advance!
Code:
library(shiny)
library(magrittr)
library(DT)
library(ggplot2)
library(waiter)
new_choices <- setNames(names(mtcars), names(mtcars))
ui <- fluidPage(
# Application title
titlePanel("My shiny app"),
sidebarLayout(
sidebarPanel(
tabsetPanel(
tabPanel("Selection",
selectInput("x_axis", "Choose x axis",
choices = new_choices),
selectInput("y_axis", "Choose y axis",
choices = new_choices),
hr(),
),
tabPanel("Titles",
hr(),
textInput(inputId = "title", "You can write the title:", value = "This is the title"),
textInput(inputId = "xlab", "You can re-name the x-axis:", value = "x-axis...."),
textInput(inputId = "ylab", "You can re-name the y-axis:", value = "y-axis ...."),
),
tabPanel("Calculations",
hr(),
checkboxInput("log2", "Do the log2 transformation", value = F),
checkboxInput("sqrt", "Calculate the square root", value = F),
)
),
useWaitress(),
actionButton(inputId = "drawplot", label = "Show the plot")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("plot"),
)
)
)
server <- function(input, output, session) {
waitress <- Waitress$new(theme = "overlay-percent", min = 0, max = 10)
data <- reactive({
mtcars
})
filtered_data <- reactive({
data <- data()
if(input$log2 == TRUE){
data <- log2(data+1)
}
if(input$sqrt == TRUE){
data <- sqrt(data)
}
return(data)
})
v <- reactiveValues()
observeEvent(input$drawplot, {
# use notification
waitress$notify()
for(i in 1:10){
waitress$inc(1) # increase by 10%
Sys.sleep(.3)
}
v$plot <- ggplot() +
geom_point(data = filtered_data(),
aes_string(x = input$x_axis, y = input$y_axis)) +
xlab(input$xlab) +
ylab(input$ylab) +
ggtitle(input$title)
waitress$close() # hide when done
})
output$plot <- renderPlot({
if (is.null(v$plot)) return()
v$plot
})
}
shinyApp(ui, server)
Feels like a bug to me. You may file an issue to the waiter github repository and ask them to fix it. Meanwhile, a workaround we can do is to manually show and hide the bar by ourselves.
library(shiny)
library(magrittr)
library(DT)
library(ggplot2)
library(waiter)
library(shinyjs)
new_choices <- setNames(names(mtcars), names(mtcars))
ui <- fluidPage(
# Application title
titlePanel("My shiny app"),
sidebarLayout(
sidebarPanel(
tabsetPanel(
tabPanel("Selection",
selectInput("x_axis", "Choose x axis",
choices = new_choices),
selectInput("y_axis", "Choose y axis",
choices = new_choices),
hr(),
),
tabPanel("Titles",
hr(),
textInput(inputId = "title", "You can write the title:", value = "This is the title"),
textInput(inputId = "xlab", "You can re-name the x-axis:", value = "x-axis...."),
textInput(inputId = "ylab", "You can re-name the y-axis:", value = "y-axis ...."),
),
tabPanel("Calculations",
hr(),
checkboxInput("log2", "Do the log2 transformation", value = F),
checkboxInput("sqrt", "Calculate the square root", value = F),
)
),
useWaitress(),
useShinyjs(),
actionButton(inputId = "drawplot", label = "Show the plot")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
waitress <- Waitress$new(theme = "overlay-percent", min = 0, max = 10)
data <- reactive({
mtcars
})
filtered_data <- reactive({
data <- data()
if(input$log2 == TRUE){
data <- log2(data+1)
}
if(input$sqrt == TRUE){
data <- sqrt(data)
}
return(data)
})
v <- reactiveValues()
observeEvent(input$drawplot, {
# use notification
show(selector = '.waitress-notification.notifications')
waitress$notify()
for(i in 1:10){
waitress$inc(1) # increase by 10%
Sys.sleep(.3)
}
v$plot <- ggplot() +
geom_point(data = filtered_data(),
aes_string(x = input$x_axis, y = input$y_axis)) +
xlab(input$xlab) +
ylab(input$ylab) +
ggtitle(input$title)
waitress$close()
hide(selector = '.waitress-notification.notifications')
})
output$plot <- renderPlot({
if (is.null(v$plot)) return()
v$plot
})
}
shinyApp(ui, server)

Spinner from shinycssloaders package loads before pressing the action button

I am creating a shiny app with some tabs and I am using the shinycssloaders package in order to show a spinner AFTER pressing the actionButton. I saw this post because I was having the same problem... I followed the solution that it was given to the post, but as I my app is different (it has tabPanels, it doesn't work properly, the spinner still apears).
For example, if you click on "Show the plot" in the first tab (selection) and then you want to want to do the log2 transformation o calculate the square root (3rd tab, calculations), before clicking the actionButton the spinner appears and the plot updates. It happens the same when you want to change the titles (2nd tab).
Does anyone know how to fix it?
Thanks very much in advance
The code:
library(shiny)
library(magrittr)
library(DT)
library(ggplot2)
library(shinycssloaders)
new_choices <- setNames(names(mtcars), names(mtcars))
ui <- fluidPage(
# Application title
titlePanel("My shiny app"),
sidebarLayout(
sidebarPanel(
tabsetPanel(
tabPanel("Selection",
selectInput("x_axis", "Choose x axis",
choices = new_choices),
selectInput("y_axis", "Choose y axis",
choices = new_choices),
hr(),
),
tabPanel("Titles",
hr(),
textInput(inputId = "title", "You can write the title:", value = "This is the title"),
textInput(inputId = "xlab", "You can re-name the x-axis:", value = "x-axis...."),
textInput(inputId = "ylab", "You can re-name the y-axis:", value = "y-axis ...."),
),
tabPanel("Calculations",
hr(),
checkboxInput("log2", "Do the log2 transformation", value = F),
checkboxInput("sqrt", "Calculate the square root", value = F),
)
),
actionButton(inputId = "drawplot", label = "Show the plot")
),
# Show a plot of the generated distribution
mainPanel(
# plotOutput("plot")
uiOutput("spinner"),
)
)
)
server <- function(input, output, session) {
data <- reactive({
mtcars
})
filtered_data <- reactive({
data <- data()
if(input$log2 == TRUE){
data <- log2(data+1)
}
if(input$sqrt == TRUE){
data <- sqrt(data)
}
return(data)
})
observeEvent(input$drawplot, {
output$spinner <- renderUI({
withSpinner(plotOutput("plot"), color="black")
})
output$plot <- renderPlot({
Sys.sleep(3)
ggplot() +
geom_point(data = filtered_data(),
aes_string(x = input$x_axis, y = input$y_axis)) +
xlab(input$xlab) +
ylab(input$ylab) +
ggtitle(input$title)
})
})
}
shinyApp(ui, server)
Is it OK like this? I'm not sure to understand all your requirements. To avoid the spinner at the start-up, I use a conditionalPanel. In the server code, I did some changes. It is not recommended to define some output inside an observer.
library(shiny)
library(magrittr)
library(ggplot2)
library(shinycssloaders)
new_choices <- setNames(names(mtcars), names(mtcars))
ui <- fluidPage(
# Application title
titlePanel("My shiny app"),
sidebarLayout(
sidebarPanel(
tabsetPanel(
tabPanel(
"Selection",
selectInput("x_axis", "Choose x axis",
choices = new_choices),
selectInput("y_axis", "Choose y axis",
choices = new_choices),
hr(),
),
tabPanel(
"Titles",
hr(),
textInput(inputId = "title", "You can write the title:", value = "This is the title"),
textInput(inputId = "xlab", "You can re-name the x-axis:", value = "x-axis...."),
textInput(inputId = "ylab", "You can re-name the y-axis:", value = "y-axis ...."),
),
tabPanel(
"Calculations",
hr(),
checkboxInput("log2", "Do the log2 transformation", value = F),
checkboxInput("sqrt", "Calculate the square root", value = F),
)
),
actionButton(inputId = "drawplot", label = "Show the plot")
),
# Show a plot of the generated distribution
mainPanel(
conditionalPanel(
condition = "input.drawplot > 0",
style = "display: none;",
withSpinner(plotOutput("plot"))
)
)
)
)
server <- function(input, output, session) {
data <- reactive({
mtcars
})
filtered_data <- reactive({
data <- data()
if(input$log2 == TRUE){
data <- log2(data+1)
}
if(input$sqrt == TRUE){
data <- sqrt(data)
}
return(data)
})
gg <- reactive({
ggplot() +
geom_point(data = filtered_data(),
aes_string(x = input$x_axis, y = input$y_axis)) +
xlab(input$xlab) +
ylab(input$ylab) +
ggtitle(input$title)
}) %>%
bindEvent(input$drawplot)
output$plot <- renderPlot({
Sys.sleep(3)
gg()
})
}
shinyApp(ui, server)
You need to isolate the expressions that you don't want to trigger the rendering event inside renderPlot
library(shiny)
library(magrittr)
library(DT)
library(ggplot2)
library(shinycssloaders)
new_choices <- setNames(names(mtcars), names(mtcars))
ui <- fluidPage(
# Application title
titlePanel("My shiny app"),
sidebarLayout(
sidebarPanel(
tabsetPanel(
tabPanel("Selection",
selectInput("x_axis", "Choose x axis",
choices = new_choices),
selectInput("y_axis", "Choose y axis",
choices = new_choices),
hr(),
),
tabPanel("Titles",
hr(),
textInput(inputId = "title", "You can write the title:", value = "This is the title"),
textInput(inputId = "xlab", "You can re-name the x-axis:", value = "x-axis...."),
textInput(inputId = "ylab", "You can re-name the y-axis:", value = "y-axis ...."),
),
tabPanel("Calculations",
hr(),
checkboxInput("log2", "Do the log2 transformation", value = F),
checkboxInput("sqrt", "Calculate the square root", value = F),
)
),
actionButton(inputId = "drawplot", label = "Show the plot")
),
# Show a plot of the generated distribution
mainPanel(
# plotOutput("plot")
uiOutput("spinner"),
)
)
)
server <- function(input, output, session) {
data <- reactive({
mtcars
})
filtered_data <- reactive({
data <- data()
if(input$log2 == TRUE){
data <- log2(data+1)
}
if(input$sqrt == TRUE){
data <- sqrt(data)
}
return(data)
})
observeEvent(input$drawplot, {
output$spinner <- renderUI({
withSpinner(plotOutput("plot"), color="black")
})
output$plot <- renderPlot({
Sys.sleep(3)
ggplot() +
geom_point(data = isolate(filtered_data()),
aes_string(x = isolate(input$x_axis), y = isolate(input$y_axis))) +
xlab(isolate(input$xlab)) +
ylab(isolate(input$ylab)) +
ggtitle(isolate(input$title))
})
})
}
shinyApp(ui, server)
Read more about shiny reactivity and isolation: https://shiny.rstudio.com/articles/isolation.html

Multilines graph with uploaded CSV

I would like to be able to display a multi-line graph with an imported csv. CSV files contain time series. On import, I would like to be able to choose, knowing that the name of the fields can change according to the CSV, the field representing the X and the one of Y, and define the field containing the ID which will create the various lines. Something like this :
For now, I have this but it's completly wrong
# ui.R
library(shiny)
library(shinydashboard)
library(ggplot2)
shinyUI(
dashboardPage(
dashboardHeader(title ="Sen2extract"),
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Chart", tabName = "chart")
)
),
dashboardBody(
tabItem(tabName = "chart",
box(
width = 12, collapsible=FALSE,
fileInput(inputId = "csv_chart", label = "Upload your CSV", multiple = FALSE,
accept = c(".csv", "text/csv", "text/comma-separated-values,text/plan"), width = "300px"),
selectInput("X", label = "Field X :", choices = list("Choice 1" = "")),
selectInput("Y", label = "Field Y :", choices = list("Choice 1" = "")),
selectInput("group", label = "Group by :", choices = list("Choice 1" = ""))
),
box(plotOutput("plot"), width = 12)
)
)
)
)
# server.R
library(shiny)
library(shinydashboard)
library(ggplot2)
shinyServer(function(input, output, session){
output$plot = renderPlot({
data <- read.csv(file = input$csv_chart)
ggplot(data) +
geom_line(mapping = aes(x = input$X, y = input$Y)) +
labs (x = "Years", y = "", title = "Index Values")
})
})
there were several issues with your code and I have a working version below.
The main issue was that you have to read your data within reactive() and then update the selection. Also, to have multiple lines in your graph, you have to add what to group on in ggplot when you define the mapping in aes or in this case aes_string. I chose color as this gives multiple lines colored according to different groups in the chosen column.
library(shiny)
library(shinydashboard)
library(tidyverse)
ui <- dashboardPage(
dashboardHeader(title ="Sen2extract"),
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Chart", tabName = "chart")
)
),
dashboardBody(
tabItem(tabName = "chart",
box(
width = 12, collapsible=FALSE,
fileInput(inputId = "csv_chart", label = "Upload your CSV",
multiple = FALSE,
accept = c(".csv",
"text/csv",
"text/comma-separated-values,text/plan"),
width = "300px"),
selectInput("X", label = "Field X:", choices = "Pending Upload"),
selectInput("Y", label = "Field Y:", choices = "Pending Upload"),
selectInput("group", label = "Group by:", choices = "Pending Upload")
),
box(plotOutput("plot"), width = 12)
)
)
)
server <- function(input, output, session){
data <- reactive({
req(input$csv_chart)
infile <- input$csv_chart
if (is.null(infile))
return(NULL)
df <- read_csv(infile$datapath)
updateSelectInput(session, inputId = 'X', label = 'Field X:',
choices = names(df), selected = names(df)[1])
updateSelectInput(session, inputId = 'Y', label = 'Field Y:',
choices = names(df), selected = names(df)[2])
updateSelectInput(session, inputId = 'group', label = 'Group by:',
choices = names(df), selected = names(df)[3])
return(df)
})
output$plot <- renderPlot({
ggplot(data()) +
geom_line(mapping = aes_string(x = input$X, y = input$Y, color=input$group)) +
labs(x = "Years", y = "", title = "Index Values")
})
}
shinyApp(ui = ui, server = server)

How do I connect fileInput to ggplot in Shiny?

I have been working on this for more than 6 hours today, and I know it's a simple issue, but I can't figure it out. What I want is to input a file, and then be able to use multiple selectInput dropdown menus to change the output on the ggplot. Here is what I have so far:
UI:
ui = dashboardPage(
dashboardHeader(title = "Apple Financials"),
dashboardSidebar(
fileInput("file1", label = "Upload SAS Data:", accept = ".sas7bdat"),
selectInput("x", label = "X-Axis Variable", choices = c("Sales", "Cash", "Assets", "Profits", "R&D", "SG&A")),
selectInput("y", label = "Y-Axis Variable", choices = c("Sales", "Cash", "Assets", "Profits", "R&D", "SG&A"), selected = "R&D"),
selectInput("scale", label = "Choose the Scale:", choices = c("Levels", "Log 10")),
radioButtons("model", label = "Choose the Model:", choices = c("Linear Model", "LOESS", "Robust Linear", "None"), selected = "LOESS"),
checkboxInput("ribbon", label = "Standard Error Ribbon", value = TRUE),
conditionalPanel(
condition = "input.model == 'LOESS'",
sliderInput("span", label = "Span for LOESS", min = 0, max = 1, value = .75)
)
),
dashboardBody(
box(width = NULL, height = 415, plotOutput("plots"))
)
)
Server:
server = function(input, output) {
observe({
data = input$file1
if(is.null(data))
return(NULL)
df = read_sas(data$datapath)
output$plots = renderPlot({
ggplot(df, aes(x = input$x, y = input$y)) +
geom_line()
})
})
}
As the input is a string, we need aes_string in ggplot
server = function(input, output) {
observe({
data = input$file1
if(is.null(data))
return(NULL)
df = read_sas(data$datapath)
output$plots = renderPlot({
ggplot(df, aes_string(x = input$x, y = input$y)) +
geom_line()
})
})
}
shinyApp(ui, server)
NOTE: For demonstration, we are uploading a csv file instead of SAS file

Resources