Multiple conditional selection criteria in shiny - r

Probably a simple one:
I have a data.frame such as this:
set.seed(1)
df <- data.frame(name=c("A","A","B","C","B","A"),id=1:6,rep1=rnorm(6),rep2=rnorm(6),rep3=rnorm(6))
In the UI part of the R shiny server I'd like to have a drop-down menu that lists unique(df$name), and then given that selection, in a second drop-down menu I'd like to list all df$id that correspond to that df$name selection (i.e., if the selected name is selected.name, this will be: dplyr::filter(df,name == selected.name)$id). Then given these two selections (which are a unique row in df) I'd like to execute server, which executes this function to plot the given selection:
plotData <- function(selected.df)
{
plot.df <- reshape2::melt(dplyr::select(selected.df,-name,-id))
ggplot2::ggplot(plot.df,ggplot2::aes(x=variable,y=value))+ggplot2::geom_point()+ggplot2::theme_minimal()
}
Here's the shiny code I'm trying:
server <- function(input, output)
{
output$id <- renderUI({
selectInput("id", "ID", choices = unique(dplyr::filter(df,name == input$name)$id))
})
output$plot <- renderPlot({
plotData(selected.df=dplyr::filter(df,name == input$name,id == output$id))
})
}
ui <- fluidPage(
# App title ----
titlePanel("Results Explorer"),
# Sidebar layout with a input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# select name
selectInput("name", "Name", choices = unique(df$name)),
uiOutput("id")
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)
When I run: shinyApp(ui = ui, server = server), I get the error:
Evaluation error: Reading objects from shinyoutput object not allowed..
What's missing?

Here the option would be have renderUI in the 'server' and uiOuput in 'ui'
-ui
library(shiny)
library(dplyr)
library(ggplot2)
ui <- fluidPage(
# App title ----
titlePanel("Results Explorer"),
# Sidebar layout with a input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# select name
selectInput("name", "Name", choices = unique(df$name)),
uiOutput("idselection")
# select id - this is where I need help
),
# Main panel for displaying outputs ----
mainPanel(
# ShinyServer part
plotOutput("plot")
)
)
)
-server
server = function(input, output) {
output$idselection <- renderUI({
selectInput("id", "ID", choices = unique(df$id[df$name ==input$name]))
})
output$plot <- renderPlot({
df %>%
count(name) %>%
ggplot(., aes(x = name, y = n, fill = name)) +
geom_bar(stat = 'identity') +
theme_bw()
})
}
shinyApp(ui = ui, server = server)
-output

Ok, tiny fix:
Create data:
set.seed(1)
df <- data.frame(name=c("A","A","B","C","B","A"),id=1:6,rep1=rnorm(6),rep2=rnorm(6),rep3=rnorm(6))
Function that server will execute:
plotData <- function(selected.df)
{
plot.df <- reshape2::melt(dplyr::select(selected.df,-name,-id))
ggplot2::ggplot(plot.df,ggplot2::aes(x=variable,y=value))+ggplot2::geom_point()+ggplot2::theme_minimal()
}
shiny code:
server <- function(input, output)
{
output$id <- renderUI({
selectInput("id", "ID", choices = unique(dplyr::filter(df,name == input$name)$id))
})
output$plot <- renderPlot({
plotData(selected.df=dplyr::filter(df,name == input$name,id == input$id))
})
}
ui <- fluidPage(
# App title ----
titlePanel("Results Explorer"),
# Sidebar layout with a input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# select name
selectInput("name", "Name", choices = unique(df$name)),
uiOutput("id")
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)

Related

Shiny: How can I loop thru variable names in the ui selectInput choices in the server datasetInput switch?

in Shiny I simply want to select which variable of a dataframe shall be plotted and I do not want to have to type all the variable names in the server switch part. Here is what I do:
ui <- fluidPage(
titlePanel("Hello World!"),
sidebarLayout(
sidebarPanel(
selectInput("variable", "Choose a variable:",
# choices = c("cyl", "mpg")),
choices = names(mtcars)),
),
mainPanel(
plotOutput(outputId = "BarPlot"),
)
)
)
server <- function(input, output) {
datasetInput <- reactive({
switch(input$variable,
"cyl" = mtcars[,"cyl"],
"mpg" = mtcars[,"mpg"])
})
output$BarPlot <- renderPlot({
x <- datasetInput()
barplot(table(x))
})
}
Instead of
switch(input$variable,
"cyl" = mtcars[,"cyl"],
"mpg" = mtcars[,"mpg"])
can I do something like
choices = mtcars[,get(choices)]
to cover all choices without having to type them one by one?
One approach is to use varSelectInput and pass the data frame as data (it will include all column names as the choices). Then you can extract the selected column from mtcars through mtcars[[input$variable]] in your example:
library(shiny)
ui <- fluidPage(
titlePanel("Hello World!"),
sidebarLayout(
sidebarPanel(
varSelectInput("variable",
"Choose a variable:",
data = mtcars),
),
mainPanel(
plotOutput(outputId = "BarPlot"),
)
)
)
server <- function(input, output) {
datasetInput <- reactive({
mtcars[[input$variable]]
})
output$BarPlot <- renderPlot({
x <- datasetInput()
barplot(table(x))
})
}
shinyApp(ui, server)

using drop down bottom in shiny to loaed files from a folder

I am using shiny to upload different data files from a certain folder and plot a histogram based on a certain column. The name of each file looks like "30092017ARB.csv" (date + ARB.csv).
The code loops over all file names in the data-folder and print the name of files in a drop-down bottom. After selecting the name of file it should be uploaded and plot a histogram of the mw-column (the name of column is "mw). My GUI looks as follows:
library("shiny")
dataset <- list.files("C:/R_myfirstT/data", pattern=".*.csv$")
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("Data plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Selector for choosing dataset ----
selectInput(inputId = "date",
label = "Choose a date:",
choices = dataset)
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)
and the server
# Define server ----
dataset <- list.files("C:/R_myfirstT/data", pattern=".*.csv$")
dat.name<-paste("C:/R_myfirstT/data/",dataset,sep = "")
server <- function(input, output) {
datasetInput <- reactive({
switch(input$dataset,
for (i in 1:length(dataset)){
toString(dataset[i])=read.csv(file=dat.name[i], header=TRUE, sep=";")
}
)
output$plot <- renderPlot({
hist(dataset.mw, breaks = 40)
})
})
}
My problem is: I do not get any histogram! I get just the which is nice however, not entirely my goal!
Any idea what could be the reason?
Something like this works:
ui.R
library("shiny")
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("Data plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Selector for choosing dataset ----
selectInput(inputId = 'date',
label = 'Choose a date:',
choices = list.files(path = "./data",
full.names = FALSE,
recursive = FALSE))
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)
server.R
# Define server ----
server <- function(input, output) {
dataset <- reactive({
infile <- input$date
if (is.null(infile)){
return(NULL)
}
read.csv(paste0('./data/',infile))
})
output$plot <- renderPlot({
x <- dataset()[,1]
hist(x, breaks = 40)
})
}

Shiny reactive subset

I am trying to subset data frame of three column (StockCode,Price,label)
but I had to used reactive and my ask is how to render label
I need somethink like renderText(dataset()$label)
ui.R
library(shiny)
# Define UI for app that draws a histogram ----
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
uiOutput("codePanel")
),
# Main panel for displaying outputs ----
mainPanel(
textOutput("text")
)
)
)
server.R
server <- function(input, output) {
output$codePanel<-renderUI({
selectInput("codeInput",label ="choose code",choices =data$StockCode)
})
dataset<-reactive({
subset(data,data$StockCode==input$codeInput)
})
output$text<-renderText(dataset())
}
If we are looking to show the data.frame output use the renderDataTable from DT. For reproducibility, used the inbuilt dataset iris
library(shiny)
library(DT)
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
uiOutput("codePanel")
),
mainPanel(
DT::dataTableOutput("text")
)
)
)
server <- function(input, output) {
filt <- selectInput("codeInput",label ="choose code",
choices = as.list(unique(iris$Species)))
output$codePanel <- renderUI({ filt
})
dataset<-reactive({
subset(iris, Species == input$codeInput)
})
output$text<-renderDataTable(dataset())
}
shinyApp(ui = ui, server = server)
-output
The dataset rows can be pasted together to a string to be used in the renderText
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
uiOutput("codePanel")
),
mainPanel(
verbatimTextOutput("text")
)
)
)
server <- function(input, output) {
filt <- selectInput("codeInput",label ="choose code",
choices = as.list(unique(iris$Species)))
output$codePanel <- renderUI({ filt
})
iris$Species <- as.character(iris$Species)
dataset<-reactive({
do.call(paste, c(collapse = "\n", rbind(colnames(iris), subset(iris, Species == input$codeInput))))
})
output$text<-renderText(dataset())
}
shinyApp(ui = ui, server = server)
-output
Or use htmlOutput with renderUI
ui <- fluidPage(
# App title ----
titlePanel("Hello Shiny!"),
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
uiOutput("codePanel")
),
mainPanel(
htmlOutput("text")
)
)
)
server <- function(input, output) {
filt <- selectInput("codeInput",label ="choose code",
choices = as.list(unique(iris$Species)))
output$codePanel <- renderUI({ filt
})
dataset<-reactive({
do.call(paste, c(collapse = "<br/>", rbind(colnames(iris), subset(iris, Species == input$codeInput))))
})
output$text<-renderUI(HTML(dataset()))
}
shinyApp(ui = ui, server = server)
I could not get renderDataTable from DT to work. A message said some functions were masked. So, I removed DT and added in some code from the R Studio tutorial on tables and data.frames. This is what I came up with:
library(shiny)
ui <- fluidPage(
# App title ----
titlePanel("Subsetting Iris Dataset"),
sidebarLayout(
# Sidebar panel for inputs
sidebarPanel(
uiOutput("codePanel"),
# Input: Numeric entry for number of obs to view
numericInput(inputId = "obs",
label = "Number of observations to view:",
value = 10)
),
mainPanel(
tableOutput("view")
)
)
)
server <- function(input, output) {
filt <- selectInput("codeInput", label = "choose code",
choices = unique(iris$Species))
output$codePanel <- renderUI({ filt
})
dataset <- reactive({
subset(iris, Species == input$codeInput)
})
output$view <- renderTable(head(dataset(), n = input$obs))
}
shinyApp(ui = ui, server = server)

Shiny R: how to evaluate data set name to print the dataset

I want to print data set values in R shiny web app. But below code is printing the name of dataset in UI output. How can I print values of dataset?
library(MASS)
library(shinythemes)
library(shiny)
library(ggplot2)
mass.tmp <- data(package = "MASS")[3]
mass.datasets <- as.vector(mass.tmp$results[,3])
ui <- fluidPage(
theme = shinytheme("superhero"),
titlePanel("Linear Regression Modelling"),
sidebarLayout(
sidebarPanel(
selectInput("dsname", "Dataset:",choices = c(mass.datasets))
,
uiOutput("x_axis")
,
tableOutput("tab")
),
mainPanel(
tags$br(),
tags$br()
)
)
)
server <- function(input, output) {
num_ds <- function(ds)
{
nums <- sapply(ds,is.numeric)
num_ds <- ds[,nums]
return(num_ds)
}
ds_ext <- reactive({ num_ds(input$dsname) })
output$tab <- renderTable({ eval(input$dsname) })
# output$x_axis <- renderUI({
# col_opts <- get(ds_ext())
# selectInput("x_axis2", "Independent Variable:", choices = names(col_opts))
# })
}
shinyApp(ui = ui, server = server)
This is full code. I am trying to display data set from MASS package as you see in the code above.

R Shiny: Nested tabPanels disable each other

In the attached MWE Shiny example, I have a nested tabsetPanel within a tabPanel for a navbar. If you run the MWE with only one tabPanel within the tabSet you will see that Shiny behaves exactly as it is expected. However, if you run the MWE with two tabPanels, the result is not printed to the main panel of each tab.
Why does this behaviour occur? And how do I resolve this conundrum?
library(shiny)
ui <- shinyUI(navbarPage("tabalicious",
tabPanel("Nav1", value = "nav1",
mainPanel(h2("Hello"),
br(),
p("This is my app.")
)
)
,
tabPanel("Nav2", value = "nav2",
tabsetPanel(
tabPanel("tabsettab1",
sidebarLayout(
sidebarPanel(
helpText("Choose your settings"),
selectInput("zone_type",
label = "Choose a zone type to display",
choices = list("Industrial", "Residential"),
selected = "Industrial")
),
mainPanel(h2("A tab for a tabSet"),
textOutput('zone_type')
)
)
)
# Uncomment this to see the issue
# ,
# tabPanel("tabsettab2",
# sidebarLayout(
# sidebarPanel(
# helpText("Choose your settings"),
# selectInput("zone_type",
# label = "Choose a zone type to display",
# choices = list("Industrial", "Residential"),
# selected = "Industrial")
# ),
# mainPanel(h2("A tab for a tabSet"),
# textOutput('zone_type')
# )
# )
# )
)
)
)
)
server <- shinyServer(function(input, output) {
output$zone_type <- renderText({
paste("You have selected", input$zone_type)
})
})
# Run the application
shinyApp(ui = ui, server = server)
It doesn't have to do with tabs, but multiple calls to output the results of the same render* function. For example, a simplified page (with no tabs) will work fine, but if you uncomment the duplicated call, will fail to display zone_type:
library(shiny)
server <- shinyServer(function(input, output) {
output$zone_type <- renderText({paste("You have selected", input$zone_type)})
})
ui <- shinyUI(fluidPage(
selectInput("zone_type",
label = "Choose a zone type to display",
choices = list("Industrial", "Residential")),
# textOutput('zone_type'),
textOutput('zone_type')
))
runApp(shinyApp(server = server, ui = ui))
While your shinyUI function can only call each output of shinyServer once, within shinyServer you can call the inputs as many times as you like, so it's easy to duplicate outputs:
library(shiny)
server <- shinyServer(function(input, output) {
output$zone_type <- renderText({paste("You have selected", input$zone_type)})
output$zone_type2 <- renderText({paste("You have selected", input$zone_type)})
})
ui <- shinyUI(fluidPage(
selectInput("zone_type",
label = "Choose a zone type to display",
choices = list("Industrial", "Residential")),
textOutput('zone_type'),
textOutput('zone_type2')
))
runApp(shinyApp(server = server, ui = ui))
If you don't want to duplicate work for the server, you can't pass one output to another, but you can just save the render* results to a local variable which you can pass to both outputs:
server <- shinyServer(function(input, output) {
zone <- renderText({paste("You have selected", input$zone_type)})
output$zone_type <- zone
output$zone_type2 <- zone
})

Resources