Shiny no longer accepts reactive function for xreg value - r

I have been working on a shiny app which uses auto.arima() from the package, along with an xreg parameter. For some reason, the xreg function (which takes a data frame or matrix) has stopped accepting the output of a reactive function - which is a subsetted dataframe. The work-around sucks, and so I'm hoping someone knows a good way to fix this.
Shiny produces this ERROR:
xreg should be a numeric matrix or vector
I've tried:
re-installing: forecast, shiny, dplyr, and completing wiping our R and Rstudio, and re-installing from scratch.
I've tried rolling back the forecast package to the build from 6 months ago (when this was working)
I've tried rolling back R to the build from 6 months ago (when this was working)
I've tried using other forecast packages; bsts for example seems to work just fine
This is some minimally viable shiny code. Create a .csv with 3 columns of data, be sure to name the columns, like y, x1 and x2.
library(shiny)
library(forecast)
library(dplyr)
ui <- fluidPage(
# Application title
titlePanel("arima test"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
# Input: Select a file ----
fileInput("uploaded_file", "Choose CSV File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
uiOutput("dv_dropdown"),
uiOutput("iv_checkbox")
),
# Show a plot of the generated distribution
mainPanel(
verbatimTextOutput("model"),
tableOutput('data')
)
)
)
server <- function(input, output) {
# Read .csv file ----
df <- reactive({
req(input$uploaded_file)
read.csv(input$uploaded_file$datapath,
header = TRUE)
})
# Dynamically generate a list of the dependent variables for the user to choose from the uploaded .csv ----
output$dv_dropdown <- renderUI({
selectInput(inputId = "select_dependents",
label = "dependent time series:",
choices = names(df()[,c(-1)])
)
})
# Dynamically generate a list of the independent variables for the user to choose ----
output$iv_checkbox <- renderUI({
checkboxGroupInput(inputId = "select_ivs",
label = "Select Independent variables:",
choices = setdiff(names(df()[,c(-1)]), input$select_dependents),
selected = setdiff(names(df()), input$select_dependents))
})
####### CREATE REACTIVE DATA OBJECTS BASED ON FILTERS #################
# this creates a dataframe of the dependent time series
df_sel <- reactive({
req(input$select_dependents)
df_sel <- df() %>% select(input$select_dependents)
})
# this creates a dataframe of the dependent time series
df_indep <- reactive({
req(input$select_ivs)
df_indep <- df() %>% select(input$select_ivs)
})
#proof that the independent variables are in fact in a matrix/dataframe
output$data <- renderTable({
df_indep()
})
#This is the TEST ARIMA Model
modela <- reactive({
modela <- auto.arima(df_sel(), xreg = df_indep()) #model with regressors
#modela <- auto.arima(df_sel()) #model without regressors to demonstrate that it actually works without the xreg argument
})
#this is the solution to the xreg problem above, but there's no reason I can think of that xreg shouldn't be able to take a reactive data object like it was doing before...
#x = as.matrix(as.data.frame(lapply(df_indep(), as.numeric)))
# then set: xreg = x
output$model <- renderPrint({
summary(modela())
})
}
# Run the application
shinyApp(ui = ui, server = server)

Related

how to fix 'Error: variable lengths differ (found for 'input$s')' in R Shiny

I'm trying to make a simple shiny ap for creating kaplan-meier survival curves that are stratified by selection the user makes. When I code the KM calculation statically (with the column name thorTr) it works but the calculation and plot is static. When I replace with input$s I get ERROR:variable lengths differ (found for 'input$s')
I've tried looking at other code which use as.formula and paste, but I don't understand and couldn't get to work. But I am a new R and Shiny user so maybe I didn't get it right. Here is a similar shiny ap but I want to use survminer and the ggsurvplot for plotting
library(shiny)
library(ggplot2)
library(survival)
library(survminer)
#load data
data(GBSG2, package = "TH.data")
#Define UI for application that plots stratified km curves
ui <- fluidPage(
# Sidebar layout with a input and output definitions
sidebarLayout(
# Inputs
sidebarPanel(
# Select variable strat
selectInput(inputId = "s",
label = "Select Stratification Variable:",
choices = c("horTh","menostat","tgrade"),
selected = "horTh")
),
# Outputs
mainPanel(
plotOutput(outputId = "km")
)
)
)
# Define server function required to create the km plot
server <- function(input, output) {
# Create the km plot object the plotOutput function is expecting
output$km <- renderPlot({
#calc KM estimate with a hard coded variables - the following line works but obviously is not reactive
#km <- survfit(Surv(time,cens) ~ horTh,data=GBSG2)
#replaced hard coded horTh selection with the respnse from the selection and I get an error
km <- survfit(Surv(time,cens) ~ input$s ,data=GBSG2)
#plot km
ggsurvplot(km)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)
I expect to have a plot that updates the stratification variable with the users selection
Try using surv_fit() instead of survfit().
surv_fit() is a helper from survminer which does different scoping compared to survival:survit(), which is what you seem to need, as Byron suggests.
My snippet looks like:
output$plot <- renderPlot({
formula_text <- paste0("Surv(OS, OS_CENSOR) ~ ", input$covariate)
## for ggsurvplot, use survminer::surv_fit instead of survival:survfit
fit <- surv_fit(as.formula(formula_text), data=os_df)
ggsurvplot(fit = fit, data=os_df)
})
Two things:
The formula in the call to survfit() needs to be defined explicitly. The object being passed to survfit() in the original code uses a character value on the right hand side of the function. This throws an error, which we can address by translating the entire pasted value into a formula, i.e., as.formula(paste('Surv(time,cens) ~',input$s))
The formula needs to be defined in the call to ggsurvplot() to avoid scoping issues. This is a little more technical and has to do with the way that ggsurvplot() is programmed. Basically, ggsurvplot() can't access a formula that is defined outside of its own call.
Try replacing
km <- survfit(Surv(time,cens) ~ input$s ,data=GBSG2)
ggsurvplot(km)
with
ggsurvplot(survfit(as.formula(paste('Surv(time,cens) ~',input$s)),data=GBSG2))
Hi finally got this to work combinigng both solutions. I don't understand the fix but at least it now works the way I wanted it to :)
library(shiny)
library(ggplot2)
library(survival)
library(survminer)
data(GBSG2, package = "TH.data")
# Define UI for application that plots features of movies
ui <- fluidPage(
# Sidebar layout with a input and output definitions
sidebarLayout(
# Inputs
sidebarPanel(
# Select variable strat
selectInput(inputId = "s",
label = "Select Stratification Variable:",
choices = c("Hormone Therapy" = "horTh",
"Menopausal Status" = "menostat",
"Tumor Grade" = "tgrade"),
selected = "horTh")
),
# Outputs
mainPanel(
plotOutput(outputId = "km")
)
)
)
# Define server function required to create the scatterplot
server <- function(input, output) {
# Create the km plot object the plotOutput function is expecting
output$km <- renderPlot({
## calc survival curve and plot
kmdata <- surv_fit(as.formula(paste('Surv(time,cens) ~',input$s)),data=GBSG2)
ggsurvplot(kmdata)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)

Executing code on data set filtered using drop down menu in Shiny/R

I am trying to create a shiny app to accomplish the following -
Select an ID from the drop down menu (Eg: 106841)
Filter the original data set of about 150K observations and obtain a smaller data set of about 600 values using the primary key
Perform additional manipulation and run regression on this data set
Present ggplot graph and text summary of the regression
Allow same process to be applied to different IDs based on user input
Sample structure of code to give you an idea of how i am trying to meet these requirements -
Server.R:
#Excerpt of server code
branch_data <- openxlsx::read.xlsx("Branch_Final.xlsx")
<Other data input and cleaning code>
branch_data_final <- data.table(branch_data)
shinyServer(function(input, output) {
#Filtering data set using ID (input$select_ID is the variable)
data_branch_analysis<-(data_branch_analysis[ID==input$select_ID])[order(DATE)]
#Data manipulation for regression
data_branch_analysis[,NDATE:=as.Date(DATE,"%Y.%m.%d")]
data_branch_analysis[,L_AVG_AGE:=shift(AVG_AGE,1)]
data_branch_analysis[,L_AVG_WAGE:=as.numeric(shift(AVG_WAGE,1))]
<Other lines of code for manipulation>
#Regression
fit1<-lm(data=data_branch_analysis,VISITOR_NUM~0+time+WD+L_W3_7+L_W7_14+L_W14_21+...)
bestm<-step(fit1)
fit2<-auto.arima(data_branch_analysis_train$VISITOR_NUM,max.order=30,xreg=as.matrix(x_reg))
<Other lines of code for regression)
#GGPLOT
output$final_forecast_branch <- renderPlot({
g <-
ggplot()+geom_line(aes(x=data_branch_analysis$NDATE,y=data_branch_analysis$VISITOR_NUM,col="original"))+
geom_line(aes(x=data_branch_analysis$NDATE[2:(ntrain+1)],y=fit2$fitted,col="train"))+
geom_line(aes(x=data_branch_analysis$NDATE[(ntrain+2):nrow(data_branch_analysis)],y=fore2$mean,col="test"))
g
})
output$final_forecast_branch_analysis_accuracy <- renderText(expr = accuracy(fore2,x=data_branch_analysis_$VISITOR_NUM[(ntrain+2):nrow(data_branch_analysis)])
}
UI.R
#Excerpt of UI code
navbarMenu("Analyzer Widget",
tabPanel(
"Branch",
sidebarLayout(
fluid = 'TRUE',
sidebarPanel(
# p("Please enter the following information - "),
selectInput(
inputId = "select_ID",
'Select Branch ID',
selected = "106841",
sort(unique(data_branch_analysis$ID))
)
),
mainPanel(tabsetPanel(
tabPanel(
'Training Data',
plotOutput('final_forecast_branch'),
p("Accuracy of Model"),
textOutput("final_forecast_branch_analysis_accuracy"),
...
Currently, i see no output from the ggplot or textOutput blocks. I've tried reactive and observe but obviously i am unable to implement in properly. Would appreciate your thoughts on how to structure the code for this to work.
Thanks for your inputs.
Hi you ewant to make a chain of reactive expressions someting like my example below.
shinyServer(function(input, output) {
filterDta <- reactive({
#Filtering data set using ID (input$select_ID is the variable)
data_branch_analysis<-(data_branch_analysis[ID==input$select_ID])[order(DATE)]
})
minpulateDta <- reactive({
data_branch_analysis <- filterDta()
#Data manipulation for regression
data_branch_analysis[,NDATE:=as.Date(DATE,"%Y.%m.%d")]
data_branch_analysis[,L_AVG_AGE:=shift(AVG_AGE,1)]
data_branch_analysis[,L_AVG_WAGE:=as.numeric(shift(AVG_WAGE,1))]
<Other lines of code for manipulation>
})
calcRegression <- reactive({
#Regression
data_branch_analysis <- minpulateDta()
fit1<-lm(data=data_branch_analysis,VISITOR_NUM~0+time+WD+L_W3_7+L_W7_14+L_W14_21+...)
bestm<-step(fit1)
fit2<-auto.arima(data_branch_analysis_train$VISITOR_NUM,max.order=30,xreg=as.matrix(x_reg))
<Other lines of code for regression)
})
#GGPLOT
output$final_forecast_branch <- renderPlot({
data_branch_analysis <- calcRegression()
g <-
ggplot()+geom_line(aes(x=data_branch_analysis$NDATE,y=data_branch_analysis$VISITOR_NUM,col="original"))+
geom_line(aes(x=data_branch_analysis$NDATE[2:(ntrain+1)],y=fit2$fitted,col="train"))+
geom_line(aes(x=data_branch_analysis$NDATE[(ntrain+2):nrow(data_branch_analysis)],y=fore2$mean,col="test"))
g
})
output$final_forecast_branch_analysis_accuracy <- renderText(expr = accuracy(fore2,x=data_branch_analysis_$VISITOR_NUM[(ntrain+2):nrow(data_branch_analysis)])
}
In this case of course you don't really need to seperate minpulateDta and calcRegression but it makes the code more readable when you separete the different steps. If you want to reuse the results some where else it is also easier in this way.
Hope this helps!

R Shiny: keep old output

In a Shiny app, is there a way to keep old reactive output and display it in the app along with new reactive output? To provide an example: say I want to display the summary table of a linear model to which I gradually add more variables. I currently have a checkboxGroupInput panel using which I select the explanatory variables to be included in the model, and then I render a table which contains the summary of the model estimated using the selected variables. Now when I decide to use a different set of variables, I'd like to keep the original summary table displayed but also add the new summary table below the old one. If possible, I'd like to display all past instances of the reactive table, i.e., the number of tables displayed in the app should be equal to the number of different sets of explanatory variables I have decided to use throughout the app. At the moment, the table is rendered with htmlOutput in the ui part and stargazer package and renderText in the server part.
Here's an approach that works. It uses a reactiveValues object, and each time you click the "Fit Model" button, it appends the new model to the end of the list. The numeric input controls how many models to display on the screen. This preserves every model you fit in the session.
I didn't do the stargazer table because I'm not that familiar with it. But you should be able to adapt this pretty easily.
library(shiny)
library(broom)
shinyApp(
ui =
shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel(
checkboxGroupInput(inputId = "indep",
label = "Independent Variables",
choices = names(mtcars)[-1],
selected = NULL),
actionButton(inputId = "fit_model",
label = "Fit Model"),
numericInput(inputId = "model_to_show",
label = "Show N most recent models",
value = 2)
),
mainPanel(
htmlOutput("model_record")
)
)
)
),
server =
shinyServer(function(input, output, session){
Model <- reactiveValues(
Record = list()
)
observeEvent(
input[["fit_model"]],
{
fit <-
lm(mpg ~ .,
data = mtcars[c("mpg", input[["indep"]])])
Model$Record <- c(Model$Record, list(fit))
}
)
output$model_record <-
renderText({
tail(Model$Record, input[["model_to_show"]]) %>%
lapply(tidy) %>%
lapply(knitr::kable,
format = "html") %>%
lapply(as.character) %>%
unlist() %>%
paste0(collapse = "<br/><br/>")
})
})
)

Showing Model Predictions with Shiny in R

I'd be happy to get some help with R shiny, I'm new to it.
I built a logistic regression model that runs on a training set called "Rdata1.csv".
Then after I train the model I want let the user upload a test set file
and run the predictions on the test set.
Here is my ui.R:
library(shiny)
shinyUI(fluidPage(
titlePanel("Predictions"),
sidebarLayout(
sidebarPanel(
fileInput("file", label = h3("Upload CSV")),
hr(),
fluidRow(column(4, verbatimTextOutput("value")))
),
mainPanel(
textOutput("text1")
)
)
))
Here is my server.R:
library(shiny)
library(aod)
library(ROCR)
mydata <- read.csv("C:/Rdata1.csv")
mydata$Continent <- factor(mydata$Continent)
mydata$IP <- factor(mydata$IP)
mylogit <- glm(Good ~ Continent + IP, data = mydata, family = "binomial")
shinyServer(function(input, output) {
output$text1 <- renderPrint({
mydatanew <- read.csv(input$file[4])
mydatanew$Continent <- factor(mydatanew$Continent)
mydatanew$IP <- factor(mydatanew$IP)
mydatanew$predicted<-predict(mylogit, newdata=mydatanew, type="response")
paste("predictions", mydatanew)
})
}
)
In the app I get no output - instead it I get the error:
"file must be a character string or connection" and i see nothing.
Anyone know what's wrong with the code?
Thanks!
Welcome to SO. This question is hard to make reproducible, but it looks like the datapath from fileInput is not being passed correctly. See ?fileInput:
Whenever a file upload completes, the corresponding input variable is set to a dataframe.
This dataframe contains one row for each selected file, and the following columns: ...
... the fourth of which is datapath.
In other words
file <- data.frame(name="foo",size=999,type="text/plain",datapath = "~/temp/whatever.csv", stringsAsFactors=FALSE)
str(file[4]) # this gives you a little data frame, probably not what you want
str(file[1,4]) # this gives you the character value itself
Does that work?

How to Order ggplot2 x-axis dates chronologically when in mm-yyyy format?

I'm designing an R program to output different graphs of any csv file input. I am using Rstudio Shiny and ggplot2 to develop the program.
My problem involves ordering dates chronologically rather than alphabetically (which is the default apparently). Let's use this code as an example (my code is a bit different, but this is code from someone who helped me earlier):
related posts:
Unable to change the graph form of my ggplot rshiny program, help me find the bug?
Sorting months in R
How do you order a nominale variable. e.g month in R?
Boxplot with ggplot2 in R - returns by month
server.R
library(shiny)
library(datasets)
library(ggplot2)
X <- read.csv(file.choose())
# Define server logic required to summarize and view the selected dataset
shinyServer(function(input, output) {
output$opt.x <- renderUI({
selectInput("xcolumn", "X column to Plot",
names(Y())
)
})
output$opt.y <- renderUI({
selectInput("ycolumn", "Y Column",
names(Y()))
})
# Generate a summary of the dataset
output$summary <- renderPrint({
dataset <- X
summary(dataset)
})
# Show the first "n" observations
output$view <- renderTable({
head(X, n = input$obs)
})
createPlot <- function(df, colx, coly) {
p <- ggplot(data=df, aes(x=df[,colx],y=df[,coly]), environment = environment()) #+ geom_line(aes(x=df[,colx],y=df[,coly], group=colx))
p <- p + geom_line(aes(group=colx))
p <- p + xlab(names(df)[colx]) + ylab(names(df)[coly])
}
Y <- reactive({
X
})
# create a basic plot
output$plotBasic <- reactivePlot(function() {
df <- Y()
print(createPlot(df, colx=input$xcolumn, coly=input$ycolumn))
})
})
ui.R
library(shiny)
# Define UI for dataset viewer application
shinyUI(pageWithSidebar(
# Application title
headerPanel("My app!"),
# Sidebar with controls to select a dataset and specify the number
# of observations to view
sidebarPanel(
numericInput("obs", "Number of observations to view:", 13),
uiOutput("opt.x"), #dynamic UI
uiOutput("opt.y") #value comes from Server.R
),
# Show a summary of the dataset and an HTML table with the requested
# number of observations
mainPanel(
tabsetPanel(
tabPanel("Table", tableOutput("view")),
tabPanel("BasicGraph", plotOutput("plotBasic"))
)
)
))
This can be taken care of easily with factor or as.Date functions if you started with a list that you knew of, but here I am taking in input (can assume the format is mm-yyyy) and I do not know how to set the column of x variable data to a variable. This is because the user can choose any column in the imported data as the X column.

Resources