Reactive function shiny+ggplot2 in shiny error - r

I am trying to create R Shiny app which can take in a dataset, choose from the input value, which item is to be plotted. I am facing issues when I am trying to filter the dataset based on the input value in the reactive function. I also get errors in ggplot function. I get "object of type 'closure' is not subsettable" and "ggplot doesnot know how to deal with a reactive function". I tried tmpdf with () and even without. Nothing seems to work.
Server.R
require(dplyr)
require(ggplot2)
shinyServer(function(input, output) {
#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)
})
#This function is repsonsible for loading the AS Item nos in the selected file
output$asitmno <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
itmchoices <- unique(df$ASItemNo)
selectInput("asitmno", "AS Item No:", choices = itmchoices)
})
#This function is triggered when the action button is pressed
getplot <- reactive({
if (input$getplot == 0) return(NULL)
df=filedata()
itm=input$asitmno
if (is.null(df)) return(NULL)
#This function filters the dataset for the given item
tmpdf <- reactive({
if (is.null(df)) return(NULL)
df$MonthDate<-as.Date(df$MonthDate, "%m/%d/%Y")
df<-df[input$ASItemNo %in% input$asitmno]
})
#This function plots the prices for the selected item
output$plot <- renderPlot({
p<-ggplot(tmpdf(), aes(y = stdcom, x = MonthDate, color = "Commodity Price")) + geom_line() +geom_line(data = tmpdf, aes(y = stitm, x = MonthDate, color = "Item Price",text = paste("R2 value:",round(cor0*100,2),"%"))) + ylab('Price') + xlab('MonthDate')+ggtitle("Plot of Item Price vs Commodity Price")
print(p)
})
})
ui.R
shinyUI(pageWithSidebar(
headerPanel("Commodity Price Vs item Price Plots"),
sidebarPanel(
#Selector for file upload
fileInput('datafile', 'Choose CSV file',
accept=c('text/csv', 'text/comma-separated-values,text/plain')),
#These column selectors are dynamically created when the file is loaded
uiOutput("asitmno"),
#The action button prevents an action firing before we're ready
actionButton("getplot", "Get Plot")
),
mainPanel(
plotOutput("plot")
)
))

Related

Shiny: calculating standard deviation from an uploaded excel file

I am trying to calculate the standard deviation of an Excel file loaded onto my Shiny App. I don't appear to be able to do so. When I put sd(output$contents) or sd(file1) it tends to crash the application. Here is what I have so far
For reference, the data I am uploading is univariate time series
I would be very grateful if someone would be able to help me out- I think it is a beginner problem! perhaps I am just viewing the file and not using it?
EDIT: the excel file always contains a single column of numbers, but the title and header may change. Therefore I would like to reference column A in the changing excel files.
ui <- fluidPage(
setBackgroundColor("ghostwhite"),
titlePanel(h1("title", style = "color:navy")),
p("subtitle"),
headerPanel(h3("Input data here", style = "color:navy")),
# Sidebar panel
sidebarLayout(
sidebarPanel( position =c("left"),
sliderInput("SL",
"ServiceScore",
min = 1.28, max = 3.09, value = 2.28),
numericInput("LT", "LT: weeks",0, min=0, max = 30),
fileInput('file1', 'MS, choose xlsx file',
accept = c(".xlsx")
),
br(),
actionButton("action_Calc", label = "Refresh & Calculate"), ),
# Main panel
mainPanel(h3( textOutput("SL"),
textOutput("LT"),
textOutput("SS"),
tableOutput('contents')
))))
server <- function(input, output) {
output$SL <- renderText({
paste("Your score", input$SL)})
output$LT <- renderText ({
paste( "Your LT is", input$LT)})
output$contents <- renderTable({
req(input$file1)
inFile <- input$file1
read_excel(inFile$datapath, 1)
})
values<- reactiveValues()
observe({
input$action_Calc
values$int<- isolate({
input$SL*sqrt(input$LT/4)*sd(**HERE IS WHERE I NEED THE SD of the EXCEL FILE**)
})})
output$SS <- renderText({paste("calculation is", values$int)})
}
shinyApp(ui, server)
Read the Excel file in a reactive conductor:
Data <- reactive({
req(input$file1)
inFile <- input$file1
read_excel(inFile$datapath, 1)
})
output$contents <- renderTable({
Data()
})
Now if you want the standard deviation of the first column:
values<- reactiveValues()
observe({
input$action_Calc
values$int <- isolate({
input$SL*sqrt(input$LT/4)*sd(Data()[[1]])
})
})
output$SS <- renderText({paste("calculation is", values$int)})

modularize Shiny app: CSV and Chart modules

I want to create a modularized Shiny app where one module, dataUpload, is used to import a CSV and another module, chart, is used to
Create dynamic x and y dropdowns based on the column names within the CSV THIS WORKS
Create a plot based on the selected input$xaxis, input$yaxis This produces the error invalid type/length (symbol/0) in vector allocation
I think the issue is with my reactive ggplot in chart.R and I'd love any help - I added all the info here but I also have a github repo if that's easier I think this could be a really great demo into the world of interacting modules so I'd really appreciate any help!!
App.R
library(shiny)
library(shinyjs)
library(tidyverse)
source("global.R")
ui <-
tagList(
navbarPage(
"TWO MODULES",
tabPanel(
title = "Data",
dataUploadUI("datafile", "Import CSV")
),
tabPanel(
title = "Charts",
chartUI("my_chart")
)
)
)
server <- function(input, output, session) {
datafile <- callModule(dataUpload, "datafile", stringsAsFactors = FALSE)
output$table <- renderTable({ datafile() })
# PASS datafile WITHOUT () INTO THE MODULE
my_chart <- callModule(chart, "my_chart", datafile = datafile)
output$plot <- renderPlot({ my_chart() })
}
shinyApp(ui, server)
dataUpload.R
dataUpload <- function(input, output, session, stringsAsFactors) {
# The selected file, if any
userFile <- reactive({
# If no file is selected, don't do anything
# input$file == ns("file")
validate(need(input$file, message = FALSE))
input$file
})
# The user's data, parsed into a data frame
dataframe <- reactive({
read.csv(userFile()$datapath,
stringsAsFactors = stringsAsFactors)
})
# We can run observers in here if we want to
observe({
msg <- sprintf("File %s was uploaded", userFile()$name)
cat(msg, "\n")
})
# Return the reactive that yields the data frame
return(dataframe)
}
dataUploadUI.R
# The first argument is the id -- the namespace for the module
dataUploadUI <- function(id, label = "CSV file") {
# Create a namespace function using the provided id
#ALL UI FUNCTION BODIES MUST BEGIN WITH THIS
ns <- NS(id)
# Rather than fluidPage use a taglist
# If you're just returning a div you can skip the taglist
tagList(
sidebarPanel(
fileInput(ns("file"), label)),
mainPanel(tableOutput("table"))
)
}
chart.R
I believe this is the file that needs some minor changing in order to have the plot properly render?
chart <- function(input, output, session, datafile = reactive(NULL)) {
# SINCE DATAFILE IS A REACTIVE WE ADD THE PRERENTHESIS HERE
# WHERE/HOW CAN I ACCESS input$xaxis?
# Do I need to use ns? Can you do that in the server side of a module?
output$XAXIS <- renderUI(selectInput("xaxis", "X Axis", choices = colnames(datafile())))
output$YAXIS <- renderUI(selectInput("yaxis", "Y Axis", choices = colnames(datafile())))
# NOT WORKING
# Use the selectInput x and y to plot
p <- reactive({
req(datafile)
# WORKS: ggplot(datafile(), aes(x = Sepal_Length, y = Sepal_Width))
# DOES NOT WORK:
ggplot(datafile(), aes_(x = as.name(input$xaxis), y = as.name(input$yaxis))) +
geom_point()
})
return(p)
}
chartUI.R
chartUI <- function(id, label = "Create Chart") {
ns <- NS(id)
tagList(
sidebarPanel(
uiOutput(ns("XAXIS")),
uiOutput(ns("YAXIS"))
),
mainPanel(plotOutput("plot"))
)
}
We need to manually specify the name space within a renderUI function using session$ns
chart <- function(input, output, session, datafile = reactive(NULL)) {
# SINCE DATAFILE IS A REACTIVE WE ADD THE PRERENTHESIS HERE
# WHERE/HOW CAN I ACCESS input$xaxis?
# Do I need to use ns? Can you do that in the server side of a module?
output$XAXIS <- renderUI(selectInput(session$ns("xaxis"), "X Axis", choices = colnames(datafile())))
output$YAXIS <- renderUI(selectInput(session$ns("yaxis"), "Y Axis", choices = colnames(datafile())))
# NOT WORKING
# Use the selectInput x and y to plot
p <- reactive({
req(datafile)
# WORKS: ggplot(datafile(), aes(x = Sepal_Length, y = Sepal_Width))
# DOES NOT WORK:
ggplot(datafile(), aes_(x = as.name(input$xaxis), y = as.name(input$yaxis))) +
geom_point()
})
return(p)
}

Why is R Shiny throwing this error when plotting data (ggplot2) returned from a reactive() function?

I'm working on a Shiny app that takes input data (csv) from a user, and plots various representations of correlation in the dataset. My scatter plot renders when the user uploads a file, but flashes an error message Error: no expression to parse first. It seems that my ggplot function is being called before the data being returned from the reactive() function is finished uploading, so the input is undefined. Is this because it is executing asynchronously?
I tried adding conditionals to check if the reactive function getData() is null before executing the plot, but the error still flashes before successfully rendering the plot.
ui.R
library(shiny)
fluidPage(
titlePanel("Correlation Analyzer"),
sidebarLayout(
sidebarPanel(
fileInput("file", "Choose Clean CSV File to Analyze (must include headers)",
accept = c("text/csv","text/comma-separated-values,text/plain",".csv")
),
uiOutput("xvars"), # dropdowns for selecting variable names
uiOutput("yvars"),
checkboxGroupInput(inputId='corrType', label="Correlation Type",
choices=c('Continuous - Continuous (Pearson)', "Categorical - Categorical (Kramer's V)",
'Continuous - Categorical (Correlation Ratio)'),
selected = NULL, inline = FALSE, width = NULL)
),
mainPanel(
if (is.null(tableOutput("dataHead")) == FALSE) {
plotOutput("scatter")
}
)
)
)
server.R
library(shiny)
library(ggplot2)
function(input, output) {
getData = reactive({
inFile = input$file
if (is.null(inFile)) {
return(NULL)
}
df = read.csv(inFile$datapath, header = TRUE)
return(df)
})
output$dataHead = renderTable({
return(head(getData()))
})
output$xvars =
renderUI({ # send list of available variable name choices to UI
selectInput(inputId='selected_xvar', label="Select X Variable", choices=colnames(getData()), selected=input$selected_xvar)
})
output$yvars =
renderUI({
selectInput(inputId='selected_yvar', label="Select Y Variable", choices=colnames(getData()), selected=input$selected_yvar)
})
output$scatter = renderPlot({
selected_xvar = input$selected_xvar
selected_yvar = input$selected_yvar
df = getData()
if (is.null(df)==FALSE) {
ggplot(df, aes_string(x=selected_xvar, y=selected_yvar)) +
geom_point(shape=1, col="blue") +
geom_smooth(method=lm) + ggtitle("Scatterplot") + xlab(selected_xvar) + ylab(selected_yvar) +
theme(plot.title = element_text(size=18, hjust=0.5))
# plot(unlist(df[selected_xvar]), unlist(df[selected_yvar]), main="Scatterplot",
# xlab=selected_xvar, ylab=selected_yvar, pch=19)
}
})
}
I also tried using the base plot() function, and get an error message Error: undefined columns selected before the plot renders.
You can use req() function to stop the process and wait until the variables become available.
if (is.null(df)==FALSE) {
req(selected_xvar, selected_yvar)
ggplot(df, aes_string(x=selected_xvar, y=selected_yvar)) + # omitted below
See: https://shiny.rstudio.com/reference/shiny/latest/req.html

Shiny allow users to choose which plot outputs to display

I have a shiny app and my server function looks like this:
shinyServer(function(input, output, session) {
filedata <- reactive({
infile <- input$file1
if (is.null(infile)) {
return(NULL)
}
myDF <- fread(infile$datapath)
return(myDF)
# Return the requested graph
graphInput <- reactive({
switch(input$graph,
"Plot1" = plot1,
"Plot2" = plot2)
})
output$selected_graph <- renderPlot({
paste(input$graph)
})
output$plot1 <- renderPlot({
#fill in code to create a plot1
})
output$plot2 <- renderPlot({
#fill in code to create plot2
})
The UI function looks like this:
shinyUI(pageWithSidebar(
headerPanel("CSV Viewer"),
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv', 'text/comma-separated-values,text/plain', '.csv')),
selectInput("graph", "Choose a graph to view:",
choices = c("Plot1", "Plot2"))
submitButton("Update View")
),#end of sidebar panel
mainPanel(
tabsetPanel(
tabPanel("Graph Viewer", plotOutput("selected_graph"))
)
I can't make the selected plot display on the screen. When I make a selection from the drop-down menu and click the "Update View" button the app does not display the plot. It does not display an error message. It displays nothing at all.
How can I fix this?
As mentioned in the comments, it's difficult to ensure that any answer will work, given the incomplete example in your question. Based on the skeleton server provided, however, this pattern for selecting a graph should work:
shinyServer(function(input, output, session) {
filedata <- reactive({
# Haven't tested that this will read in data correctly;
# assuming it does
infile <- input$file1
if (is.null(infile)) {
return(NULL)
}
myDF <- fread(infile$datapath)
return(myDF)
})
plot1 <- reactive({
# this should be a complete plot image,
# e.g. ggplot(data, aes(x=x, y=y)) + geom_line()
})
plot2 <- reactive({
# this should be a complete plot image,
# e.g. ggplot(data, aes(x=x, y=y)) + geom_line()
})
# Return the requested graph
graphInput <- reactive({
switch(input$graph,
"Plot1" = plot1(),
"Plot2" = plot2()
)
})
output$selected_graph <- renderPlot({
graphInput()
})
}
What changed:
plot1 and plot2 are reactive functions (and not outputs) that can be returned from the graphInput reactive function
graphInput returns the value (i.e. plot) of either plot1 or plot2 into output$selected_graph

Shiny and ggplot - error when using both scale_x_ and scale_y_continuous

Background: This is an odd one. Essentially, am working on a shiny app where people can pull a csv export off a particular website, upload it and then interactive with it. Because the numbers are large (millions) it defaults to scientific notation, which isn't easy on the eye, so I'm trying to use "labels = comma" to correct this.
Issue: When I have both scale_x_cont and scale_y_cont in the ggplot function, the app crashes. When I have just x or just y in there, it runs fine.
Now I tried to write the smallest reproducible piece of code I could, but when I made a simple one using mtcars and the same selectInput method, it ran fine, with no errors with both scale_x_cont and scale_y_cont in place...
Error
Error in eval(substitute(expr), envir, enclos) :
geom_point requires the following missing aesthetics: x, y
Error: geom_point requires the following missing aesthetics: x, y
Minimal CSV to replicate with
https://raw.githubusercontent.com/nzcoops/datasets/master/dump_test
App
require(shiny)
require(DT)
require(ggplot2)
require(scales)
runApp(
list(
ui = fluidPage(
sidebarPanel(fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
htmlOutput("contents2"),
htmlOutput("contents3")
),
mainPanel(
plotOutput("plot1"),
dataTableOutput("contents4")
)
),
server = function(input, output, session) {
contents1 <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
dat <<- read.csv(inFile$datapath)
dat[,2:5] <<- lapply(dat[,2:5],function(x){as.numeric(gsub(",", "", x))})
names(dat)
})
output$contents2 <- renderUI({
if (is.null(input$file1))
return(NULL)
selectInput('columnsx', 'Columns X', contents1()[3:5])
})
output$contents3 <- renderUI({
if (is.null(input$file1))
return(NULL)
selectInput('columnsy', 'Columns Y', contents1()[3:5])
})
output$contents4 <- renderDataTable({
if (is.null(input$file1))
return(NULL)
dat
}, options = list(paging = FALSE, searching = FALSE))
output$plot1 <- renderPlot({
if (is.null(input$file1))
return(NULL)
p <- ggplot(dat, aes_string(x=input$columnsx, y=input$columnsy)) +
geom_point() +
scale_x_continuous(labels = comma) #+ scale_y_continuous(labels = comma)
# Remove the above hash and the presence of scale_y_ will crash app
print(p)
})
}
))
You have some funky scoping stuff going on in the function. If you replace the first line of your function with this:
p <- ggplot(dat, aes_string(x=dat[input$columnsx], y=dat[input$columnsy]))
It will plot out ok.

Resources