I have one question to open the topic already. Well, I'm trying to do a similar app to this one Shiny: dynamic dataframe construction; renderUI, observe, reactiveValues. And I would like to add a new category at the beginning which will select the variables from the table. I can not combine variables with other elements in an application. Could someone explain to me what I'm doing wrong?
As you can see on the graphics program does not work well.
Below is a script
#rm(list = ls())
library(shiny)
data <- data.frame(Category1 = rep(letters[1:3],each=15),
Info = paste("Text info",1:45),
Category2 = sample(letters[15:20],45,replace=T),
Size = sample(1:100, 45),
MoreStuff = paste("More Stuff",1:45))
ui <- fluidPage(
titlePanel("Test Explorer"),
sidebarLayout(
sidebarPanel(
selectizeInput("show_vars", "Columns to show:",
choices = colnames(data), multiple = TRUE,
selected = c("Category1","Info","Category2")),
uiOutput("category1"),
uiOutput("category2"),
uiOutput("sizeslider")
),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output,session) {
data2 <- reactive({
req(input$table)
if(input$table == "All"){
return(data)
}
data[,names(data) %in% input$show_vars]
})
output$category1 <- renderUI({
selectizeInput('cat1', 'Choose Cat 1', choices = c("All",sort(as.character(unique(data$Category1)))),selected = "All")
})
df_subset <- eventReactive(input$cat1,{
if(input$cat1=="All") {df_subset <- data}
else{df_subset <- data[data$Category1 == input$cat1,]}
})
df_subset1 <- reactive({
if(is.null(input$cat2)){df_subset()} else {df_subset()[df_subset()$Category2 %in% input$cat2,]}
})
output$category2 <- renderUI({
selectizeInput('cat2', 'Choose Cat 2 (optional):', choices = sort(as.character(unique(df_subset()$Category2))), multiple = TRUE,options=NULL)
})
output$sizeslider <- renderUI({
sliderInput("size", label = "Size Range", min=min(df_subset1()$Size), max=max(df_subset1()$Size), value = c(min(df_subset1()$Size),max(df_subset1()$Size)))
})
df_subset2 <- reactive({
if(is.null(input$size)){df_subset1()} else {df_subset1()[df_subset1()$Size >= input$size[1] & df_subset1()$Size <= input$size[2],]}
})
output$table <- renderTable({
df_subset2()
})
}
shinyApp(ui, server)
You don't need data2 since you are not using it and instead you can just use the same condition to filter columns with %in% everywhere you are displaying the dataframe.
#rm(list = ls())
library(shiny)
data <- data.frame(Category1 = rep(letters[1:3],each=15),
Info = paste("Text info",1:45),
Category2 = sample(letters[15:20],45,replace=T),
Size = sample(1:100, 45),
MoreStuff = paste("More Stuff",1:45))
ui <- fluidPage(
titlePanel("Test Explorer"),
sidebarLayout(
sidebarPanel(
selectizeInput("show_vars", "Columns to show:",
choices = colnames(data), multiple = TRUE,
selected = c("Category1","Info","Category2")),
uiOutput("category1"),
uiOutput("category2"),
uiOutput("sizeslider")
),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output,session) {
output$category1 <- renderUI({
selectizeInput('cat1', 'Choose Cat 1', choices = c("All",sort(as.character(unique(data$Category1)))),selected = "All")
})
df_subset <- eventReactive(input$cat1,{
if(input$cat1=="All") {df_subset <- data}
else{df_subset <- data[data$Category1 == input$cat1,names(data) %in% input$show_vars]}
})
df_subset1 <- reactive({
if(is.null(input$cat2)){df_subset()} else {df_subset()[df_subset()$Category2 %in% input$cat2,names(data) %in% input$show_vars]}
})
output$category2 <- renderUI({
selectizeInput('cat2', 'Choose Cat 2 (optional):', choices = sort(as.character(unique(df_subset()$Category2))), multiple = TRUE,options=NULL)
})
output$sizeslider <- renderUI({
sliderInput("size", label = "Size Range", min=min(df_subset1()$Size), max=max(df_subset1()$Size), value = c(min(df_subset1()$Size),max(df_subset1()$Size)))
})
df_subset2 <- reactive({
if(is.null(input$size)){df_subset1()} else {df_subset1()[df_subset1()$Size >= input$size[1] & df_subset1()$Size <= input$size[2],names(data) %in% input$show_vars]}
})
output$table <- renderTable({
df_subset2()
})
}
shinyApp(ui, server)
Related
When I click on the Action Button, I would like to clear everything: both the output and the selections in the picketInput() (input$engine and input$cylinder in the code below). For consistency if I can do it with shinyWidget's actionBttn, that will be great as well.
library(shiny)
library(shinyWidgets)
df <- mtcars
ui <- fluidPage(
sidebarPanel(
pickerInput("engine", "Select engine:", choices = unique(df$vs),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
pickerInput("cylinder", "Select cylinder:", choices = unique(df$cyl),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
actionButton("reset", "Clear Selection"),
),
mainPanel(
textOutput("results")
)
)
server <- function(input, output, session) {
data <- reactiveValues()
observeEvent(input$cylinder, {
tmp <- df
tmp1 <- tmp[tmp$vs %in% input$engine, ]
tmp2 <- tmp1[tmp1$cyl %in% input$cylinder, ]
data$tmp2 <- tmp2
})
output$results <- renderText({
if(is.null(data$tmp2)) return()
print(row.names(data$tmp2))
})
observeEvent(input$reset, {
updatePickerInput(session, "engine", NULL)
updatePickerInput(session, "cylinder", NULL)
data$tmp2 <- NULL
})
}
shinyApp(ui = ui, server = server)
You'll have to respect the order of updatePickerInput's parameters or name them. Your above approach would have updated the label.
Please see ?updatePickerInput and check the following:
library(shiny)
library(shinyWidgets)
library(datasets)
DF <- mtcars
ui <- fluidPage(
sidebarPanel(
pickerInput("engine", "Select engine:", choices = unique(DF$vs),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
pickerInput("cylinder", "Select cylinder:", choices = unique(DF$cyl),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
actionBttn("reset", "Clear Selection"),
),
mainPanel(
textOutput("results")
)
)
server <- function(input, output, session) {
data <- reactiveValues()
observeEvent(input$cylinder, {
tmp <- DF
tmp1 <- tmp[tmp$vs %in% input$engine, ]
tmp2 <- tmp1[tmp1$cyl %in% input$cylinder, ]
data$tmp2 <- tmp2
})
output$results <- renderText({
req(data$tmp2)
row.names(data$tmp2)
})
observeEvent(input$reset, {
updatePickerInput(session, inputId = "engine", selected = "")
updatePickerInput(session, inputId = "cylinder", selected = "")
data$tmp2 <- NULL
})
}
shinyApp(ui = ui, server = server)
I would like to add a new category at the beginning which will select the columns for the table. I can not combine variables with other elements in an application. Could someone explain to me what I'm doing wrong? As you can see on the graphics program does not work well.
My code:
library(shiny)
data <- data.frame(
Category1 = rep(letters[1:3], each = 15),
Info = paste("Text info", 1:45),
Category2 = sample(letters[15:20], 45, replace = T),
Size = sample(1:100, 45),
MoreStuff = paste("More Stuff", 1:45)
)
ui <- fluidPage(titlePanel("Test Explorer"),
sidebarLayout(
sidebarPanel(
selectizeInput(
"show_vars",
"Columns to show:",
choices = colnames(data),
multiple = TRUE,
selected = c("Category1", "Info", "Category2")
),
uiOutput("category1"),
uiOutput("category2"),
uiOutput("sizeslider")
),
mainPanel(tableOutput("table"))
))
server <- function(input, output, session) {
data2 <- reactive({
req(input$table)
if (input$table == "All") {
return(data)
}
data[, names(data) %in% input$show_vars]
})
output$category1 <- renderUI({
selectizeInput('cat1',
'Choose Cat 1',
choices = c("All", sort(as.character(
unique(data$Category1)
))),
selected = "All")
})
df_subset <- eventReactive(input$cat1, {
if (input$cat1 == "All") {
df_subset <- data
}
else{
df_subset <- data[data$Category1 == input$cat1, ]
}
})
df_subset1 <- reactive({
if (is.null(input$cat2)) {
df_subset()
} else {
df_subset()[df_subset()$Category2 %in% input$cat2, ]
}
})
output$category2 <- renderUI({
selectizeInput(
'cat2',
'Choose Cat 2 (optional):',
choices = sort(as.character(unique(
df_subset()$Category2
))),
multiple = TRUE,
options = NULL
)
})
output$sizeslider <- renderUI({
sliderInput(
"size",
label = "Size Range",
min = min(df_subset1()$Size),
max = max(df_subset1()$Size),
value = c(min(df_subset1()$Size), max(df_subset1()$Size))
)
})
df_subset2 <- reactive({
if (is.null(input$size)) {
df_subset1()
} else {
df_subset1()[df_subset1()$Size >= input$size[1] &
df_subset1()$Size <= input$size[2], ]
}
})
output$table <- renderTable({
df_subset2()
})
}
shinyApp(ui, server)
You have few problems with your code
You stored that reactive value of the columns selection in data2(), and displaying table df_subset2(). As with your code, the columns change when you add columns and select Cat1 dropdown, since its values are dependent on the data.react.
Avoid using generic names like data to store data. Sometimes it interfere with R base names
You need to use ObserveEvent and eventReactive, when you expect the change on UI to reflect
Below is what I fixed, you can change accordingly.
Added a submit button
Wrapped the input selections code into an ObserveEvent
By this, your data is displayed only when you click the submit button.
Here is the code.
library(shiny)
data.input <- data.frame(
Category1 = rep(letters[1:3], each = 15),
Info = paste("Text info", 1:45),
Category2 = sample(letters[15:20], 45, replace = T),
Size = sample(1:100, 45),
MoreStuff = paste("More Stuff", 1:45)
)
ui.r
ui <- fluidPage(titlePanel("Test Explorer"),
sidebarLayout(
sidebarPanel(
selectizeInput(
"show_vars",
"Columns to show:",
choices = colnames(data.input),
multiple = TRUE,
selected = c("Category1", "Info", "Category2")
),
actionButton("button", "An action button"),
uiOutput("category1"),
uiOutput("category2"),
uiOutput("sizeslider")
),
mainPanel(tableOutput("table"))
))
server.r
server <- function(input, output, session) {
data.react <- eventReactive(input$button, {
data.input[, input$show_vars]
})
observeEvent(input$button, {
output$category1 <- renderUI({
data.sel <- data.react()
selectizeInput('cat1',
'Choose Cat 1',
choices = c("All", sort(as.character(
unique(data.sel$Category1)
))),
selected = "All")
})
df_subset <- eventReactive(input$cat1, {
data.sel <- data.react()
if (input$cat1 == "All") {
data.sel
}
else{
data.sel[data.sel$Category1 == input$cat1,]
}
})
output$category2 <- renderUI({
selectizeInput(
'cat2',
'Choose Cat 2 (optional):',
choices = sort(as.character(unique(
df_subset()$Category2
))),
multiple = TRUE,
options = NULL
)
})
df_subset1 <- reactive({
if (is.null(input$cat2)) {
df_subset()
} else {
df_subset()[df_subset()$Category2 %in% input$cat2,]
}
})
output$sizeslider <- renderUI({
sliderInput(
"size",
label = "Size Range",
min = min(data.input$Size),
max = max(data.input$Size),
value = c(min(data.input$Size), max(data.input$Size))
)
})
df_subset2 <- reactive({
if (is.null(input$size)) {
df_subset1()
} else {
df_subset1()[data.input$Size >= input$size[1] &
data.input$Size <= input$size[2],]
}
})
output$table <- renderTable({
df_subset2()
})
})
}
shinyApp(ui, server)
I would like to prepare a Shiny App in which the user can fill one column (e.g. Col1) with numbers and then press a button to generate entries for Col2 (a transformation of values introduced to Col1, e.g. multiply each row of Col1 by a random number).
How should I add the button to the following sample code:
library(rhandsontable)
library(shiny)
# add a sparkline chart
DF$chart = sapply(1:10, function(x) jsonlite::toJSON(list(values=rnorm(10))))
rhandsontable(DF, rowHeaders = NULL) %>%
hot_col("chart", renderer = htmlwidgets::JS("renderSparkline"))
editTable <- function(DF, outdir=getwd(), outfilename="table"){
ui <- shinyUI(fluidPage(
titlePanel("Edit and save a table"),
sidebarLayout(
sidebarPanel(
helpText("Shiny app based on an example given in the rhandsontable package.",
"Right-click on the table to delete/insert rows.",
"Double-click on a cell to edit"),
wellPanel(
h3("Table options"),
radioButtons("useType", "Use Data Types", c("TRUE", "FALSE"))
),
br(),
wellPanel(
h3("Save"),
actionButton("save", "Save table")
),
wellPanel(
textOutput('result')
)
),
mainPanel(
rHandsontableOutput("hot")
)
)
))
server <- shinyServer(function(input, output) {
values <- reactiveValues()
## Handsontable
observe({
if (!is.null(input$hot)) {
DF = hot_to_r(input$hot)
} else {
if (is.null(values[["DF"]]))
DF <- DF
else
DF <- values[["DF"]]
}
values[["DF"]] <- DF
})
output$hot <- renderRHandsontable({
DF <- values[["DF"]]
if (!is.null(DF))
rhandsontable(DF, useTypes = as.logical(input$useType), stretchH = "all")
})
## Save
observeEvent(input$save, {
finalDF <- isolate(values[["DF"]])
saveRDS(finalDF, file=file.path(outdir, sprintf("%s.rds", outfilename)))
})
})
## run app
runApp(list(ui=ui, server=server))
function(input, output)
return(invisible())
}
( DF <- data.frame(Col1=1:10, Col2=runif(10), stringsAsFactors = FALSE))
editTable(DF)
Are you looking for something like that:
ui <- shinyUI(fluidPage(
titlePanel("Edit and save a table"),
sidebarLayout(
sidebarPanel(
helpText("Shiny app based on an example given in the rhandsontable package.",
"Right-click on the table to delete/insert rows.",
"Double-click on a cell to edit"),
wellPanel(
h3("Table options"),
radioButtons("useType", "Use Data Types", c("TRUE", "FALSE")),
actionButton("Calculate", "Calculate column 2")
),
br(),
wellPanel(
h3("Save"),
actionButton("save", "Save table")
),
wellPanel(
textOutput('result')
)
),
mainPanel(
rHandsontableOutput("hot")
)
)
))
server <- shinyServer(function(input, output) {
#extract data from the table to be used
portfoliovals2 <- reactive({
live_data = hot_to_r(input$hot)[,1]
return(live_data)
})
#extract data to be used
portfoliovalsB2 <- reactive({
live_data = hot_to_r(input$hot)[,2]
return(live_data)
})
## create a new df every time the table is modified
new_df_g <- reactive({
initial_dataEdit = portfoliovals2()
initial_dataEditB = portfoliovalsB2()
initial_dataEditW <- data.frame(initial_dataEdit, initial_dataEditB)
return(initial_dataEditW)
})
output$hot <- renderRHandsontable({
if (input$Calculate ==0){
initial_data = data.frame(Col1=1:10, Col2=runif(10), stringsAsFactors = FALSE)
} else {
initial_data = new_df_g()
initial_data <- plyr::rename(initial_data, c("initial_dataEdit"="Col1", "initial_dataEditB"="Col2"))
initial_data$Col2 <- initial_data$Col1 * 1.3
}
rhandsontable(initial_data, readOnly = FALSE, rowHeaders = NULL, height = 600) %>%
hot_cols(columnSorting = TRUE)
})
})
## Save
observeEvent(input$save, {
finalDF <- new_df_g()
saveRDS(finalDF, file=file.path(outdir, sprintf("%s.rds", outfilename)))
})
})
## run app
runApp(list(ui=ui, server=server))
I have reactive data react$data, and I have two inputs input$chosencolumn, input$chosenrows
With the reactive dataset, how would I be able to specify rows I want like a data.frame where you do data[data$chosencolumn == chosenrows,]
Reproducible example:
server.R
### Start of Shiny server
shinyServer(function(input, output, session) {
reactdata <- reactiveValues()
observe({
if(is.null(input$fileinput)){return(NULL)}
else{reactdata$inputdata <- read.xlsx(input$fileinput$datapath, header=T, sheetIndex = 1)}
})
output$selectsamples <- renderUI({
if(is.null(input$fileinput)){return(NULL)}
selectInput("selectsamples",
label = h5("Samples"), choices = colnames(reactdata$inputdata),
selected="Sample")
})
output$sampleselected <- renderUI({
if(is.null(input$fileinput)){return(NULL)}
selectInput("sampleselected",
label = h5("sampleselected"), choices = unique(as.character(reactdata$inputdata[,input$selectsamples])),
selected="B")
})
output$selectdilutions <- renderUI({
if(is.null(input$fileinput)){return(NULL)}
selectInput("selectdilutions",
label=h5("Select Dilutions"),
choices = colnames(reactdata$inputdata),
selected="Dilution")
})
reactdata1 <- reactiveValues()
observe({
reactdata1$datatable1 <- datatable(reactdata$inputdata,
rownames = TRUE,
options = list(pageLength = 100, dom = 'tip'))
})
output$datatable1 <- renderDataTable({
reactdata1$datatable1
})
})
ui.R
require(shiny)
require(devtools)
require(grDevices)
require(xlsx)
require(DT)
shinyUI(fluidPage(
navbarPage("",inverse = FALSE,
tabPanel("Analyse")),
titlePanel(""),
fluidRow(
column(3,
wellPanel(
fileInput("fileinput", label = h5("Input file")),
uiOutput("selectsamples"),
uiOutput("sampleselected"),
uiOutput("selectdilutions")
)),
column(9,
fluidRow(
wellPanel(
uiOutput("sample1"),
dataTableOutput("datatable1"))
)))
)
)
I would like to change reactdata1$datatable1 so that it only includes rows of data chosen by the sample selected (i.e. the value that input$sampleselected is chosen as).
So, something like reactdata1$datatable1[input$selectsamples == input$sampleselected,]
An example dataset is here:
Dropbox link to excel file
Here's a general example where you subset a reactive data.frame based on dynamically entered user input:
require(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars","DNase","iris")
),
selectizeInput(
'colName', 'Select Column: ', list(), multiple = TRUE
),
selectizeInput(
'rowName', 'Select Rows', list(), multiple = TRUE
)
),
mainPanel(
tableOutput('tbl')
)
) #end sidebar layout
))
server <- shinyServer(function(input, output, session) {
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars,
"DNase"=DNase,
"iris"=iris)
})
# Update UI
observe({
updateSelectizeInput(session, "colName", choices = colnames( datasetInput() ))
updateSelectizeInput(session, "rowName", choices = rownames( datasetInput() ))
})
# Create reactive data by subseting the reactive dataset
r1 <- reactive({
v <- input$colName %in% colnames(datasetInput())
if( sum(v == FALSE) > 0) return() # Check for missmatching datasetInput names and column names
if(is.null(input$colName) || is.null(input$rowName)) return() # None selected, return empty
# Subset data
datasetInput()[as.numeric(input$rowName), input$colName, drop=FALSE]
})
output$tbl <- renderTable({
r1()
})
})
shinyApp(ui, server)
I am following this tutorial to learn to build Shiny apps. In the final version, the renderUI() for "Country" just takes all of the countries in the dataset. Is there a way to make this list reactive/filtered based on the price range selected with the slider?
Here is the relevant code:
output$countryOutput <- renderUI({
selectInput("countryInput", "Country",
sort(unique(bcl$Country)),
selected="CANADA")
})
And here is the entire. very simple app:
library(shiny)
library(ggplot2)
library(dplyr)
bcl <- read.csv("bcl-data.csv", stringsAsFactors = FALSE)
ui <- fluidPage(
titlePanel("BC Liquor Prices", windowTitle = "Mmmmm yeh"),
sidebarLayout(
sidebarPanel(
sliderInput("priceInput", "Price",
min = 0, max = 100,
value = c(25, 40), pre = "$"
),
radioButtons("typeInput", "Product type",
choices = c("BEER", "REFRESHMENT", "SPIRITS", "WINE"),
selected = "WINE"
),
uiOutput("countryOutput")
),
mainPanel(plotOutput("coolplot"),
br(),
br(),
tableOutput("results")
)
)
)
server <- function(input, output, session) {
filtered <- reactive({
if (is.null(input$countryInput)) {return(NULL)}
bcl %>%
filter(
Price >= input$priceInput[1],
Price <= input$priceInput[2],
Type == input$typeInput,
Country == input$countryInput
)
})
output$countryOutput <- renderUI({
selectInput("countryInput", "Country",
sort(unique(bcl$Country)),
selected="CANADA")
})
output$coolplot <- renderPlot({
if (is.null(filtered())) {return()}
ggplot(filtered(), aes(Alcohol_Content)) + geom_histogram()
})
output$results <- renderTable({
filtered()
})
}
shinyApp(ui = ui, server = server)
Try this code...You need two different reactive values: 1) One to generate the country list based on first two inputs and 2) Two two generate the plot and table results based on the selected country.
Also, I changed the names to reflect the actual column names I get when reading that file. You may need to change back IF you changed them in some other part of the code.
library(shiny)
library(ggplot2)
library(dplyr)
bcl <- read.csv("bcl-data.csv", stringsAsFactors = FALSE)
ui <- fluidPage(
titlePanel("BC Liquor Prices", windowTitle = "Mmmmm yeh"),
sidebarLayout(
sidebarPanel(
sliderInput("priceInput", "Price",
min = 0, max = 100,
value = c(25, 40), pre = "$"
),
radioButtons("typeInput", "Product type",
choices = c("BEER", "REFRESHMENT", "SPIRITS", "WINE"),
selected = "BEER"
),
uiOutput("countryOutput")
),
mainPanel(plotOutput("coolplot"),
br(),
br(),
tableOutput("results")
)
)
)
server <- function(input, output, session) {
filteredForCountry <- reactive({
bcl %>%
filter(
CURRENT_DISPLAY_PRICE >= input$priceInput[1],
CURRENT_DISPLAY_PRICE <= input$priceInput[2],
PRODUCT_SUB_CLASS_NAME == input$typeInput
)
})
output$countryOutput <- renderUI({
df <- filteredForCountry()
if (!is.null(df)) {
selectInput("countryInput", "Country",
sort(unique(df$PRODUCT_COUNTRY_ORIGIN_NAME)),
selected="CANADA")
}
})
filteredFull <- reactive({
if (is.null(input$countryInput)) {
return (filteredForCountry())
}
bcl %>%
filter(
CURRENT_DISPLAY_PRICE >= input$priceInput[1],
CURRENT_DISPLAY_PRICE <= input$priceInput[2],
PRODUCT_SUB_CLASS_NAME == input$typeInput,
PRODUCT_COUNTRY_ORIGIN_NAME == input$countryInput
)
})
output$coolplot <- renderPlot({
if (is.null(filteredFull())) {return()}
ggplot(filteredFull(), aes(PRODUCT_ALCOHOL_PERCENT)) +
geom_histogram(binwidth = 0.05)
})
output$results <- renderTable({
filteredFull()
})
}
shinyApp(ui = ui, server = server)