I am trying to make an app in Shiny which is dynamically subsetting a data-set 3 times by users input.
Let's assume that the dataset is that
Number<- c(10, 20, 30 , 40, 50 ,60, 70, 80, 90,100,110,120,130,140)
Att1 <- c('a','a','a','a','a','a','a','b','b','b','b','b','b','b')
Att2 <- c('c','c','c','d','d','d','d','e','e','e','g','g','g','g')
Index<-c('I1','I2','I3','I4', 'I5','I6','I7','I8','I9','I10', 'I11','I12','I13','I14')
df <- data.frame(Number, Att1 , Att2,Index)
What i want to do is to create a dropdown menu that gives you the choices a or b from att1 then the choice reacts with the second drop down where the choices of the att2 are displayed but subsetted for choice att1. Depending on the choice the user then the last drop down will give him the choices for which index to choose. Now after the choice of the index a dataframe have to return with only the numbers indicated by the index and this number will be used in next steps.
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
library(data.table)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("App"),
sidebarLayout(
sidebarPanel(
selectInput("Att1", "Choose Att1",choices= c(as.character(unique(df$Att1)) )),
uiOutput("c")),
# Show a plot of the generated distribution
mainPanel( DT::dataTableOutput("table")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
Number<- c(10, 20, 30 , 40, 50 ,60, 70, 80, 90,100,110,120,130,140)
Att1 <- c('a','a','a','a','a','a','a','b','b','b','b','b','b','b')
Att2 <- c('c','c','c','d','d','d','d','e','e','e','g','g','g','g')
Index<-c('I1','I2','I3','I4', 'I5','I6','I7','I8','I9','I10', 'I11','I12','I13','I14')
df <- data.frame(Number, Att1 , Att2,Index)
selectedData <- reactive({
Ddata<-subset(df,Att1==input$Att1)
})
output$c<-renderUI({selectInput("Att2", "Choose Att2",choices= c(as.character(unique(selectedData()$Att2)) ))})
selectedData2 <- reactive({
Vdata<-subset(selectedData(),Att2==input$c)
Vdata<-as.data.frame(Vdata)
Vdata
})
output$table <- DT::renderDataTable({
head(selectedData2(), n = 10)
})
}
# Run the application
shinyApp(ui = ui, server = server)
This is where I got as far but the problem is how can I use a reactive dataset second time in a reactive expression and also the output for the first 2 attributes is null. I am trying to solve this for days, any thoughts?
There is a specific shiny function to update the content of a SelectInput: updateSelectInput().
If used inside an observe it can be used exactly for what you are trying to do:
server <- function(input, output, session) {
observe({
input$Att1
x <- df[df$Att1 == input$Att1, 'Att2']
xs <- as.character(unique(x))
updateSelectInput(session, 'Att2', choices = xs)
})
selectedData <- reactive({
df[df$Att2 == input$Att2, ]
})
output$table <- DT::renderDataTable({
head(selectedData(), n = 10)
})
}
Here is the ui for completeness
ui <- fluidPage(
# Application title
titlePanel("App"),
sidebarLayout(
sidebarPanel(
selectInput("Att1", "Choose Att1",choices = as.character(unique(df$Att1)) ),
selectInput("Att2", "Choose Att2",choices = NULL, selected = 1)
),
# Show a plot of the generated distribution
mainPanel( DT::dataTableOutput("table")
)
)
)
Just continuing with what you have... I added "NULL" as a choice to the drop-downs, and if "NULL" is selected then the full data set is retained.
Number <- c(10, 20, 30 , 40, 50 ,60, 70, 80, 90,100,110,120,130,140)
Att1 <- c('a','a','a','a','a','a','a','b','b','b','b','b','b','b')
Att2 <- c('c','c','c','d','d','d','d','e','e','e','g','g','g','g')
Index <- c('I1','I2','I3','I4', 'I5','I6','I7','I8','I9','I10', 'I11','I12','I13','I14')
df <- data.frame(Number, Att1, Att2, Index)
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
library(data.table)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("App"),
sidebarLayout(
sidebarPanel(
selectInput("Att1", "Choose Att1", choices = c("NULL", as.character(unique(df$Att1))), selected = "NULL"),
uiOutput("c"),
uiOutput("d")),
# Show a plot of the generated distribution
mainPanel( DT::dataTableOutput("table")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
selectedData <- reactive({
if(input$Att1 == "NULL") Ddata <- df #Keep full data set if NULL
else Ddata <- subset(df, Att1 == input$Att1)
Ddata
})
######################
output$c <- renderUI({selectInput("Att2", "Choose Att2", choices = c("NULL", as.character(unique(selectedData()$Att2))), selected = "NULL")})
selectedData2 <- reactive({
if(input$Att2 == "NULL") Vdata <- selectedData()
else Vdata <- subset(selectedData(), Att2 == input$Att2)
Vdata
})
######################
#=====================
output$d <- renderUI({selectInput("Index", "Choose Index", choices = c("NULL", as.character(unique(selectedData2()$Index))), selected = "NULL")})
selectedData3 <- reactive({
if(input$Index == "NULL") Fdata <- selectedData2()
else Fdata <- subset(selectedData2(), Index == input$Index)
Fdata
})
#=====================
output$table <- DT::renderDataTable({
head(selectedData3(), n = 10)
})
}
# Run the application
runApp(shinyApp(ui = ui,
server = server), launch.browser=TRUE
)
Related
I have a shiny app which is used to sample 10 rows of iris data.
When I start this shiny app for the first time, I need to click the sampling action button to display the sampled iris rows.
Is it possible to pre-assign a value that could allow shiny to display the sampled iris data when I first open the app?
Below is the original code.
library(shiny)
ui = fluidPage(
actionButton(inputId = "sampling", label = "Sample rows"),
tableOutput("DFTable")
)
server = function(input, output, session){
n <- eventReactive(input$sampling, {
getrows <- dim(iris)[1]
return(sample(1:getrows, 10))
})
output$DFTable <- renderTable(iris[n(), ])
}
shinyApp(ui, server)
I tried two ways, both didn't work.
to initiate a default value for n
n <- reactiveVal(value = 1:10)
use if() function
output$DFTable <- renderTable(
if(is.null(n())){n() = 1:10}
iris[n(), ]
)
Thanks a lot for your help.
Would the following work for you?
library(shiny)
ui = fluidPage(
actionButton(inputId = "sampling", label = "Sample rows"),
tableOutput("DFTable")
)
server = function(input, output, session){
values <- reactiveValues()
values$n <- sample(1:nrow(iris), 10)
observeEvent(input$sampling, {
values$n <- sample(1:nrow(iris), 10)
})
output$DFTable <- renderTable(iris[values$n, ])
}
shinyApp(ui, server)
I want to make a shiny app that can make successive calculations based on user input. Something like this:
a <- input$inputa
b <- a+2
c <- b-3
d <- c*4
e <- d/5
So the user would choose input a, and the shiny app would do the rest and show values a, b, c, d, e.
I managed to do it if the app always makes the entire calculations based on a. But if I try to create value b and call it, it breaks.
The following code works and shows the final result as it should, but I'm sure it can be improved upon, removing repetitions:
# UI
ui <- fluidPage(
# Application title
titlePanel("Doing algebra"),
# Sidebar with numeric input
sidebarLayout(
sidebarPanel(
numericInput("inputa",
"Input a:",
min = 0,
max = 100,
value = 20,
step=1)
),
# Show results of successive calculations
mainPanel(
verbatimTextOutput("output1"),
h4("+2"),
verbatimTextOutput("output2"),
h4("-3"),
verbatimTextOutput("output3"),
h4("*4"),
verbatimTextOutput("output4"),
h4("/5"),
verbatimTextOutput("output5")
)
)
)
# server
server <- function(input, output) {
output$output1 <- renderText({ input$inputa })
output$output2 <- renderText({ input$inputa+2 })
output$output3 <- renderText({ ( input$inputa+2)-3 })
output$output4 <- renderText({ (( input$inputa+2)-3)*4 })
output$output5 <- renderText({ ((( input$inputa+2)-3)*4)/5 })
}
shinyApp(ui, server)
The last bit, (((input$inputa+2)-3)*4)/5, looks terrible and is terrible. Can I make a shiny app that creates a value in one equation and uses that value in the next equation?
Thanks!
You can store the data in a reactive expression.
ui <- fluidPage(
# Application title
titlePanel("Doing algebra"),
# Sidebar with numeric input
sidebarLayout(
sidebarPanel(
numericInput("inputa",
"Input a:",
min = 0,
max = 100,
value = 20,
step=1)
),
# Show results of successive calculations
mainPanel(
verbatimTextOutput("output1"),
h4("+2"),
verbatimTextOutput("output2"),
h4("-3"),
verbatimTextOutput("output3"),
h4("*4"),
verbatimTextOutput("output4"),
h4("/5"),
verbatimTextOutput("output5")
)
)
)
# server
server <- function(input, output) {
rv <- reactive({
tibble::tibble(a = input$inputa, b = a + 2, c = b-3, d = c*4, e = d/5)
})
output$output1 <- renderText({rv()$a})
output$output2 <- renderText({rv()$b})
output$output3 <- renderText({rv()$c})
output$output4 <- renderText({rv()$d})
output$output5 <- renderText({rv()$e})
}
shinyApp(ui, server)
I have a dataframe with a time series as index. The data in the data frame are updated by a dashboard action (e.g. a download button) and therefore the dataframe is reactive. With a slider I want to be able to select only certain rows of the dataframe. The min max values of the slider therefore refer to the rownames of the reactive data frame. So far I am not able to get this implemented. Below the code. The if(0) part in the SERVER section is the one I am talking about. Any help appreciated.
require(shiny)
AquireData <- function(){
# In this function the data are created
df <- data.frame(replicate(3,sample(0:50,1000,rep=TRUE)))
rownames(df) <- seq(from = as.POSIXct("2012-05-15 07:00"),
to = as.POSIXct("2019-05-17 18:00"), by = "min")[0:dim(df)[1]]
names(df) <- c('A','B','C')
return (df)
}
ui <- fluidPage(
# App title
titlePanel("my dashboard"),
# define stuff for the sidebar (buttons, selectlists etc.). These items will
# be displayed for all panels
sidebarLayout(
sidebarPanel(
actionButton("Button_GetAndUpdate", "Update data"),
sliderInput("start_end_dates", "Date range", min =0, max=0, value=1)
),
# Main panel. Here you can display your graphs, plots and tables
mainPanel("observed data", tableOutput("rawdata"))
)
)
server <- function(input, output,session) {
# When the app is called an update of the data is drawn
df_data <- reactive({AquireData()})
# Check what the update button is doing. If its getting pressed pull and update
observeEvent (input$Button_GetAndUpdate,{df_data <<- reactive({AquireData()})})
# set date range slider values using the dates from the data frame index
if(0){
updateSliderInput(session, "start_end_dates",
label = "Date range",
min = as.POSIXct(min(rownames(df_data())),"%Y-%m-%d %H:%M:%S",tz=""),
max = as.POSIXct(max(rownames(df_data())),"%Y-%m-%d %H:%M:%S",tz="")
)
}
# get the head of the dataframe
data_head <- reactive({
input$Button_GetAndUpdate
isolate({
head(df_data())
})
})
output$rawdata <- renderTable({
data_head()
})
}
shinyApp(ui = ui, server = server)
runApp("Header_dashboard")
You could use shinyWidgets::sliderTextInput and shinyWidgets::updateSliderTextInput respectively instead of sliderInputfor this:
shinyWidgets::updateSliderTextInput(
session, "start_end_dates",
choices = rownames(df_data())
)
That means for your app:
require(shiny)
AquireData <- function(){
# In this function the data are created
df <- data.frame(replicate(3,sample(0:50,1000,rep=TRUE)))
rownames(df) <- seq(from = as.POSIXct("2012-05-15 07:00"),
to = as.POSIXct("2019-05-17 18:00"), by = "min")[0:dim(df)[1]]
names(df) <- c('A','B','C')
return (df)
}
ui <- fluidPage(
# App title
titlePanel("my dashboard"),
# define stuff for the sidebar (buttons, selectlists etc.). These items will
# be displayed for all panels
sidebarLayout(
sidebarPanel(
actionButton("Button_GetAndUpdate", "Update data"),
shinyWidgets::sliderTextInput(
"start_end_dates",
label = "Time range",
choices = c(as.POSIXct("2019-01-01 12:00:00"), as.POSIXct("2019-12-31 14:00:00")),
)
),
# Main panel. Here you can display your graphs, plots and tables
mainPanel("observed data", tableOutput("rawdata"))
)
)
server <- function(input, output,session) {
# When the app is called an update of the data is drawn
df_data <- reactive({AquireData()})
# Check what the update button is doing. If its getting pressed pull and update
observeEvent (input$Button_GetAndUpdate,{df_data <<- reactive({AquireData()})})
# set date range slider values using the dates from the data frame index
observe({
shinyWidgets::updateSliderTextInput(
session, "start_end_dates",
choices = rownames(df_data())
)
})
# get the head of the dataframe
data_head <- reactive({
input$Button_GetAndUpdate
isolate({
head(df_data())
})
})
output$rawdata <- renderTable({
data_head()
})
}
shinyApp(ui = ui, server = server)
I know this question has been posted a few times but this is my first time developing something i Shiny and I am getting confused with a couple different things. One of them is inputting the data frame correctly and using it in the output functions.
My only goals right now is to:
Display the head or complete dataframe depending on user choice
I have a binary column called status (status being Pass or Fail). I want to group by dates to count the status (any one would do) and plot it.
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(readxl)
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Data Quality Result Monitoring"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")
),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head")
),
# Show a plot of the generated distribution
mainPanel(
#plotOutput("linechart"),
h4("Observations"),
tableOutput("contents")
)
)
# Define server logic required to draw a histogram'
library(ggplot2)
server <- function(input, output) {
df <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
df <- read_xlsx(inFile$datapath, sheet = 1)
return(inFile)})
output$linechart <- renderPlot({
ndf() <- group_by(df,Execution_Date) %>% summarize( count = n() )
ggplot(ndf()) + geom_bar(aes(x=week,y=count),stat="identity")
})
output$contents <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, head of that data file by default,
# or all rows if selected, will be shown.
dataset() <- df
if(input$disp == "head") {
return(head(dataset()))
}
else {
return(dataset())
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
dataset() <- df
This is where you get the error:
"Error in <-: invalid (NULL) left side of assignment"
You can not assign a value to a reactive expression. It works the other way round:
dataset <- df()
Play around with this by using the print function.
Another error in your code is this:
df <- read_xlsx(inFile$datapath, sheet = 1)
return(inFile)
You return the wrong variable, you want to return the df.
Here is the code which should work for you:
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(readxl)
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Data Quality Result Monitoring"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")
),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head")
),
# Show a plot of the generated distribution
mainPanel(
#plotOutput("linechart"),
h4("Observations"),
tableOutput("contents")
)
)
# Define server logic required to draw a histogram'
library(ggplot2)
server <- function(input, output) {
df <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
df <- read_xlsx(inFile$datapath, sheet = 1)
df
})
output$linechart <- renderPlot({
ndf <- group_by(df(),Execution_Date) %>% summarize( count = n() )
ggplot(ndf + geom_bar(aes(x=week,y=count),stat="identity"))
})
output$contents <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, head of that data file by default,
# or all rows if selected, will be shown.
dataset <- df()
if(input$disp == "head") {
return(head(dataset))
}
else {
return(dataset)
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
I also recommend that you implement a check for structure and names in your code.
This is due to ndf() <- group_by(df,Execution_Date) %>% summarize( count = n() )
ndf() is NULL function that does not exist.
df is a reactive and you use it with df() instead of df, meaning that code is evaluated each time the reactivity changes.
I have written R code and tried to create a shiny app which will serve the same purpose with gui.
R code:
text1 <-data.frame(x=2,y=30)
text1
text2 <- data.frame(a=11,b=10)
text2
# fisrt set of data
z<- cbind.data.frame(text1,text2)
z
# second set of data
nz <-cbind.data.frame(text1,text2)
nz
# combined data. my plan to change the z or nz, and it will reflect everytime, and save as z.
# every time I change any value of x,y,a,and b. it should add a new row
# couldn't able to write the following steps in shiny as reactive form
z <- rbind.data.frame(z,nz)
z
I have tried to prepare a shiny app but couldn't do the step of
z <- rbind.data.frame(z,nz)
z
In shiny. It would be helpful anyone has any idea. z will be overwritten by the row bind of z and nz. The shiny app code is given below:
library(shiny)
ui <- fluidPage(theme = shinytheme("sandstone"),
# header
headerPanel("DTI post analysis conversion"),
sidebarLayout(
# sidebar for form
sidebarPanel(
h3("Information",""),
textInput("x", "Value X",""),
textInput("y", "Value Y",""),
textInput("a", "Value a",""),
textInput("b", "Value b",""),
actionButton("update", "first data Set"),
actionButton("update1", "Add another Set")),
# output for viewing
mainPanel(
DT::dataTableOutput("tableDT"),
#DT::dataTableOutput("tableDT1"),
DT::dataTableOutput("tableDT2")
)
)
)
server <- function(input, output, session) {
text1 <- reactive({
tx1 <- data.frame(X = input$x,
Y = input$y)
})
text2 <- reactive({
tx2 <- data.frame(A = input$a,
B = input$b)
})
# create 1st row of data
z <- eventReactive(input$update,{
cbind.data.frame(text1(), text2())
})
# create 2nd row of data
nz <- eventReactive(input$update1,{
cbind.data.frame(text1(), text2())
})
# everytime I change any value and click "add another data set", it should add a new row
# the problem is it only works for the first time.
combine <- eventReactive(input$update1,{
rbind.data.frame(z(), nz())
})
output$tableDT <- DT::renderDataTable(
z()
)
output$tableDT1 <- DT::renderDataTable(
nz()
)
output$tableDT2 <- DT::renderDataTable(
combine()
)
}
shinyApp (ui = ui, server = server)
I've tried to assign the combined value to a global object and then use it everytime the button is clicked. Please check if this helps.
library(shiny)
ui <- fluidPage(theme = shinytheme("sandstone"),
# header
headerPanel("DTI post analysis conversion"),
sidebarLayout(
# sidebar for form
sidebarPanel(
h3("Information",""),
textInput("x", "Value X",""),
textInput("y", "Value Y",""),
textInput("a", "Value a",""),
textInput("b", "Value b",""),
actionButton("update", "first data Set"),
actionButton("update1", "Add another Set")),
# output for viewing
mainPanel(
DT::dataTableOutput("tableDT"),
#DT::dataTableOutput("tableDT1"),
DT::dataTableOutput("tableDT2")
)
)
)
f <- data.frame()
server <- function(input, output, session) {
text1 <- reactive({
tx1 <- data.frame(X = input$x,
Y = input$y)
})
text2 <- reactive({
tx2 <- data.frame(A = input$a,
B = input$b)
})
# create 1st row of data
z <- eventReactive(input$update,{
f <<- cbind.data.frame(text1(), text2())
f
})
# create 2nd row of data
nz <- eventReactive(input$update1,{
cbind.data.frame(text1(), text2())
})
# everytime I change any value and click "add another data set", it should add a new row
# the problem is it only works for the first time.
combine <- eventReactive(input$update1,{
f <<- rbind.data.frame(f, nz())
})
output$tableDT <- DT::renderDataTable(
z()
)
output$tableDT1 <- DT::renderDataTable(
nz()
)
output$tableDT2 <- DT::renderDataTable(
combine()
)
}
shinyApp (ui = ui, server = server)
The new code which avoid the duplication is given below:
library(shiny)
ui <- fluidPage(theme = shinytheme("sandstone"),
# header
headerPanel("DTI post analysis conversion"),
sidebarLayout(
# sidebar for form
sidebarPanel(
h3("Information",""),
textInput("x", "Value X",""),
textInput("y", "Value Y",""),
textInput("a", "Value a",""),
textInput("b", "Value b",""),
actionButton("update", "first data Set"),
actionButton("update1", "Add another Set")),
# output for viewing
mainPanel(
DT::dataTableOutput("tableDT"),
#DT::dataTableOutput("tableDT1"),
DT::dataTableOutput("tableDT2")
)
)
)
f <- data.frame()
server <- function(input, output, session) {
text1 <- reactive({
tx1 <- data.frame(X = input$x,
Y = input$y)
})
text2 <- reactive({
tx2 <- data.frame(A = input$a,
B = input$b)
})
# create 1st row of data
z <- eventReactive(input$update,{
f <<- cbind.data.frame(text1(), text2())
})
# create 2nd row of data
nz <- eventReactive(input$update1,{
cbind.data.frame(text1(), text2())
})
# everytime I change any value and click "add another data set", it should add a new row
# the problem is it only works for the first time.
combine <- eventReactive(input$update1,{
f <<- rbind.data.frame(z(), nz())
})
# this step avoid the duplication of add rows
combine2<- eventReactive(input$update1,{
f<<- rbind.data.frame(f, nz())
})
output$tableDT <- DT::renderDataTable(
z()
)
output$tableDT1 <- DT::renderDataTable(
nz()
)
output$tableDT2 <- DT::renderDataTable(
combine2()
)
}
shinyApp (ui = ui, server = server)