Why does my plot disappear in shiny when I add a table? - r

I have created a shiny app should take input from three sliders and:
Plots a distribution in ggplot
Show a summary table of values underneath the plot in #1 above
If I just want to plot the histogram (and I comment out the table data), I can get the code to work correctly. However, when I add the table, the plot disappears even though the plot header is still there. I have tried moving the commas a braces around to see if it's a simple syntax error but haven't had any luck.
library(shiny)
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("Test Shiny Layout"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
h4("Input Data"),
sliderInput("bins", "Bin Width", min = 4,max = 12, value = 8),
),
# Show a plot of the generated distribution
mainPanel(
h4("Histogram"),
plotOutput("distPlot", width = "600", height = "600"),
h4("Table of Values"),
tableOutput("table")
)
)
))
Server
library(shiny)
library(ggplot2)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
bins <- input$bins
df1 <- (iris$Sepal.Length)
x <- mean(df1)
y <- sd(df1)
ggplot(data = iris) +
geom_histogram(mapping = aes(x = Sepal.Length), color = "blue", binwidth = "bins")
# Create an empty dataframe and then plug in the mean and standard deviation
results <- data.frame("0", "0")
results[1,1] = x
results[1,2] = y
colnames(results) <- c("Mean", "SD")
rownames(results) <- c("Sepal Length")
output$table <- renderTable(results)
})
})

Your renderTable() is inside your renderPlot() call. So renderPlot isn't returning anything.
You were right: it was a simple syntax error. But you also had several other issues in your code. At least a dozen. Three in binwidth = "bins" alone.
Here's a working version. I suspect you will still want to make tweaks, but at least you have both a histogram and a summary table that both look reasonably sensible.
library(shiny)
library(ggplot2)
data(iris)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
ggplot(data = iris) +
geom_histogram(aes(x = Sepal.Length), color = "blue", bins = input$bins)
})
output$table <- renderTable({
iris %>%
summarise(Mean=mean(Sepal.Length),
SD=sd(Sepal.Length))
})
}
ui <- fluidPage(
titlePanel("Test Shiny Layout"),
sidebarLayout(
sidebarPanel(
h4("Input Data"),
sliderInput("bins", "Bin Width", min = 4,max = 12, value = 8),
),
mainPanel(
h4("Histogram"),
plotOutput("distPlot", width = "600", height = "600"),
h4("Table of Values"),
tableOutput("table")
)
)
)
shinyApp(ui = ui, server = server)

Related

R Shiny how to refer to inputs that are part of dynamic number of inputs

So, I need to make a shiny app that takes a dynamic number of inputs to eventually do dimension reduction, but I'm stuck trying to figure out how to refer to what's in my inputs when I have a dynamic number of them. I'm using the iris dataset and the inputs are the variables. Part of what I need to do is plot 2 of them with a k means, but I'm just trying to 1st make a basic plot. What I have so far is
library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
titlePanel("Old Faithful Geyser Data"),
fluidRow(
column(2,
textInput(inputId = "number", label = "number of selectInput",value = 2)
),
column(8,
plotOutput("distPlot")),
column(2,
uiOutput(outputId = "putselect"))
)
))
server <- shinyServer(function(input, output) {
output$putselect = renderUI(
if(input$number != 0 ){
lapply(1:(input$number), function(i){
selectInput(inputId = paste0("var",i), label = paste0("input ",i), choices = names(iris))
})
}
)
output$distPlot <- renderPlot({
ggplot(iris, aes(x = input$var1, y = input$var2, color = Species)) +
geom_point()
})
})
shinyApp(ui = ui, server = server)
In my output$distplot what goes in the ggplot x and y? The way I have it now it shows up and the labels on the graph change, but there are no points on the graph. I'm new to using Shiny so any help would be appreciated.
instead of aes use aes_string like:
ggplot(iris, aes_string(x = input$var1,
y = input$var2,
color = "Species"
)
)
note to quote the variables supplied as a string (Species in this case)
see: Shiny: passing input$var to aes() in ggplot2

Define column values as input for reactive shiny plot

I want to start a shiny app for practice where a use can choose from a dropdown the values in the "cut" column from the diamonds dataset (from ggplot2).
My ui looks as following:
library(shiny)
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("Reactive Boxplot"),
# Show a boxplot of the selected cut
mainPanel(
selectInput("column", label = h3("Column to plot"),
choices = c("", diamonds$cut),
selected = 1,
width='55%',
multiple = FALSE),
plotOutput("diamondshist")
)
)
)
I don't know how to define the input variables as the five distinct values in the "cut" column of diamonds dataset. Any input on this?
My server file looks like shared below. I assume I would also need to adapt the input data for the plot.
library(shiny)
library(ggplot2)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
compute_plot <- reactive({
if (input$column != ""){
ggplot(diamonds[, input$column])+
labs(title = "From diamonds dataset")+
geom_boxplot(aes(x = cut, y = price))+
scale_y_reverse()
}
})
output$diamondshist <- renderPlot({
compute_plot();
})
})
I assume this is what you are after:
pass the levels of diamonds$cut as input selection
subset the diamonds dataset to the selected cut
library(shiny)
library(ggplot2)
# Define UI for application that draws a histogram
ui=shinyUI(fluidPage(
# Application title
titlePanel("Reactive Boxplot"),
# Show a boxplot of the selected cut
mainPanel(
selectInput("column", label = h3("Column to plot"),
choices = c("", levels(diamonds$cut)),
selected = NULL,
width='55%',
multiple = FALSE),
plotOutput("diamondshist")
)
)
)
# Define server logic required to draw a histogram
server=shinyServer(function(input, output) {
compute_plot <- reactive({
if (input$column != ""){
ggplot(subset(diamonds, cut==input$column))+
labs(title = "From diamonds dataset")+
geom_boxplot(aes(x = cut, y = price))+
scale_y_reverse()
}
})
output$diamondshist <- renderPlot({
compute_plot();
})
})
shinyApp(ui = ui, server = server)

Get unique values of a dataframe for select input choices but only when the dataframe was defined in server.ui not globally

Example shiny app:
library(tidyverse)
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("example"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
selectInput(inputId = "cut",
label = "cut",
# choices = unique(diamonds$cut), # works
choices = unique(my_diamonds$cut), # does not work
selected = "Ideal")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
my_diamonds <- diamonds
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- my_diamonds$carat
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
In this case I am using a faux data frame 'my_diamonds'. In my real code I am connecting to a database using dbplyr and then making some transformations to it, so duplicating that in ui section seems wasteful.
What is the 'right' way to use a dataframe defined in server section to get the unique values, in this case my_diamonds$cut to use as a select input's drop down choices?
Instead of using selectInput in the UI, you can instead use UIoutput in the UI and then define the UI element within the server function using renderUI.
So given that you have defined a UIOutput element called otn_race_selection_op, then we can define that as a selectInput object using the below code. Here getData is a reactive element that updates itself to the latest data. So based on that, you can modify the input choices for your selectInput object
output$otn_race_selection_op <- renderUI({
df <- getData()
options <- sort(unique(df$Race))
selectInput(
inputId = "otn_race_selection",
label = "Race",
choices = c("All", options)
,
selected = "All"
)
})

R shiny brushed points table blank NA rows

I am working on a shiny app where I allow a user to select the plotting criteria and then also allow them to brush the plot and see their selection in a table below. I have some NA values in my data. I have noticed that these NAs end up in my brushed point table as full rows of NA. I can remove these manually with something like this. However, I was wondering if I perhaps was doing something wrong on my brush that was causing this.
Code with a working example is below. I have also included an image of a brush selection demonstrating what I mean.
library(shiny)
library(tidyverse)
# replace some random values in mtcars with NA
set.seed(1)
mtnew <-
as.data.frame(lapply(mtcars, function(m)
m[sample(
c(TRUE, NA),
prob = c(0.8, 0.2),
size = length(m),
replace = TRUE
)]))
# set up UI that allows user to pick x and y variables, see a plot,
# brush the plot, and see a table based on the brush
ui <- fluidPage(
titlePanel("Shiny Test"),
sidebarLayout(
sidebarPanel(
selectInput("xvar",
"pick x",
choices = names(mtnew)),
selectInput("yvar",
"pick y",
choices = names(mtnew))),
mainPanel(
plotOutput("myplot",
brush = brushOpts(id = "plot_brush")),
tableOutput("mytable")
)
)
)
server <- function(input, output) {
output$myplot <- renderPlot({
ggplot(data = mtnew) +
geom_point(aes(x = !!rlang::sym(input$xvar),
y = !!rlang::sym(input$yvar)))
})
output$mytable <- renderTable({
brush_out <- brushedPoints(mtnew, input$plot_brush)
})
}
# Complete app with UI and server components
shinyApp(ui, server)
I guess that you'll have to establish which data you want to represent.
You may want to have only defined record without NAs, in that case I would suggest to use the complete.cases function. Yet this solution will highly reduce your data set (below I've applied to your code).
Another option is to preserve all your records but without the NAs. In that case you should consider using imputation methods to set proper values in replacement. Take a look at this post which provides an example.
library(shiny)
library(tidyverse)
# replace some random values in mtcars with NA
set.seed(1)
mtnew <-
as.data.frame(lapply(mtcars, function(m)
m[sample(
c(TRUE, NA),
prob = c(0.8, 0.2),
size = length(m),
replace = TRUE
)]))
mtnew_complete <- mtnew[complete.cases(mtnew),]
# set up UI that allows user to pick x and y variables, see a plot,
# brush the plot, and see a table based on the brush
ui <- fluidPage(
titlePanel("Shiny Test"),
sidebarLayout(
sidebarPanel(
selectInput("xvar",
"pick x",
choices = names(mtnew)),
selectInput("yvar",
"pick y",
choices = names(mtnew))),
mainPanel(
plotOutput("myplot",
brush = brushOpts(id = "plot_brush")),
tableOutput("mytable")
)
)
)
server <- function(input, output) {
output$myplot <- renderPlot({
#ggplot(data = mtnew) +
ggplot(data = mtnew_complete) +
geom_point(aes(x = !!rlang::sym(input$xvar),
y = !!rlang::sym(input$yvar)))
})
output$mytable <- renderTable({
#brush_out <- brushedPoints(mtnew, input$plot_brush)
brush_out <- brushedPoints(mtnew_complete, input$plot_brush)
})
}
# Complete app with UI and server components
shinyApp(ui, server)

Shiny only uses the first item of selectInput when multiple = TRUE

I'm trying to use the value(s) of input$levels in the plot as the title but selectInput is only displaying the first value when multiple are selected. The plot itself changes in the correct way, which means shiny knows that multiple levels are selected.
library(tidyverse)
library(shiny)
test_data <- data.frame(x = seq(1, 100, 10),
y = seq(1, 100, 10),
level = rep(c(1, 2), 5))
ui <- fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
selectInput("levels",
"Include level(s):",
selected=1,
choices=c(1, 2),
multiple=TRUE)
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
ggplot(test_data %>%
filter(level %in% input$levels), aes(x, y)) +
geom_point() +
ggtitle(paste("Including level(s):", input$levels))
})
}
shinyApp(ui, server)
How does one access all values of selectInput when multiple are selected?
input$levels contains a vector of your selected items. To make them appear in the title of your graph, you can do:
ggtitle(paste("Including level(s):", paste(input$levels,collapse=', ')))
Hope this helps!

Resources