I got stuck on my first shiny app again. So far the App was runing fine, but now I wanted to download the plot I generated and I can not work out how to get the results out of the observe function.
As I can not generate the plot outside the observe function, I was thinking I would assign the necessary data to a global variable useing <<-, but if I run a reactive function e.g. df.selected.columns() this seem to cause errors.
Can someone give me a hint how to proceed?
Thank you so much for any suggestions! Aishe
Here is me code:
ui <- shinyServer(
fluidPage(
tabsetPanel(
tabPanel("Data upload",
titlePanel("Data upload"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",multiple = TRUE, accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE), radioButtons("sep", "Separator", choices = c(Comma = ",", Semicolon = ";",Tab = "\t"), selected = ","),
tags$hr(),
checkboxInput("disp", "Display",TRUE),
tags$hr(),
uiOutput("choose_first_column"),
uiOutput("choose_second_column"),
br()
),
mainPanel(
tableOutput("contents"),
tags$hr(),
tableOutput("tab"),
tags$hr(),
uiOutput("download"),
plotOutput("headplot")
)
)
),
tabPanel("2","2"
)
)
)
)
server <- shinyServer(
function(input, output) {
observe({
req(input$file1)
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
output$contents <- renderTable({
(head(df))})
output$choose_first_column <- renderUI({
colnames <- names(df)
selectInput("column_1", "Choose Date column",
choices = colnames,
selected = colnames)})
output$choose_second_column <- renderUI({
colnames <- names(df)
selectInput("column_2", "Choose Variable column",
choices = colnames,
selected = colnames)})
df.selected.columns <- reactive({
df.columns <- df[,c(input$column_1,input$column_2)]
return(df.columns)
})
output$tab <- renderTable({
(head(df.selected.columns()))
})
Plot1 <- reactive({
plot(head(df.selected.columns()[,2]))
})
output$headplot <- renderPlot({
Plot1()
})
# This comes closest to what I wanted to do. However, now I can not select the columns anymore.
# try(result <<- head(df.selected.columns()[,2]),silent=T)
# With this line it crushes straight away
# result <<- head(df.selected.columns()[,2])
})
output$download <- renderUI({
if(!is.null(input$column_1) & !is.null(input$column_2)) {
downloadButton('OutputPlot', 'Download Plot')
}
})
output$OutputPlot <- downloadHandler(
filename = function() {
paste('plot', '.pdf', sep='')
},
content=function(file){
pdf(file)
plot(result)
dev.off()
})
})
runApp(list(ui = ui, server = server))
Input data example:
date time level
01.01.2000 00:00:00 0.3724
01.01.2000 01:00:00 0.192
01.01.2000 02:00:00 -0.0252
Remove the observe
Make the loaded file a reactive
Update all references to df to df() since it's now a reactive expression
Add appropriate req() functions to prevent error messages
In your downloadHandler you have plot(result), but there's no such thing as result. You want Plot() or plot(df.selected.columns())
You should be confirming that your selected delimiter is actually splitting the loaded table correctly before your return the loaded table. Without that, you'll get errors and strange results/
Here's the updated df and downloadHandler functions to get you started:
df <- reactive({
req(input$file1)
read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
})
output$OutputPlot <- downloadHandler(
filename = function() {
paste('plot', '.pdf', sep='')
},
content=function(file){
pdf(file)
plot(head(df.selected.columns()[,2]))
dev.off()
})
Related
I want to create a shiny app where one can upload a csv file and then select columns of that file. The problem is that after uploading a file, my code fails to update the column names for possible choices. Here is a reproducible example. Thank you!
ui <- fluidPage(
fileInput("file1",
"Please choose a csv File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
div(style="display:inline-block", selectInput('var',
'Select the first var',
"") )
)
server <- function( input, output, session ) {
data <- reactive({
inFile <- input$file1
req(inFile)
validate(need(ext == "csv", "Please upload a csv file"))
df = read.csv(inFile$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
colnames <- names(df)
df
})
output$contents <- renderTable( {
updateSelectInput(session,
inputId = 'var',
label = 'Select the first var',
choices = colnames)
} ) }
shinyApp(ui = ui, server = server)
Some of your reactive expression aren't right, lets split things out to make it easier to follow. In particular use observeEvent to watch the file input.
library(shiny)
ui <- fluidPage(
fileInput("myfileinput", "Please choose a csv File", multiple = FALSE, accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")),
selectInput('myselectinput','Select the first var', ""),
tableOutput('mytable')
)
server <- function(input, output, session) {
#Reactive to store loaded data
reactives <- reactiveValues(
mydata = NULL
)
#Observe file being selected
observeEvent(input$myfileinput, {
#Store loaded data in reactive
reactives$mydata <- read.csv(file = input$myfileinput$datapath)
#Update select input
updateSelectInput(session, inputId = 'myselectinput', label = 'Select the first var', choices = colnames(reactives$mydata))
})
#Data table
output$mytable <- renderTable({
reactives$mydata
})
}
shinyApp(ui = ui, server = server)
The example that I'm working with is the iris data. If the current data contains iris[1:15,], how can I upload a .csv file with more iris data and click a button to combine the uploaded data with the current data and save everything in one dataframe?
Here is what I have so far based on what I've read. I was able to create the fileInput and action button but I think my issue is with the reactive button. I'm not sure how to use it properly to achieve what I need.
library(shiny)
library(DT)
data1<-data.frame(iris[1:15,])
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
numericInput('num','Number of rows',value=10,min=0),
actionButton("update", "Combine Data")),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output) {
output$table <- renderTable({
head(data1,n=input$num)
})
x<-reactive({
req(input$file1)
df_uploaded <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote,
stringsAsFactors = FALSE)
data2<-data.frame(df_uploaded)
return(data2)
})
merged_data<-eventReactive(input$update,{
datam<-rbind.data.frame(data1,x())
return(datam)
})
# output$table <- renderTable({
# head(merged_data(),n=input$num)})
}
shinyApp(ui, server)
Thanks!
The main issue is that read.csv receiving invalid argument i.e. NULL for header, sep, quote as you don't have input$header, input$sep, input$quote in UI.
library(shiny)
library(DT)
data1<-data.frame(iris[1:15,])
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
numericInput('num','Number of rows',value=10,min=0),
actionButton("update", "Combine Data")),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output) {
# output$table <- renderTable({
# head(data1,n=input$num)
# })
x<-reactive({
req(input$file1)
df_uploaded <- read.csv(input$file1$datapath,
#you don't have these variables in the UI, so they will raise an error
#header = input$header,
#sep = input$sep,
#quote = input$quote,
stringsAsFactors = FALSE)
#No need data2 and return(data2) as read.csv returns data.frame by default
#data2<-data.frame(df_uploaded)
#return(data2)
})
merged_data<-eventReactive(input$update,{
datam<-rbind.data.frame(data1, x())
return(datam)
})
output$table <- renderTable({
head(merged_data(), n=input$num)})
}
shinyApp(ui, server)
Newbie to R and working through simple R Shiny examples for learning purposes. The following program enables user to upload a delimited data file, at which point head() displays first few rows. I also want to allow use to input in a text input the name of a variable in the file to generate a frequency. How can i capture the text input and reference it in the server section? You can see i have commented out a line where i manually enter the field and it works fine.
I've sifted through quite a few examples using textinput, but all were facing different issues than i could find. I do apologize if a post already has the help i seek. Thanks in advance.
server <- function(input, output) {
splay <- reactive({
req(input$file1)
df.raw <- read.csv(input$file1$datapath, header = input$header, sep = input$sep, quote = input$quote)
info <- list(df.raw=df.raw)
return(info)
})
output$contents <- renderTable({
if(input$disp == "head") { return(head(splay()$df.raw)) }
else { return(splay()$df.raw) }
})
observe({
varname <- renderText({input$frqvar})
})
output$jason <- renderTable({
if (is.null(input$file1)) { return() }
#table(splay()$df.raw$tx)
table(splay()$df.raw$varname())
})
output$caption1 <- renderText({
if (is.null(input$file1)) { return() }
paste("Listing of Uploaded Data and Frequency of ",input$frqvar ,"Variable")
})
} #this ends the server function
#ui=user interface portion
#place elements in the fluid page section to layout the page
ui <- fluidPage(
# App title
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions
sidebarLayout(
# Sidebar panel for inputs
sidebarPanel(
# Input: Select a file
fileInput("file1", "Choose CSV File", multiple = FALSE, accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")),
# Horizontal line
tags$hr(),
# Input: Checkbox if file has header
checkboxInput("header", "Header", TRUE),
# Input: Select separator
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
# Input: Select quotes
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"'),
# Horizontal line
tags$hr(),
# Input: Select number of rows to display
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head"),
textInput("frqvar",
label = h1("Variable to run Freq"),
value = " " ),
actionButton("action", label="Submit")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
textOutput("caption1"),
tableOutput("contents"),
tableOutput("jason")
#tableOutput("")
)
)
)
shinyApp(ui = ui, server=server)
Below is an example using one of R's built-in dataset, with a twist. Having users type in the name of the variable will lead to a lot of errors and thus a lot of work on your end to catch those errors. Ideally, after users have uploaded their dataset, you generate a dropdown menu of the variable names that can be selected.
Before explaining the above, you can access any input in your server function with input$id.
library(shiny)
ui <- fluidPage(
textInput("id", "label"),
verbatimTextOutput("out")
)
server <- function(input, output){
output$out <- renderPrint({
input$id
})
}
shinyApp(ui, server)
Now, for generating executing what you are after but with a selectInput (drop down menu).
library(shiny)
ui <- fluidPage(
selectInput("dataset", "select a dataset", choices = c("cars", "mtcars")),
uiOutput("dropdown"),
verbatimTextOutput("head"),
plotOutput("hist")
)
server <- function(input, output) {
data <- reactive({
if(input$dataset == "cars")
cars
else
mtcars
})
output$dropdown <- renderUI({
selectInput("variables", "Select a variable", names(data()))
})
output$head <- renderPrint({
head(data())
})
output$hist <- renderPlot({
hist(data()[[input$variables]])
})
}
shinyApp(ui, server)
Below is the code with small modifications of your serverfunction with dependency of submit button reactive environment.
server <- function(input, output, session) {
session$onSessionEnded(stopApp)
splay <- reactive({
req(input$file1)
df <- read.csv(input$file1$datapath, header = input$header, sep = input$sep, quote = input$quote)
info <- list(df = df)
return(info)
})
output$contents <- renderTable({
if (input$disp == "head") { return(head(splay()$df)) }
else {return(splay()$df) }
})
freq <- eventReactive(input$action,{
return(splay()$df[[input$frqvar]])
})
observeEvent(input$action,{
output$jason <- renderTable({
if (is.null(input$file1)) { return() }
else {table(freq()) }
})
})
output$caption1 <- renderText({
if (is.null(input$file1)) { return() }
paste("Listing of Uploaded Data and Frequency of ",input$frqvar ," Variable")
})
}
I was trying to simplify my shiny app. However, as much as I try it is not working, as I would like it to.
My Idea was to load data to the app, perform some analyses and return intermediate results to the user. At the moment I have to load the data, choose the right columns etc. for each output I am generating:
ui <- shinyServer(
fluidPage(
tabsetPanel(
tabPanel("Data upload",
titlePanel("Data upload"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",multiple = TRUE, accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE), radioButtons("sep", "Separator", choices = c(Comma = ",", Semicolon = ";",Tab = "\t"), selected = ","),
tags$hr(),
checkboxInput("disp", "Display",TRUE),
tags$hr(),
uiOutput("choose_first_column"),
uiOutput("choose_second_column"),
br()
),
mainPanel(
tableOutput("contents"),
tags$hr(),
tableOutput("tab")
)
)
),
tabPanel("2","2"
)
)
)
)
server <- shinyServer(
function(input, output) {
observe({
req(input$file1)
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
output$contents <- renderTable({
(head(df))})
output$choose_first_column <- renderUI({
colnames <- names(df)
selectInput("column_1", "Choose Date column",
choices = colnames,
selected = colnames)})
output$choose_second_column <- renderUI({
colnames <- names(df)
selectInput("column_2", "Choose Variable column",
choices = colnames,
selected = colnames)})
output$tab <- renderTable({
req(input$file1)
df2 <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
df2 <- df2[, c(input$column_1,input$column_2), drop = FALSE]
return(head(df2))})
})
})
runApp(list(ui = ui, server = server))
It works, but as I usually have many data and I want to perform a couple of analyses, it is gets quite time-consuming to load and process the data for each “output content”.
Is there a way to avoid this? Could I for example load the data and choose the right columns globaly, as in the second example? (I crossed out the lines where the error occurs)
ui <- shinyServer(
fluidPage(
tabsetPanel(
tabPanel("Data upload",
titlePanel("Data upload"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",multiple = TRUE, accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE), radioButtons("sep", "Separator", choices = c(Comma = ",", Semicolon = ";",Tab = "\t"), selected = ","),
tags$hr(),
checkboxInput("disp", "Display",TRUE),
tags$hr(),
uiOutput("choose_first_column"),
uiOutput("choose_second_column"),
br()
),
mainPanel(
tableOutput("contents"),
tags$hr(),
tableOutput("tab")
)
)
),
tabPanel("2","2"
)
)
)
)
server <- shinyServer(
function(input, output) {
observe({
req(input$file1)
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
output$contents <- renderTable({
(head(df))})
output$choose_first_column <- renderUI({
colnames <- names(df)
selectInput("column_1", "Choose Date column",
choices = colnames,
selected = colnames)})
output$choose_second_column <- renderUI({
colnames <- names(df)
selectInput("column_2", "Choose Variable column",
choices = colnames,
selected = colnames)})
# df <- df[, c(input$column_1,input$column_2), drop = FALSE]
#
# output$tab <- renderTable({
# (head(df))})
})
})
runApp(list(ui = ui, server = server))
Input data example:
date time level
01.01.2000 00:00:00 0.3724
01.01.2000 01:00:00 0.192
01.01.2000 02:00:00 -0.0252
I would appreciate any help!
Aishe
From what I've understood, you are getting an error because the dataframe df that you have defined is not reactive. You should make it reactive as it will change every time the user selects input columns.
Refer this to read about reactivity. Change the deleted portion of your code to this:
df.selected.columns <- df[c(input$column_1,input$column_2)]
output$tab <- renderTable({
(head(df.selected.columns()))
})
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).