In my app, the user can upload their file as the input data (using file upload widget). If they don't have their data, I provide some demo data (user can choose demo data by clicking actionButton).
How do I make a variable = the upload OR the demo, whichever is later? Any help is appreciated.
server.R
library(shiny)
DemoData = data.frame('Col.1'=c('Demo','Demo'),
'Col.2'=c('Data','Data'))
shinyServer(function(input, output) {
# option 1: use demo data
getDemo = eventReactive(input$Demo,{
DemoData
})
# option 2: user upload data
getUpload = reactive({
inFile = input$file
if (is.null(inFile)) return(NULL)
read.csv(inFile$datapath)
})
# need getData() to be option 1 or 2, whichever happened later
# should respond to multiple times of changing between option 1 and 2
getData = # ??? getDemo() or getUpload(), whichever is later
# show the data
output$InputData = renderDataTable({
as.data.frame( getData() )
})
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel(h2("Hello Shiny")),
sidebarLayout(
sidebarPanel(
fileInput('file',
'Choose CSV File (two columns: Town and State)',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')
),
actionButton('Demo', 'Use Demo Data')
),
mainPanel(
tabsetPanel(
tabPanel(title=h4('Data'),
column(5, tags$h3('Input Data'), dataTableOutput('InputData'))
)
)
)
)
))
UserData.R (maybe make it easier for you to test)
getwd()
setwe()
UserData = data.frame('Col.1'=c('User','User'),
'Col.2'=c('Data','Data'))
write.csv(UserData, file="UserData.csv", row.names=FALSE)
You can use observers, one to watch the demo button and one to watch for file uploads. Both update the same reactive data, so you see the effect of whichever happened last.
library(shiny)
DemoData <- data.frame('Col.1'=1:10,
'Col.2'=rnorm(10))
shinyApp(
shinyUI(fluidPage(
titlePanel(h2("Hello Shiny")),
sidebarLayout(
sidebarPanel(
fileInput('file',
'Choose CSV File (two columns: Town and State)',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')
),
actionButton('Demo', 'Use Demo Data')
),
mainPanel(
tabsetPanel(
tabPanel(title=h4('Data'),
column(5, tags$h3('Input Data'), tableOutput('InputData'))
)
)
)
)
)),
shinyServer(function(input, output) {
values <- reactiveValues() # store values to be changed by observers
values$data <- data.frame()
## Observer for uploaded file
observe({
inFile = input$file
if (is.null(inFile)) return(NULL)
values$data <- read.csv(inFile$datapath)
})
## Observer for demo data button
observe({
if (input$Demo > 0) # otherwise demo data shows on startup
values$data <- DemoData
})
## show the data
output$InputData = renderTable({
values$data
})
})
)
Related
I want to create a shiny app that do two things. Frist it has to be able to upload XLS file and after the user can add it some columns (in this case, just the column "Tecnico"), but for the moment I cant be able to do that. Once the user write the value for the column and update the table, the app crashed.
library(shiny)
library(readxl)
runApp(
list(
ui = fluidPage(
titlePanel("Use readxl"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")),textInput("tecnix","Tecnico"),
actionButton("go", "update")),
mainPanel(
tableOutput('my_output_data'))
)
),
server = function(input, output){
data1 <- reactive({
inFile <- input$file1
if (is.null(inFile)){return(NULL)}
isolate({
input$file1
my_data <- read_excel(inFile$datapath)
})
my_data
})
observeEvent(input$go, {
data1()$Técnico <- input$tecnix
})
output$my_output_data <- renderTable({data1()})
}
))
Any ideas?
Thank you so much,
As suggested by #Till using reactiveValues will help solve the problem.
library(shiny)
library(readxl)
runApp(
list(
ui = fluidPage(
titlePanel("Use readxl"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")),textInput("tecnix","Tecnico"),
actionButton("go", "update")),
mainPanel(
tableOutput('my_output_data'))
)
),
server = function(input, output){
rv <- reactiveValues(my_data = NULL)
observeEvent(input$file1, {
req(input$file1$datapath)
rv$my_data <- read_excel(input$file1$datapath)
})
observeEvent(input$go, {
rv$my_data$Techni <- input$tecnix
})
output$my_output_data <- renderTable({rv$my_data})
}
))
I have a Shiny app that includes a number of dropdown selection boxes, the values of which are filled from reading an RDS file. The app also includes a fileInput function to upload new data. How can I change the values in the dropdown boxes to reflect the new data? Currently I can see that the data is uploaded, but the old data remains in the dropdown.
The data that should be uploaded is saved to a file using
saveRDS( data.frame(names=c("Jill","Jane","Megan")),"myDataFrame.rds")
In my app.R file, I first define the 'default' value of the data:
myDataFrame <- data.frame(names=c("Tom","Dick","Harry"))
The content of my app.R is as follows:
library(shiny)
ui <- shinyUI(
fluidPage(
fileInput('file1', 'Choose file to upload',accept = ".rds"),
selectInput("myNames","Names",myDataFrame$names),
tableOutput('contents')
)
)
server <- shinyServer(function(input, output) {
output$contents <- renderTable({
inFile <- input$file1
if (is.null(inFile)) { return(myDataFrame) }
readRDS(inFile$datapath)
})
})
The initial view of the application is as expected: both the dropdown and the table contain the 'default' names. Upon upload of my RDS file containing a new dataframe, the table changes (which is what I was looking for) but the dropdown values do not. How can I make the latter happen?
I added reactive object myData that you have to use for table contents, but more importantly to update choices in selectInput (check observe and updateSelectInput part).
library(shiny)
ui <- shinyUI(
fluidPage(
fileInput("file1", "Choose file to upload", accept = ".rds"),
selectInput("myNames","Names", ""),
tableOutput("contents")
)
)
server <- function(input, output, session) {
myData <- reactive({
inFile <- input$file1
if (is.null(inFile)) {
d <- myDataFrame
} else {
d <- readRDS(inFile$datapath)
}
d
})
output$contents <- renderTable({
myData()
})
observe({
updateSelectInput(session, "myNames",
label = "myNames",
choices = myData()$names,
selected = myData()$names[1])
})
}
shinyApp(ui, server)
to riff off of #PoGibas' answer, I needed to load multiple list values for an app, here is a similar application using reactiveValues and observeEvent :
library(shiny)
# save a dummy RDS for loading
saveRDS(list(names=LETTERS,numbers=seq(10)),'dummy.rds')
# define initial values
myDataList <- list(names=c("Tom","Dick","Harry"), numbers=seq(5))
ui <- shinyUI(
fluidPage(
fileInput("file1", "Choose file to upload", accept = ".rds"),
selectInput("myNames","Names", ""),
selectInput("myNumbers","Numbers", ""),
tableOutput("contents")
)
)
server <- function(input, output, session) {
md <- reactiveValues(
names = myDataList$names,
numbers = myDataList$numbers
)
observeEvent(input$file1,{
d <- readRDS(input$file1$datapath)
for (n in names(d)){
md[[n]] <- d[[n]]
}
})
output$contents <- renderTable({
data.frame(data = c(md$names,md$numbers))
})
observe({
updateSelectInput(session, "myNames",
label = "myNames",
choices = md$names,
selected = md$names[1])
updateSelectInput(session, "myNumbers",
label = "myNumbers",
choices = md$numbers,
selected = md$numbers[1])
})
}
shinyApp(ui, server)
I am trying to create a Shiny dashboard where the user can upload data sets, naming them, and then selecting one data set from a dropdown menu.
I dont fully understand how a user can upload a data, save it and further access it. I tried using assign(), but the dataset does not show up under ls(). My try:
library(data.table)
library(shinyWidgets)
library(shinydashboard)
if (interactive()) {
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
actionButton('show_ls', 'show_ls'),
# Name data
textInput('name_data', 'Store data as' , value = ''),
# Action button to upload
actionButton('upload_data', 'Upload and save data')
),
mainPanel(
tableOutput('ls')
# textOutput('ls'))
)
)
)
server <- function(input, output, session) {
# This part uploads one row from the file, so the user can selects columns and choose name of the file
data <- reactive({
file1 <- input$file1
if(is.null(file1)){return()}
data_input <- fread(file=file1$datapath, sep=",")
updateTextInput(
session,
'name_data',
value = file1$name
)
return(data_input)
})
#### ASSIGNING THE DATA
assign_data <- eventReactive(input$upload_data, {
assign(input$name_data, data(), envir = .GlobalEnv)
})
assign_the_data <- reactive(assign_data())
output$contents <- renderTable({
if(is.null(data())) return(NULL)
data()
})
outputOptions(output, 'contents', suspendWhenHidden = FALSE)
show_ls <- eventReactive(input$show_ls, {data.frame(a = ls(.GlobalEnv))})
output$ls <- renderTable({
show_ls()
})
}
shinyApp(ui, server)
}
Using assign() can be difficult because the search path through the namespace can be difficult to predict. A better solution would be to store the datasets in a reactive values list and access them from there. You can dynamically render the dataset picker UI based on the names of the datasets stored in the reactive values list.
if (interactive()) {
ui <- fluidPage(sidebarLayout(
sidebarPanel(
fileInput(
"file1",
"Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
)
),
# Name data
textInput('name_data', 'Store data as' , value = ''),
# Action button to upload
actionButton('upload_data', 'Upload and save data')
),
mainPanel(uiOutput("dataset_picker"),
tableOutput('selected_table')
# textOutput('ls')))
))
server <- function(input, output, session) {
# This part uploads one row from the file, so the user can selects columns and choose name of the file
dfs <- reactiveValues()
observeEvent(input$upload_data, {
req(input$file1, input$name_data)
dfs[[input$name_data]] <- read.csv(input$file1$datapath[1])
print(names(dfs))
})
output$dataset_picker <- renderUI({
req(length(dfs) > 0)
pickerInput(
"dataset_picker",
label = "Choose dataset",
choices = names(reactiveValuesToList(dfs)),
selected = NULL
)
})
output$selected_table <- renderTable({
req(input$dataset_picker)
dfs[[input$dataset_picker]]
})
}
shinyApp(ui, server)
}
I am very new to Shiny web app with R. I want to generate summary according to choice from checkboxGroupInput which i generated dynamically when browsing the CSV file. My problem is that when i want to convert from String to numeric that time it prints NA.
I am uploading my two files which are ui.r and server.r. I am trying since two days. If anyone help me then it will be very beneficial for me.
If i did anything wrong in my code then please suggest me right way.
ui.r
library(shiny)
library(shinythemes)
shinyUI(fluidPage(
theme = shinytheme("cyborg"),
themeSelector(),
# Application title
titlePanel("Data Analytics and Visualization Dashboard"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose CSV file',accept=c('text/csv', 'text/comma-
separated-values,text/plain')),
h5("Max file size to upload is 5 MB."),
radioButtons("sep", "Seperator", choices = c(Comma = ',', semicolon = ';',
tab = "\t", space = " " )),
#checkboxInput("header", "Header?")
br(),
h4("Select columns from CSV"),
uiOutput("toCol"),
br(),
h4("Summary"),
textOutput("sum")
# tableOutput("disp")
),
mainPanel(
numericInput("obs", "Enter the number of rows to display:", 5),
tableOutput("input_file"),
plotOutput("p")
)
)
))
server.r
library(shiny)
shinyServer(function(input, output,session) {
#This function is repsonsible for reading a csv file
output$input_file <- renderTable({
file_to_read = input$datafile
if(is.null(file_to_read))
{
return()
}
read.csv(file_to_read$datapath, sep = input$sep, nrows = input$obs))
})
#This function is repsonsible for loading in the selected file
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath,nrows = input$obs)
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
checkboxGroupInput("to", "Columns",items)
})
observe({
# db <- gsub(",","",input$to)
# print(db)
# paste( intToUtf8(160), input$to, intToUtf8(160))
# print(summary(as.numeric(as.character( paste( " ", input$to, "
#"))))) })
print(summary(as.numeric( input$to) ))})
# output$sum <- renderPrint({
# summary(input$data.frame[,as.numeric(input$var)])
# })
# output$disp <- renderTable({
# input$to
# })
# output$summary1 <- renderPrint({
# sum <- as.numeric(as.character(input$to))
# summary(sum)
#})
})
This could be a starting point, although I dont recommend using this for a productive app, as the login-process is not really safe nor encrypted. It is based solely on text-data.
But you will have to put the ui in the server and render the page depending on the login status. So there are 2 renderUI but just 1 server-function. I dont know if you can have 2 different server-functions and redirect them. I think it all has to be in 1 server-function.
library(shiny)
username = "joe"
password = "joe123"
ui <- fluidPage(
uiOutput("ui")
)
server <- function(input, output, session) {
LOGGED <- reactiveValues(user = FALSE)
observeEvent(input$action, {
if ((input$name == username ) & (input$pass == password)) {
LOGGED$user = TRUE
} else {
LOGGED$user = FALSE
}
})
observe({
if (LOGGED$user == FALSE) {
output$ui <- renderUI({
tagList(
p(HTML("User is joe <br> and password is joe123")),
textInput("name", "Enter your username"),
passwordInput("pass", "Enter your password"),
actionButton("action", label = "Action")
)
})
} else if (LOGGED$user == TRUE) {
output$ui <- renderUI({
tagList(
h1("You are logged in.")
)
})
}
})
}
shinyApp(ui, server)
Like #Codeer said, there is no line in your code like this one summary(as.numeric(paste(input$to, “input$to”))). I edited your code, so all the uncommented lines dont appear, as its not necessary to show them.
In your example, your loading the csv file twice, which you can definitly avoid.
I moved the csv-loading into the reactive only. Then you can access the loaded file everywhere in your shiny-app. And i think in your print(summary()) statement, you're missing the data, as your only printing out the summary of the input$tovariable, which is only text and if you convert it to numeric you create NA-values.
So i rearranged your code a bit, and I think its behaving the way you intend it to.
library(shiny)
library(shinythemes)
ui <- {shinyUI(fluidPage(
theme = shinytheme("cyborg"),
themeSelector(),
titlePanel("Data Analytics and Visualization Dashboard"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose CSV file',accept=c('text/csv', 'text/comma-
separated-values,text/plain')),
h5("Max file size to upload is 5 MB."),
radioButtons("sep", "Seperator", choices = c(Comma = ',', semicolon = ';',
tab = "\t", space = " " )),
br(),
h4("Select columns from CSV"),
uiOutput("toCol"),
br(),
h4("Summary"),
textOutput("sum")
),
mainPanel(
numericInput("obs", "Enter the number of rows to display:", 5),
tableOutput("input_file"),
verbatimTextOutput("summary"),
plotOutput("p")
)
)
))}
server <- shinyServer(function(input, output,session) {
#This function is repsonsible for loading and reading a csv file
filedata <- reactive({
req(input$datafile)
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath,nrows = input$obs, sep = input$sep)
})
output$input_file <- renderTable({
filedata()
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <- filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
checkboxGroupInput("to", "Columns",items)
})
output$summary <- renderPrint({
req(input$to)
data <- filedata()
print(summary(data[,input$to]))
})
})
shinyApp(ui, server)
The csv file is loaded in the reactive (filedata). In the renderTable, you just enter the reactive variable - filedata(). And in the observe, you call again the reactive variable and only print out the summary of the data in the clicked column (input$to).
I have a Shiny app that includes a number of dropdown selection boxes, the values of which are filled from reading an RDS file. The app also includes a fileInput function to upload new data. How can I change the values in the dropdown boxes to reflect the new data? Currently I can see that the data is uploaded, but the old data remains in the dropdown.
The data that should be uploaded is saved to a file using
saveRDS( data.frame(names=c("Jill","Jane","Megan")),"myDataFrame.rds")
In my app.R file, I first define the 'default' value of the data:
myDataFrame <- data.frame(names=c("Tom","Dick","Harry"))
The content of my app.R is as follows:
library(shiny)
ui <- shinyUI(
fluidPage(
fileInput('file1', 'Choose file to upload',accept = ".rds"),
selectInput("myNames","Names",myDataFrame$names),
tableOutput('contents')
)
)
server <- shinyServer(function(input, output) {
output$contents <- renderTable({
inFile <- input$file1
if (is.null(inFile)) { return(myDataFrame) }
readRDS(inFile$datapath)
})
})
The initial view of the application is as expected: both the dropdown and the table contain the 'default' names. Upon upload of my RDS file containing a new dataframe, the table changes (which is what I was looking for) but the dropdown values do not. How can I make the latter happen?
I added reactive object myData that you have to use for table contents, but more importantly to update choices in selectInput (check observe and updateSelectInput part).
library(shiny)
ui <- shinyUI(
fluidPage(
fileInput("file1", "Choose file to upload", accept = ".rds"),
selectInput("myNames","Names", ""),
tableOutput("contents")
)
)
server <- function(input, output, session) {
myData <- reactive({
inFile <- input$file1
if (is.null(inFile)) {
d <- myDataFrame
} else {
d <- readRDS(inFile$datapath)
}
d
})
output$contents <- renderTable({
myData()
})
observe({
updateSelectInput(session, "myNames",
label = "myNames",
choices = myData()$names,
selected = myData()$names[1])
})
}
shinyApp(ui, server)
to riff off of #PoGibas' answer, I needed to load multiple list values for an app, here is a similar application using reactiveValues and observeEvent :
library(shiny)
# save a dummy RDS for loading
saveRDS(list(names=LETTERS,numbers=seq(10)),'dummy.rds')
# define initial values
myDataList <- list(names=c("Tom","Dick","Harry"), numbers=seq(5))
ui <- shinyUI(
fluidPage(
fileInput("file1", "Choose file to upload", accept = ".rds"),
selectInput("myNames","Names", ""),
selectInput("myNumbers","Numbers", ""),
tableOutput("contents")
)
)
server <- function(input, output, session) {
md <- reactiveValues(
names = myDataList$names,
numbers = myDataList$numbers
)
observeEvent(input$file1,{
d <- readRDS(input$file1$datapath)
for (n in names(d)){
md[[n]] <- d[[n]]
}
})
output$contents <- renderTable({
data.frame(data = c(md$names,md$numbers))
})
observe({
updateSelectInput(session, "myNames",
label = "myNames",
choices = md$names,
selected = md$names[1])
updateSelectInput(session, "myNumbers",
label = "myNumbers",
choices = md$numbers,
selected = md$numbers[1])
})
}
shinyApp(ui, server)