I want to create a shiny app where the user can view data from two different datasets: 'new' and 'central'.
I use the below code:
# Define UI for application
fluidPage(
titlePanel("Public services"),
#tell shiny where to display the objects
#let the user choose the dataset they want to interact with
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose dataset:",
choices = c("Local government", "Central Government")),
uiOutput('name'),
uiOutput('type'),
uiOutput('service')),
#display an output object on the main manel
mainPanel(
# Output: Verbatim text for data summary ----
h4("Summary"),
verbatimTextOutput("summary"),
h4("Observations"),
DT::dataTableOutput("table")
))
)
# Define UI for application that
function(input, output) {
# A reactive expression to return the dataset corresponding to the
user choice
datasetInput <- reactive({
switch(input$dataset,
"Central Government" = central,
"Local Government" = local)
})
#Filter data based on selections
#name
output$name = renderUI({
selectInput('name', h5('Department or Local authority name'),
choices = names(datasetInput()))
})
output$type = renderUI({
selectInput('type', h5('Service type'), choices =
names(datasetInput()))
})
output$service = renderUI({
selectInput('service', h5('Service'), choices =
names(datasetInput()))
})
output$table <- DT::renderDataTable({
datasetInput()
})
}
Only the 'central' dataset is viewed in the dataframe, and the input options are only visible from the 'central' dataset.
The following code, which is just your code with some pieces left out and a different dataset, runs fine for me. Without a reproducible example it is
a bit difficult to help you, since I am unable to reproduce the erroneous behavior. It would be great if you could add a reproducible example, for tips on that see for example here or here.
# Define UI for application
ui<- fluidPage(
titlePanel("Public services"),
#tell shiny where to display the objects
#let the user choose the dataset they want to interact with
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose dataset:",
choices = c("mtcars2", "mtcars10"))),
mainPanel(
DT::dataTableOutput("table")
))
)
# Define UI for application that
server<-function(input, output) {
# A reactive expression to return the dataset corresponding to the
datasetInput <- reactive({
switch(input$dataset,
"mtcars2" = head(mtcars,2),
"mtcars10" = head(mtcars,10))
})
output$table <- DT::renderDataTable({
datasetInput()
})
}
shinyApp(ui,server)
Related
I am trying to create an app where you are able to select the columns that you want to see.
This post helped me a lot: Shiny How to dynamically select columns of imported dataset for further analysis
However, I want to be able to select the columns if the user doesn't click on the options and writes the columns who wants to see.
Right now, in order to be able to select columns you need to click or write ONE column.
However when you try to write more than 1 column (like this: "cyl mpg hp", in the same line) it doesn't appear anything.
This is the code:
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput("select", "Select columns to display", c('col1,col2'), multiple = TRUE),
actionButton("update", "Update Data set", class = "btn-primary",style='padding:4px; font-size:120%')
),
# Show a plot of the generated distribution
mainPanel(
h2('The Mydata'),
#tableOutput("mytable")
DT::dataTableOutput("mytable")
)
)
)
library(shiny)
library(DT)
server <- function(session, input, output) {
data <- reactive({
mtcars
})
filtereddata <- eventReactive({
input$update
data()
}, {
req(data())
if(is.null(input$select) || input$select == "")
data() else
data()[, colnames(data()) %in% input$select]
})
observeEvent(data(), {
updateSelectInput(session, "select", choices=colnames(data()))
})
output$mytable <- renderDataTable(filtereddata())
}
# Run the application
shinyApp(ui = ui, server = server)
I have tried doing in another way, like here: https://shiny.rstudio.com/reference/shiny/1.6.0/varSelectInput.html but I have the same problem.
Thanks in advance
Regards
I have a way to pick n number of columns with one string containing a space (or more if there's a typo) per column name, but it requires a textInput. SelectInput doesn't allow me to enter a string.
It will show an error if only one column is typed, but that can be modified with an if statement.
example code:
library(stringr)
library(shiny)
library(tidyverse)
library(rebus)
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
textInput('select_text', 'Type a column', placeholder = 'enter col names between spaces'),
actionButton("update", "Update Data set", class = "btn-primary",style='padding:4px; font-size:120%')
),
# Show a plot of the generated distribution
mainPanel(
h2('The Mydata'),
#tableOutput("mytable")
DT::dataTableOutput("mytable")
)
)
)
library(shiny)
library(DT)
server <- function(session, input, output) {
data <- reactive({
mtcars
})
filtereddata <- eventReactive(
input$update, {
cols_spaces <- str_split(input$select_text, rebus::one_or_more(rebus::SPACE),simplify = TRUE) #format the names to a vector
data()[, colnames(data()) %in% cols_spaces] #now they can be used to subset data()
}
)
observeEvent(data(), {
updateSelectInput(session, "select", choices=colnames(data()))
})
output$mytable <- renderDataTable(filtereddata())
}
# Run the application
shinyApp(ui = ui, server = server)
First of all, I am so sorry if the main question (the title) of the post is not clearly enough. I didn't how to write a question with my problem.
Well, the thing is that I have two select inputs. The main one: Dataset, which have 2 options: 1) Cars and 2) Iris.
The other select input, it has information from the Cars' dataset and information from the Iris one.
I need to show the information from Cars if I select Cars and the information from Iris if I select Iris.
Now, my code is not able to do that. Simply it shows you the options to choose the datasets but in the second select input only shows the information from Cars.
I don't know how to do it, I have been a lot of posts but I couldn't get what I want.
For example this post Filter one selectInput based on selection from another selectInput? was very similar and I thought that I could do something similar, but he doesn't use a dataset from R...
My code:
library(shiny)
ui <- fluidPage(
titlePanel("Select a dataset"),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Dataset",
choices = c("Cars" = "Cars", "Iris" = "Iris")),
uiOutput("select_cars"),
uiOutput("select_iris")
),
mainPanel(
verbatimTextOutput("text"),
verbatimTextOutput("text2")
)
)
)
server <- function(input, output) {
cars <- reactive({
data("mtcars")
cars <- rownames(mtcars)
return(cars)
})
iris <- reactive({
data("iris")
iris <- data.frame(unique(iris$Species))
colnames(iris) <- "iris"
return(iris)
})
output$select_cars <- renderUI({
selectInput(inputId = "options_cars", "Select one", choices = cars())
})
output$select_iris <- renderUI({
selectInput(inputId = "options_iris", "Select one iris", choices = iris())
})
output$text <- renderPrint(input$options_cars)
output$text2 <- renderPrint(input$options_iris)
}
#Run the app
shinyApp(ui = ui, server = server)
On the other hand I get an error: object of type ‘closure’ is not subsettable. But I don't know why.
Finally, I apologize if someone has already asked something similar before, I really have been looking all morning and I do not know how to solve it. (I am quite new at Shiny and I am trying to do my best).
Thanks very much in advance,
Regards
I have modified some of your code and added some JS functionality from shinyjs, which you may or may not find useful
You don't really need to create objects all the time if you only going to update the list, so we are going to use updateSelectInput to update the sliders
I used hidden functionality to hide the elements initially so they are invisible to begin with
I created dependency on input$dataset within observeEvent so we can update the sliders and hide and show both the sliders we dont want and the output we dont want
Also if your datasets are static, like mtcars and iris its best to take them outside the server.R so you dont do extra unnecessary work
Finally its always a good idea to add req so you're not creating any objects if they are NULL
Your original error was due to the fact that you were passing the dataframe and not the list or vector to the slider, try to print out the objects if you're unsure and see their types
library(shiny)
library(shinyjs)
ui <- fluidPage(
titlePanel("Select a dataset"),
useShinyjs(),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Dataset",
choices = c("Cars" = "Cars", "Iris" = "Iris")),
hidden(selectInput(inputId = "options_cars", "Select one", choices = NULL)),
hidden(selectInput(inputId = "options_iris", "Select one iris", choices = NULL))
),
mainPanel(
verbatimTextOutput("text_cars"),
verbatimTextOutput("text_iris")
)
)
)
cars_data <- unique(rownames(mtcars))
iris_data <- as.character(unique(iris$Species))
server <- function(input, output, session) {
observeEvent(input$dataset,{
if(input$dataset == "Cars"){
show('options_cars')
hide('options_iris')
show('text_cars')
hide('text_iris')
updateSelectInput(session,"options_cars", "Select one", choices = cars_data)
}else{
show('options_iris')
hide('options_cars')
show('text_iris')
hide('text_cars')
updateSelectInput(session,"options_iris", "Select one iris", choices = iris_data)
}
})
output$text_cars <- renderPrint({
req(input$options_cars)
input$options_cars
})
output$text_iris <- renderPrint({
req(input$options_iris)
input$options_iris
})
}
#Run the app
shinyApp(ui = ui, server = server)
Here is a code that allows the switch by selectInput
library(shiny)
library(datasets)
ui <- fluidPage(
titlePanel("Select a dataset"),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Dataset",
choices = c("Cars" = "Cars", "Iris" = "Iris")),
##------removed this---------------
# uiOutput("select_cars"),
#uiOutput("select_iris")
##------------------------------
uiOutput("select_by_input")
),
mainPanel(
verbatimTextOutput("text")
# verbatimTextOutput("text2")
)
)
)
server <- function(input, output) {
cars <- reactive({
data("mtcars")
cars <- rownames(mtcars)
return(cars)
})
iris <- reactive({
# data("iris")
# iris <- data.frame(unique(iris$Species))
data('iris')
#colnames(iris) <- "iris"
# iris_names <- as.character(unique(iris$Species) )
iris_names <- c('a','b','c')
return(iris_names)
})
##------removed this---------------
# output$select_cars <- renderUI({
# selectInput(inputId = "options_cars", "Select one", choices = cars())
# })
#
# output$select_iris <- renderUI({
# selectInput(inputId = "options_iris", "Select one iris", choices = iris())
# })
#-----------------------------
output$select_by_input <- renderUI({
if (input$dataset=='Cars'){
selectInput(inputId = "options_x", "Select one", choices = cars())
}else if (input$dataset=='Iris'){
selectInput(inputId = "options_x", "Select one iris", choices = iris())
}
})
output$text <- renderPrint(input$options_x)
}
#Run the app
shinyApp(ui = ui, server = server)
the object of type ‘closure’ is not subsettable. error is caused by the iris data not being loaded after running the app. I used iris_names <- c('a','b','c') to demonstrate the dynamic change by selectInput
I'm trying to build a application for myself to get every dataset in a folder, display those in a selectInput(), and then the column names from the data set in another selectInput(), so that when both values have been selected, it performs feature selection (with caret) and displays the output.
I've attached what I have done so far below, however I cannot test the selectInput() as the program closes itself as soon as its run with an error:
Warning: Error in dataset: could not find function "dataset"
[No stack trace available]
Here is the code:
#datasets <- list('Maccas' = read.csv("menu.csv"))
#selectInput("dataset", "Please pick a data set", choices = names(datasets))
#####################
library(shiny)
library(datasets)
ui <- fluidPage(sidebarLayout(
sidebarPanel(
selectInput("dataset", "choose a dataset", c("Maccas")),
selectInput("column", "select column", "placeholder1"),
selectInput("level", "select level", "placeholder2")
),
mainPanel(tableOutput("table"))
))
server <- function(input, output, session){
dataset <- list(read.csv("menu.csv"))
observe({
updateSelectInput(session, "column", choices = names(dataset()))
})
observeEvent(input$column, {
column_levels <- as.character(sort(unique(
dataset()[[input$column]]
)))
updateSelectInput(session, "level", choices = column_levels)
})
output$table <- renderTable({
subset(dataset(), dataset()[[input$column]] == input$level)
})
}
shinyApp(ui, server)
I am trying to build a shiny app where I can upload a csv file and based on the column names, from selectInput - app shows basic statistic (graphs, descriptive statistic-average, sd, var .... and some statistical tests).
There is no problem with datasets, which are already in the app. Also no problem with statistics.
Problem is how to make working selectInput with the names of columns from new upload csv file.
Here is my light version of code:
UI:
library(shiny)
shinyUI(fluidPage(
titlePanel("xxx"),
sidebarLayout(
sidebarPanel(
fileInput("csvFile", "Drag cars.csv over here!"),
selectInput("var", "choose variable:", choices= names(data()))
),
mainPanel(
textOutput("average"),
plotOutput("plot")
)
)
))
SERVER:
shinyServer(function(input, output, session) {
data <- reactive({
file1 <- input$csvFile
if (is.null(file1)) {
return()
}
data = read.csv(file=file1$datapath)
data
})
output$average <- renderText({
paste("average is: ", mean(data()[,input$var]))
})
output$plot <- renderPlot({
boxplot(data()[,input$var])
})
})
You will need to use uiOutput() and renderUI() functions.
library(shiny)
ui <- fluidPage(
titlePanel("xxx"),
sidebarLayout(
sidebarPanel(
fileInput("csvFile", "Drag cars.csv over here!"),
uiOutput("var_ui")
),
mainPanel(
textOutput("average"),
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
data <- reactive({
file1 <- input$csvFile
if (is.null(file1)) {
return()
}
data = read.csv(file=file1$datapath)
data
})
output$average <- renderText({
paste("average is: ", mean(data()[,input$var]))
})
output$plot <- renderPlot({
boxplot(data()[,input$var])
})
output$var_ui <- renderUI({
selectInput("var", "choose variable:", choices= names(data()))
})
}
shinyApp(ui, server)
You can also use observe in server. observe does not return anything. Unlike reactive, it responds immediately (and not lazily). It's best used for ip/op operations.
observe({
updateSelectInput(
session,
"var",
choices = names(data())
)
)}
I am trying to gather user input given a data set. I want to insert a column where the user can determine whether they would want to own one of the cars in the mtdata set. This is completely subjective as opinions differ from person to person so I am not able to program this in. Is there a way to append an extra column that can be a checkbox or dropdown menu to identify cars that a user would "Want to own?
library(shiny)
shinyApp(ui = shinyUI(fluidPage(
titlePanel("Interesting Cars"),
sidebarLayout(
sidebarPanel(
helpText("This is a side bar")),
mainPanel(
tableOutput("view")
)
)
)),
server = function(input, output) {
output$view <- renderTable({
head(mtcars[, 1:4], n = 6)
})
})
How about this, you can use the DT library. By adding the filter option the user can define the different components one wants and see what cars come up.
library(shiny)
library(DT)
shinyApp(ui = shinyUI(fluidPage(
titlePanel("Interesting Cars"),
sidebarLayout(
sidebarPanel(
helpText("This is a side bar")),
mainPanel(
DT::dataTableOutput("view")
)
)
)),
server = function(input, output) {
output$view <- DT::renderDataTable({
datatable(mtcars,
filter = "top"
)
})
})
Edit
If it truly is so important to add another column indicating if it is 'interesting' there will be significantly more code to written if you intend to have users assign it on different conditions. Here is an example with just the mpg. The fundamental idea here is that you assign your data to the reactiveValues function. It can then be modified as you like. This can obviously be improved upon more (as it will continue to add columns) but it demonstrates the concept.
shinyApp(ui = shinyUI(fluidPage(
titlePanel("Interesting Cars"),
sidebarLayout(
sidebarPanel(
helpText("This is a side bar"),
uiOutput("mpg"),
actionButton("add_label", "Mark Interesting")
),
mainPanel(
DT::dataTableOutput("view")
)
)
)),
server = function(input, output) {
values <- reactiveValues(
mydata = mtcars
)
output$mpg <- renderUI({
numericInput("mpg_input", "MPG Cutoff?",
value = 15
)
})
output$view <- DT::renderDataTable({
datatable(values$mydata
)
})
observeEvent(input$add_label, {
validate(
need(!is.null(input$mpg_input), "need mpg value")
)
values$mydata <- data.frame(values$mydata,
Interesting_Flag =
ifelse(values$mydata$mpg > input$mpg_input,
"Interesting",
"Not Interesting"))
})
})