Data manipulation on a reactive event - shiny

I am creating a data frame, that is dynamically created when the user inputs a search term, in order to do this i have an action button, and the data frame is created when the "go" button is pressed.
Once this is done i need to perform various data manipulations on the DF, and out put different graphs.
i am struggling to understand how i do the data manipulation in Shiny, i have some simplified example code below:
library(shiny)
library(sp)
library(stringr)
library(tidyr)
library(tidyverse)
library(tm)
library(ggplot2)
library(stringi)
library(plyr)
library(dplyr)
ui <- fluidPage(
fluidRow(
column( 4, titlePanel("Twitter Analytics")),
column( 3),
column( 4,
textInput("searchstring",
label = "",
value = "")),
column(1,
br(),
actionButton("action", "go"))
),
fluidRow(
column( 12, tabsetPanel(
tabPanel("one",
fluidRow(
column(3 ),
column(9, plotOutput("ttext"))
)
),
tabPanel("two"),
tabPanel("three")
)
)
)
)
server <- function(input, output) {
tweet <- eventReactive(input$action,{
num <- c(1,2,3,4,50)
text <- c("this is love love something", "this is not hate hate hate something", "#something islove rethched this not", " Shiny is love confusing me", "this is hate also somthing difficult")
letter<- c("a", "b", "c", "D", "e")
tweetdf <- data.frame(num, text, letter)
})
tdm <- if( is.null(tweetdf) ){return()}
else{
tweetdf$text <- tolower(tweetdf$text)
# tweetdf #UserName
tweetdf$text <- gsub("#\\w+", "", tweetdf$text)
#remove punctuation
tweetdf$text <- gsub("[[:punct:]]", "", tweetdf$text)
#remove links
tweetdf$text <- gsub("http\\w+", "", tweetdf$text)
# Remove tabs
tweetdf$text <- gsub("[ |\t]{2,}", "", tweetdf$text)
# Remove blank spaces at the beginning
tweetdf$text <- gsub("^ ", "", tweetdf$text)
# Remove blank spaces at the end
corpus <- iconv(tweetdf$text, to = "ASCII")
corpus <- Corpus(VectorSource(corpus))
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeNumbers)
cleanset <- tm_map(corpus, removeWords, stopwords('english'))
tdm <- TermDocumentMatrix(cleanset)
tdm <- as.matrix(tdm)
w <- rowSums(tdm)
}
output$ttext <- renderPlot({
library(RColorBrewer)
barplot(w)
})
output$wordCl <- renderPlot({
library(wordcloud2)
w <- data.frame(names(w), w)
colnames(w) <- c('word', 'freq')
wordcloud2(w,
color = 'random-dark',
size = 0.7,
shape = 'circle',
rotateRatio = 0.5,
minSize = 1)
})
}
shinyApp(ui, server)
i keep getting the error message that tweetdf does not exist, This should not exist, until the user has entered a search term and clicked "go"
What is the best way to approach this problem, is this even the right spot to do this

It tells you that tweetdf doest not exist because the result of eventReactive (tweetdf) is assign to the variable tweet, which makes tweet your actual reactive variable with the result of tweetdf in.
Also the problem in your code is that you mix classic variables with reactive variables.
You can access reactive variables by adding parenthesis at the end of the variable()
Here is a working example:
library(shiny)
library(sp)
library(stringr)
library(tidyr)
library(tidyverse)
library(tm)
library(ggplot2)
library(stringi)
library(plyr)
library(dplyr)
library(RColorBrewer)
library(wordcloud2)
ui <- fluidPage(
fluidRow(
column( 4, titlePanel("Twitter Analytics")),
column( 3),
column( 4,
textInput("searchstring",
label = "",
value = "")),
column(1,
br(),
actionButton("action", "go"))
),
fluidRow(
column( 12, tabsetPanel(
tabPanel("one",
fluidRow(
column(3 ),
column(9, plotOutput("ttext"))
)
# ,fluidRow(wordcloud2Output("wordCl"))
),
tabPanel("two"),
tabPanel("three")
)
)
)
)
server <- function(input, output) {
w <- eventReactive(input$action,{
num <- c(1,2,3,4,50)
text <- c("this is love love something", "this is not hate hate hate something", "#something islove rethched this not", " Shiny is love confusing me", "this is hate also somthing difficult")
letter<- c("a", "b", "c", "D", "e")
tweetdf <- data.frame(num, text, letter)
tdm <- if( is.null(tweetdf) ){return()} ## should not use return here as this is not a function
else{
print(tweetdf)
tweetdf$text <- tolower(tweetdf$text)
# tweetdf #UserName
tweetdf$text <- gsub("#\\w+", "", tweetdf$text)
#remove punctuation
tweetdf$text <- gsub("[[:punct:]]", "", tweetdf$text)
#remove links
tweetdf$text <- gsub("http\\w+", "", tweetdf$text)
# Remove tabs
tweetdf$text <- gsub("[ |\t]{2,}", "", tweetdf$text)
# Remove blank spaces at the beginning
tweetdf$text <- gsub("^ ", "", tweetdf$text)
# Remove blank spaces at the end
corpus <- iconv(tweetdf$text, to = "ASCII")
corpus <- Corpus(VectorSource(corpus))
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeNumbers)
cleanset <- tm_map(corpus, removeWords, stopwords('english'))
tdm <- TermDocumentMatrix(cleanset)
tdm <- as.matrix(tdm)
w <- rowSums(tdm)
}
})
output$ttext <- renderPlot({
barplot(w())
})
output$wordCl <- renderWordcloud2({
w <- data.frame(names(w()), w())
colnames(w) <- c('word', 'freq')
wordcloud2(w,
color = 'random-dark',
size = 0.7,
shape = 'circle',
rotateRatio = 0.5,
minSize = 1)
})
}
shinyApp(ui, server)

Related

How to use the Undo button in R shiny to undo earlier operations and recover them

I am working on a R shiny app that reads CSV and produces a dataTable. I am looking for a way to undo prior actions one by one whenever I clik the Undo button (like CTRL+ Z in Windows), however, the code below restores all previous actions once I press the Undo button.
Could someone please assist me in resolving this problem?
csv data
ID Type Range
21 A1 B1 100
22 C1 D1 200
23 E1 F1 300
app.R
library(shiny)
library(reshape2)
library(DT)
library(tibble)
###function for deleting the rows
splitColumn <- function(data, column_name) {
newColNames <- c("Unmerged_type1", "Unmerged_type2")
newCols <- colsplit(data[[column_name]], " ", newColNames)
after_merge <- cbind(data, newCols)
after_merge[[column_name]] <- NULL
after_merge
}
###_______________________________________________
### function for inserting a new column
fillvalues <- function(data, values, columName){
df_fill <- data
vec <- strsplit(values, ",")[[1]]
df_fill <- tibble::add_column(df_fill, newcolumn = vec, .after = columName)
df_fill
}
##function for removing the colum
removecolumn <- function(df, nameofthecolumn){
df[ , -which(names(df) %in% nameofthecolumn)]
}
### use a_splitme.csv for testing this program
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
actionButton("Splitcolumn", "SplitColumn"),
uiOutput("selectUI"),
actionButton("deleteRows", "Delete Rows"),
textInput("textbox", label="Input the value to replace:"),
actionButton("replacevalues", label = 'Replace values'),
actionButton("removecolumn", "Remove Column"),
actionButton("Undo", 'Undo')
),
mainPanel(
DTOutput("table1")
)
)
)
server <- function(session, input, output) {
rv <- reactiveValues(data = NULL, orig=NULL)
observeEvent(input$file1, {
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
rv$orig <- read.csv(file$datapath, header = input$header)
rv$data <- rv$orig
})
output$selectUI<-renderUI({
req(rv$data)
selectInput(inputId='selectcolumn', label='select column', choices = names(rv$data))
})
observeEvent(input$Splitcolumn, {
rv$data <- splitColumn(rv$data, input$selectcolumn)
})
observeEvent(input$deleteRows,{
if (!is.null(input$table1_rows_selected)) {
rv$data <- rv$data[-as.numeric(input$table1_rows_selected),]
}
})
output$table1 <- renderDT({
rv$data
})
observeEvent(input$replacevalues, {
rv$data <- fillvalues(rv$data, input$textbox, input$selectcolumn)
})
observeEvent(input$removecolumn, {
rv$data <- removecolumn(rv$data,input$selectcolumn)
})
observeEvent(input$Undo, {
rv$data <- rv$orig
})
}
We can create a list to host every instance of the table to recover multiple undo's. Note that if the .csv is very big this approach will become inefficient very quick. We can mitigate this infefficiency by implementing a button that clears the undo list up to a point or implementing an append function that saves only the part modified of the table rather than the whole table.
Please, fill free to modify the answer or use it for another answer.
library(shiny)
library(reshape2)
library(DT)
library(tibble)
###function for deleting the rows
splitColumn <- function(data, column_name) {
newColNames <- c("Unmerged_type1", "Unmerged_type2")
newCols <- colsplit(data[[column_name]], " ", newColNames)
after_merge <- cbind(data, newCols)
after_merge[[column_name]] <- NULL
after_merge
}
###_______________________________________________
### function for inserting a new column
fillvalues <- function(data, values, columName){
df_fill <- data
vec <- strsplit(values, ",")[[1]]
tibble::add_column(df_fill, newcolumn = vec, .after = columName)
}
##function for removing the colum
removecolumn <- function(df, nameofthecolumn){
df[ , -which(names(df) %in% nameofthecolumn)]
}
# APP ---------------------------------------------------------------------
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
actionButton("Splitcolumn", "SplitColumn"),
uiOutput("selectUI"),
actionButton("deleteRows", "Delete Rows"),
textInput("textbox", label = "Input the value to replace:"),
actionButton("replacevalues", label = 'Replace values'),
actionButton("removecolumn", "Remove Column"),
actionButton("Undo", 'Undo')
),
mainPanel(
DTOutput("table1")
)
)
)
server <- function(session, input, output) {
#added undo (a list) and counter to accumulate more than one undo
rv <- reactiveValues(data = NULL, orig=NULL, undo = list(), counter = 1)
# csv file ----------------------------------------------------------------
observeEvent(input$file1, {
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
rv$orig <- read.csv(file$datapath, header = input$header)
rv$data <- rv$orig
})
output$selectUI <- renderUI({
req(rv$data)
selectInput(inputId='selectcolumn', label='select column', choices = names(rv$data))
})
# rest of the app ---------------------------------------------------------
observeEvent(input$Splitcolumn, {
rv$undo[[rv$counter]] <- rv$data
rv$counter <- rv$counter + 1
rv$data <- splitColumn(rv$data, input$selectcolumn)
})
observeEvent(input$deleteRows,{
if (!is.null(input$table1_rows_selected)) {
rv$undo[[rv$counter]] <- rv$data
rv$counter <- rv$counter + 1
rv$data <- rv$data[-as.numeric(input$table1_rows_selected),]
}
})
output$table1 <- renderDT({
rv$data
})
observeEvent(input$replacevalues, {
rv$undo[[rv$counter]] <- rv$data
rv$counter <- rv$counter + 1
rv$data <- fillvalues(rv$data, input$textbox, input$selectcolumn)
})
observeEvent(input$removecolumn, {
rv$undo[[rv$counter]] <- rv$data
rv$counter <- rv$counter + 1
rv$data <- removecolumn(rv$data,input$selectcolumn)
})
observeEvent(input$Undo, {
if (rv$counter > 1) {
rv$data <- rv$undo[[rv$counter - 1]]
#index must be more than 1
rv$counter <- rv$counter - 1
}
})
}
shinyApp(ui, server)

How do I get meaningful outputs for findAssocs when generating word clouds from a single data frame with several filters?

Trying to create a shiny app that will generate different word clouds according to the variable selections made by users. So far, I have been able to produce the clouds, but it is the findAssocs() part that is giving problems - only returning $word and numeric(0).
#> **Warning:** Error in findAssocs: object 'dtm' not found.
I tried it without the filters and got meaningful outputs for findAssocs().
Would be very grateful for some help.
Here is the reprex-
Agegroup <- c("A","B","D","C","E","B","A","B","D","E")
Region <- c("N","S","E","W","W","N","S","E","S","E")
Word <- c("raining cats and dogs", "rabbit out of a hat", "cats with nine lives", "a bear hug",
"elephant in the room", "white elephant", "dogs bark, cats meow",
"a life worth living", "hello", "gold fish")
Word2 <- c("raining cats and dogs", "rabbit out of a hat", "cats with nine lives", "a bear hug",
"elephant in the room", "white elephant", "dogs bark, cats meow",
"a life worth living", "gold fish", "hello")
Data <- data.frame(Agegroup,Region,Word, Word2, stringsAsFactors=FALSE)
ui <- fluidPage(
titlePanel("Big and small pets"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "source",
label = "Select Question",
choices = c("Why are you satisfied or not satisfied with service?" = "satisfy",
"Reasons for recommending or not recommending business" = "recommend")),
selectInput("region",
"Select region:",
choices = c("total", "N", "S", "E", "W"),
selected = "total"),
selectInput("group",
"Select age group:",
choices = c("total", "A","B","C","D","E"),
selected = "total"),
),
mainPanel(
wordcloud2Output("cloud"),verbatimTextOutput("heading2")
)
)
)
server <- function(input, output) {
output$cloud <- renderWordcloud2({
Data <- Data%>%
dplyr::select(Region, Word, Word2, Agegroup)
if(input$region == "total"){
Data <- Data
}
else if(input$region != "total"){
Data <- Data%>%
subset(Region == input$region)
}
if(input$group == "total"){
Data <- Data
}
else if(input$group != "total"){
Data <- Data%>%
subset(Agegroup == input$group)
}
if (input$source == "satisfy"){
text <- Data%>%
select(Word)}
else if (input$source == "recommend"){
text <- Data%>%
select(Word2)}
docs <- Corpus(VectorSource(text))
toSpace <- content_transformer(function (x , pattern ) gsub(pattern, " ", x))
docs <- tm_map(docs, toSpace, "/")
docs <- tm_map(docs, toSpace, "#")
docs <- tm_map(docs, toSpace, "\\|")
docs <- tm_map(docs, content_transformer(tolower))
docs <- tm_map(docs, removeNumbers)
docs <- tm_map(docs, removeWords, stopwords("english"))
docs <- tm_map(docs, removeWords, c("blabla1", "blabla2"))
docs <- tm_map(docs, removePunctuation)
docs <- tm_map(docs, stripWhitespace)
docs <- tm_map(docs, stemDocument)
dtm <- TermDocumentMatrix(docs)
m <- as.matrix(dtm)
v <- sort(rowSums(m), decreasing=TRUE)
d <- data.frame(word = names(v), freq=v)
set.seed(1234)
isolate({
wordcloud2(data = d, size = 0.5, shape = "circle")
})
})
output$heading2 <- renderPrint({
findAssocs(dtm, "cat", corlimit = 0.3)
})
}
shinyApp(ui = ui, server = server)
There are a couple issues with the shiny code, and there's also a problem with the dplyr code. The dplyr issue was that select was used in a place where pull should have been used.
Below is a corrected shiny app. Note that dtm had to beconverted into its own reactive variable - you were defining it inside one scope and trying to use it in another. dtm is a value that changes depending on the inputs, so that means it's reactive. Also note that I removed the isolate() around the wordcloud call. That isolate statement did not do anything - isolate tells shiny to not fire reactivity when a reactive value changes, but in the line wordcloud2(data = d, size = 0.5, shape = "circle") there is nothing reactive.
library(shiny)
library(wordcloud2)
library(tm)
library(dplyr)
Agegroup <- c("A","B","D","C","E","B","A","B","D","E")
Region <- c("N","S","E","W","W","N","S","E","S","E")
Word <- c("raining cats and dogs", "rabbit out of a hat", "cats with nine lives", "a bear hug",
"elephant in the room", "white elephant", "dogs bark, cats meow",
"a life worth living", "hello", "gold fish")
Word2 <- c("raining cats and dogs", "rabbit out of a hat", "cats with nine lives", "a bear hug",
"elephant in the room", "white elephant", "dogs bark, cats meow",
"a life worth living", "gold fish", "hello")
Data <- data.frame(Agegroup,Region,Word, Word2, stringsAsFactors=FALSE)
ui <- fluidPage(
titlePanel("Big and small pets"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "source",
label = "Select Question",
choices = c("Why are you satisfied or not satisfied with service?" = "satisfy",
"Reasons for recommending or not recommending business" = "recommend")),
selectInput("region",
"Select region:",
choices = c("total", "N", "S", "E", "W"),
selected = "total"),
selectInput("group",
"Select age group:",
choices = c("total", "A","B","C","D","E"),
selected = "total"),
),
mainPanel(
wordcloud2Output("cloud"),verbatimTextOutput("heading2")
)
)
)
server <- function(input, output) {
dtm <- reactive({
Data <- Data%>%
dplyr::select(Region, Word, Word2, Agegroup)
if(input$region == "total"){
Data <- Data
}
else if(input$region != "total"){
Data <- Data%>%
subset(Region == input$region)
}
if(input$group == "total"){
Data <- Data
}
else if(input$group != "total"){
Data <- Data%>%
subset(Agegroup == input$group)
}
if (input$source == "satisfy"){
text <- Data%>%
pull(Word)}
else if (input$source == "recommend"){
text <- Data%>%
pull(Word2)}
docs <- Corpus(VectorSource(text))
toSpace <- content_transformer(function (x , pattern ) gsub(pattern, " ", x))
docs <- tm_map(docs, toSpace, "/")
docs <- tm_map(docs, toSpace, "#")
docs <- tm_map(docs, toSpace, "\\|")
docs <- tm_map(docs, content_transformer(tolower))
docs <- tm_map(docs, removeNumbers)
docs <- tm_map(docs, removeWords, stopwords("english"))
docs <- tm_map(docs, removeWords, c("blabla1", "blabla2"))
docs <- tm_map(docs, removePunctuation)
docs <- tm_map(docs, stripWhitespace)
docs <- tm_map(docs, stemDocument)
TermDocumentMatrix(docs)
})
output$cloud <- renderWordcloud2({
m <- as.matrix(dtm())
v <- sort(rowSums(m), decreasing=TRUE)
d <- data.frame(word = names(v), freq=v)
set.seed(1234)
wordcloud2(data = d, size = 0.5, shape = "circle")
})
output$heading2 <- renderPrint({
findAssocs(dtm(), "cat", corlimit = 0.3)
})
}
shinyApp(ui = ui, server = server)

Shiny: subsetting a table from a textInput with multiple values

I have a simple Shiny app. The user enters a code eg: a1, b1, c1 etc in the textInput.
When only one code is listed it works great, but if the user writes two or more codes separated by a comma it doesn't.
How can the user input as many codes as they like?
library(shiny)
ui <- fluidPage(
titlePanel(""),
sidebarLayout(
sidebarPanel(
textInput(inputId = "textBox",
label = "Code Search",
placeholder = "Enter codes here seperated by a comma"),
actionButton("textSearchButton", "Generate the Table")
),
fluidRow(
tableOutput("dtOut")
)
)
)
server <- function(input, output) {
df <- data.frame(Code = paste0(letters, 1),
Description = "Something here",
Value = "Some value")
outputFunc <- function(code, df){
# # Dummy data
# code <- c('a1', 'b1', 'c1')
outTbl <- df[df$Code %in% code,]
return(list(outTbl))
}
textSearch <- eventReactive(input$textSearchButton, {
outputFunc(input$textBox, df)
})
output$dtOut <- renderTable({
textSearch()[[1]]
})
}
shinyApp(ui, server)
I simplified your code a bit:
library(shiny)
ui <- fluidPage(
titlePanel(""),
sidebarLayout(
sidebarPanel(
textInput(inputId = "textBox",
label = "Code Search",
placeholder = "Enter codes here seperated by a comma"),
actionButton("textSearchButton", "Generate the Table")
),
fluidRow(
tableOutput("dtOut")
)
)
)
server <- function(input, output) {
df <- eventReactive(input$textSearchButton, {
# outputFunc(input$textBox, df)
req(input$textBox)
codes <- unlist(strsplit(input$textBox, ", "))
return(data.frame(Code = codes,
Description = "Something here",
Value = "Some value"))
})
output$dtOut <- renderTable({
df()
})
}
shinyApp(ui, server)
Does it respond to your need ?

Downloading the output from Shiny APP (need some advice)

I want to download the output of this App which I made but there is an error and when I open the downloaded data it is empty.I make a data set by output$other_val_show and I want to download it. Any advice?
The following code in for the UI section.
library(shiny)
library(quantreg)
library(quantregGrowth)
library(plotly)
library(rsconnect)
library(ggplot2)
library(lattice)
ui = tagList(
tags$head(tags$style(HTML("body{ background: aliceblue; }"))),
navbarPage(title="",
tabPanel("Data Import",
sidebarLayout(sidebarPanel( fileInput("file","Upload your CSV",multiple = FALSE),
tags$hr(),
h5(helpText("Select the read.table parameters below")),
checkboxInput(inputId = 'header', label = 'Header', value = FALSE),
checkboxInput(inputId = "stringAsFactors", "StringAsFactors", FALSE),
radioButtons (inputId = 'sep', label = 'Separator',
choices = c(Comma=',',Semicolon=';',Tab='\t', Space=''), selected = ',')
),
mainPanel(uiOutput("tb1"))
)),
tabPanel("Interval",
sidebarLayout(sidebarPanel(
uiOutput("model_select"),
uiOutput("var1_select"),
uiOutput("rest_var_select"),
#uiOutput("testText1"), br(),
#textInput("Smooting Parameter min value", "Smooting Parameter max value", value = "")
sliderInput("range", "Smooth Parameter range:",min = 0, max = 1000, value = c(0,100)),
downloadButton('downloadData', 'Download')
),
mainPanel(helpText("Selected variables and Fitted values"),
verbatimTextOutput("other_val_show")))),
tabPanel("Model Summary", verbatimTextOutput("summary")),
tabPanel("Scatterplot", plotOutput("scatterplot"))#, # Plot
#tabPanel("Distribution", # Plots of distributions
#fluidRow(
#column(6, plotOutput("distribution1")),
#column(6, plotOutput("distribution2")))
#)
,inverse = TRUE,position="static-top",theme ="bootstrap.css"))
The following code in for the Server section. (I want to download the output which is "gr" and I want to download it by downloadHandler function.
server<-function(input,output) {
data <- reactive({
lower <- input$range[1]
upper <- input$range[2]
file1 <- input$file
if(is.null(file1)){return()}
read.table(file=file1$datapath, sep=input$sep, header = input$header, stringsAsFactors = input$stringAsFactors)
})
output$table <- renderTable({
if(is.null(data())){return ()}
data()
})
output$tb1 <- renderUI({
tableOutput("table")
})
#output$model_select<-renderUI({
#selectInput("modelselect","Select Algo",choices = c("Reference Interval"="Model"))
#})
output$var1_select<-renderUI({
selectInput("ind_var_select","Select Independent Variable", choices =as.list(names(data())),multiple = FALSE)
})
output$rest_var_select<-renderUI({
checkboxGroupInput("other_var_select","Select Dependent Variable",choices =as.list(names(data()))) #Select other Var
})
output$other_val_show<-renderPrint({
input$other_var_select
input$ind_var_select
f<-data()
lower <- input$range[1]
upper <- input$range[2]
library(caret)
library(quantregGrowth)
dep_vars <- paste0(input$ind_var_select, collapse = "+")
after_tilde <- paste0("ps(", dep_vars, ", lambda = seq(",lower,",",upper,",l=100))")
dyn_string <- paste0(input$other_var_select, " ~ ", after_tilde)
Model<-quantregGrowth::gcrq(as.formula(dyn_string),tau=c(0.025,0.975), data=f)
temp <- data.frame(Model$fitted)
gr <- cbind(f, temp)
print(gr)
})
output$downloadData <- downloadHandler(
write.csv(gr, file, row.names = FALSE)
)
}
shinyApp(ui=ui,server=server)
It's hard to fully answer this without a minimal reproducibile example, but here's what I would try:
Create gr outside of renderPrint
Use gr() in downloadHandler
Rewrite downloadHandler to include content and filename arguments
Here's a minimal example with the same logic as your app, i.e. create a reactive dataframe which is both printed (renderPrint) and downloadable (downloadHandler).
library(shiny)
ui <- navbarPage(title = "Example",
tabPanel("First",
selectInput("fruit", "Fruit", c("apple", "orange", "pear")),
h4("Output from renderPrint:"),
textOutput("other_val_show"),
h4("Download Button: "),
downloadButton("downloadData")))
server <- function(input, output) {
gr <- reactive({
data.frame(fruit = input$fruit)
})
output$other_val_show <- renderPrint({
print(gr())
})
output$downloadData <- downloadHandler(
filename = "example.csv",
content = function(file) {
write.csv(gr(), file)
})
}
shinyApp(ui, server)
You define gr inside the scope of that renderPrint function so it isn't available to downloadHandler. You should define gr as a reactive value somewhere outside that function. That way, when you assign it in the renderPrint function, it will be accessible to the entire scope of your program.
In the future, it would be helpful to provide the text of any error messages you get - they are often quite helpful to solving problems.

How to aggregate a reactive table in shiny?

I am trying to aggregate a reactive table from Shiny. My structure is similar to this example
library(shiny)
runApp(list(
ui=pageWithSidebar(headerPanel("Adding entries to table"),
sidebarPanel(textInput("text1", "Column 1"),
textInput("text2", "Column 2"),
actionButton("update", "Update Table")),
mainPanel(tableOutput("table1"))),
server=function(input, output, session) {
values <- reactiveValues()
values$df <- data.frame(Column1 = NA, Column2 = NA)
newEntry <- observe({
if(input$update > 0) {
newLine <- isolate(c(input$text1, input$text2))
isolate(values$df <- rbind(values$df, newLine))
}
})
output$table1 <- renderTable({values$df})
}))
I am trying with several ways, for example:
output$table2 <- renderTable({
as.data.frame(values$Column1, list(values$Column2), sum
})
But until now I could not have the expected result. Do you have an idea, please?
Are you looking for something like a row sum? I used the apply function with sum, but the
output$table1 <- renderTable({cbind(values$df, Rowsum = apply(values$df, 1, function(x) sum(as.numeric(x))))})
Also, if you would like to remove the first empty line, you could use the advice in the SO question you linked
It looks like this:
Complete code:
library(shiny)
runApp(list(
ui=pageWithSidebar(headerPanel("Adding entries to table"),
sidebarPanel(textInput("text1", "Column 1"),
textInput("text2", "Column 2"),
actionButton("update", "Update Table")),
mainPanel(tableOutput("table1"))),
server=function(input, output, session) {
values <- reactiveValues()
values$df <- data.frame(Column1 = numeric(0), Column2 = numeric(0))
newEntry <- observe({
if(input$update > 0) {
newLine <- isolate(c(input$text1, input$text2))
isolate(values$df[nrow(values$df) + 1,] <- c(input$text1, input$text2))
}
})
output$table1 <- renderTable({cbind(values$df, Rowsum = apply(values$df, 1, function(x) sum(as.numeric(x))))})
}))
Please note, that there is no exception handling implemented.