Dynamically Generate Plots in Conditional Tabs using renderUI in Shiny - r

I need some help creating dynamic plots that go inside dynamic tabs. Here's the situation ... I have a data file that contains digital marketing data. The file has the following pieces of information: Campaign Name, Channel Name, Page Views, and Visits. Campaign Names are unique and roll up to one of four different marketing channels. This will change in the future depending on the data I feed it (for example, I may have six marketing channels in the next file I use), but this will do for troubleshooting purposes. I want to dynamically create tabs and output for each marketing channel in the file. I have been able to figure out how to create the tabs, but I'm having a hard time figuring out how to create other types of output (like a plot) to go with each tab.
The tabs were created using renderUI in the following code in the server file:
output$mytabs = renderUI({
if(is.null(rawData())){return ()}
channels = unique(rawData()$Channel)
myTabs = lapply(channels, tabPanel)
do.call(tabsetPanel, myTabs)
})
output$scatterPlot <- renderUI({
if(is.null(rawData())){return()}
createPlots()
myData = rawData()
channels = unique(myData$Channel)
plot_output_list <- lapply(seq_along(channels), function(i) {
plotname <- paste("plot", i, sep="")
plotOutput(plotname)
})
do.call(tagList, plot_output_list)
})
createPlots <- reactive ({
myData = rawData()
channels = unique(myData$Channel)
for (i in seq_along(channels)) {
local({
my_i <- i
plotname <- paste("plot", my_i, sep="")
tempRows = which(myData$Channel==channels[i])
output[[plotname]] <- renderPlot({
plot(x = myData$Spend[tempRows], y = myData$Return[tempRows])
})
})
}
})
These were then referenced in the ui file as follows:
mainPanel(
tabsetPanel(
tabPanel("Data Summary", uiOutput("dataSummary")),
tabPanel("Parameters & Model Fit",
uiOutput('mytabs'),
uiOutput('scatterPlot')),
tabPanel("Budget & Spend Summary"),
tabPanel("Testing", plotOutput('plot5'))
)
)
Ultimately, I'd like to plot Page Views vs Visits for each Marketing Channel on the corresponding marketing channel tab. At the moment, all four plots are showing up in each of marketing channel tab. In my global file, I've created two functions -- one function plots one channel at a time and another function that plots all the channels and saves each one as separate elements within a list. I'm not sure which one of these will end up being useful, if either.
I'm certain that I'm not understanding how to set 'myTabs' or I'm referencing it incorrectly from the ui. Even with this snippet of the code, someone here might be able to quickly spot the error and recommend a fix, but I am happy to provide the rest of my code if that would be helpful.
Thanks!
Jess
EDIT: For Reference, here is all of my code. Just changed the dir object to be the directory you want to work in.
library(shiny)
dir = ""
setwd(dir)
#######################
### Generate Data ###
#######################
channels = c("Affiliate","Email","Media","SEO")
nObs = c(round(runif(1,100,200)))
pageViews = runif(nObs*length(channels),50,500)
visits = runif(nObs*length(channels),10,100)
campaignNames = unlist(lapply(channels, FUN = function(x) paste(x,seq(from=1,to=nObs,by=1),sep="")))
channelNames = rep(channels,nObs)
myData = data.frame(Campaign = campaignNames, Channel = channelNames, Return = pageViews, Spend = visits)
write.table(myData,file="myTestData.csv",sep=",",col.names=TRUE,row.names=FALSE)
########################
### Global Functions #
########################
summarizeData = function(myDat){
summaryData = summarize(group_by(myDat,Channel), 'Campaign Count' = length(Campaign), Return = sum(Return), Spend = sum(Spend))
return(summaryData)
}
### PLOT DATA AND MODEL FIT ###
plotSingle = function(myData, channelName){
p1 <- ggplot(myData[which(myData$Channel==channelName),], aes(x = Spend, y = Return)) +
geom_point(color="black") +
theme(panel.background = element_rect(fill = 'grey85'),
panel.grid.major = element_line(colour = "white"))
return(p1)
}
plotAll = function(myData){
channels = unique(myData$Channel)
plots <- list() # new empty list
for (i in 1:length(channels)) {
channelName = channels[i]
p1 = plotSingle(myData = myData, channelName = channelName)
plots[[i]] = p1
}
return(plots)
}
############
### UI ###
############
ui <- fluidPage(
headerPanel('Plot Testing'),
sidebarPanel(
h3(helpText("Data Input")),
fileInput(inputId = "rawDataInput", label = "Upload Data"),
h5(helpText("Select the file parameters below")),
checkboxInput(inputId = 'header', label = 'Header', value = TRUE),
checkboxInput(inputId = "stringAsFactors", "stringAsFactors", FALSE),
br(),
radioButtons(inputId = 'sep', label = 'Separator', choices = c(Comma=',',Semicolon=';',Tab='\t', Space=''), selected = ',')
),
mainPanel(
tabsetPanel(
tabPanel("Data Summary", uiOutput("dataSummary")),
tabPanel("Parameters & Model Fit",
uiOutput('mytabs'),
uiOutput('scatterPlot')),
tabPanel("Budget & Spend Summary"),
tabPanel("Testing", plotOutput('plot5'))
)
)
)
################
### Server ###
################
server = function(input, output) {
rawData <- reactive({
file1 <- input$rawDataInput
if(is.null(file1)){return()}
read.table(file=file1$datapath, sep=input$sep, header = input$header, stringsAsFactors = input$stringAsFactors)
})
# this reactive output contains the summary of the dataset and display the summary in table format
output$filedf <- renderTable({
if(is.null(rawData())){return ()}
input$rawDataInput
})
# this reactive output contains the summary of the dataset and display the summary in table format
output$sum <- renderTable({
if(is.null(rawData())){return ()}
summarizeData(rawData())
})
# This reactive output contains the dataset and display the dataset in table format
output$table <- renderTable({
if(is.null(rawData())){return ()}
rawData()
})
dataPlots = reactive({
channels = unique(rawData()$Channel)
plots = plotAll(rawData())
})
output$mytabs = renderUI({
if(is.null(rawData())){return ()}
channels = unique(rawData()$Channel)
createPlots()
plot_output_list <- lapply(seq_along(channels), function(i) {
plotname <- paste("plot", i, sep="")
plotOutput(plotname)
})
myTabs = lapply(channels, tabPanel)
do.call(tabsetPanel, myTabs)
})
createPlots <- reactive ({
myData = rawData()
channels = unique(myData$Channel)
for (i in seq_along(channels)) {
local({
my_i <- i
plotname <- paste("plot", my_i, sep="")
tempRows = which(myData$Channel==channels[i])
output[[plotname]] <- renderPlot({
plot(x = myData$Spend[tempRows], y = myData$Return[tempRows])
})
})
}
})
output$scatterPlot <- renderUI({
if(is.null(rawData())){return()}
createPlots()
myData = rawData()
channels = unique(myData$Channel)
plot_output_list <- lapply(seq_along(channels), function(i) {
plotname <- paste("plot", i, sep="")
plotOutput(plotname)
})
do.call(tagList, plot_output_list)
})
output$dataSummary <- renderUI({
if(is.null(rawData())){return()}
else
tabsetPanel(tabPanel("About file", tableOutput("filedf")),tabPanel("Data", tableOutput("table")),tabPanel("Summary", tableOutput("sum")))
})
output$plot5 = renderPlot({
if(is.null(rawData())){return ()}
myData = rawData()
channelName = "Affiliate"
p1 <- ggplot(myData[which(myData$Channel==channelName),], aes(x = Spend, y = Return)) +
geom_point(color="black") +
theme(panel.background = element_rect(fill = 'grey85'),
panel.grid.major = element_line(colour = "white"))
return(p1)
})
}
### Run App ###
shinyApp(ui = ui, server = server)

Your example isn't exactly minimal so i did some stripping away. First the data and helper functions
library(shiny)
library(ggplot2)
channels = c("Affiliate","Email","Media","SEO")
nObs = c(round(runif(1,100,200)))
myData = data.frame(
Campaign = unlist(lapply(channels, FUN = function(x) paste(x,seq(from=1,to=nObs,by=1),sep=""))),
Channel = rep(channels,nObs),
Return = runif(nObs*length(channels),50,500),
Spend = runif(nObs*length(channels),10,100)
)
plotSingle = function(myData, channelName){
ggplot(myData[which(myData$Channel==channelName),], aes(x = Spend, y = Return)) +
geom_point(color="black") +
theme(panel.background = element_rect(fill = 'grey85'),
panel.grid.major = element_line(colour = "white"))
}
Now the UI
ui <- fluidPage(
headerPanel('Plot Testing'),
mainPanel(
uiOutput('mytabs'),
plotOutput('scatterPlot')
)
)
Note that we only use one plotOutput here. What we will do is just change the plot it's showing based on the currently selected tab. Here's the server code
server = function(input, output) {
rawData <- reactive({
myData
})
output$mytabs = renderUI({
if(is.null(rawData())){return ()}
channels = unique(rawData()$Channel)
myTabs = unname(Map(tabPanel, channels))
do.call(tabsetPanel, c(myTabs, id="channeltab"))
})
output$scatterPlot <- renderPlot({
if(is.null(rawData()) | is.null(input$channeltab)){return ()}
plotSingle(rawData(), input$channeltab)
})
}
You see we set an id on the tabsetPanel we create. We can then use that as input to determine which panel is selected and show the correct plot. All run with
shinyApp(ui = ui, server = server)

Related

How to write a file based on eventReactive

My app allows the user to generate some plots and save them as png.
I want the app as well to update a csv file based on some inputs made into the app by the user.
For example purposes, I created a toy app that generates a csv file in a given folder.
In both cases, the app doesn't display any error message or info, but it doesn't store any file anywhere.
library(shiny)
library(ggplot2)
library(AlphaPart)
ui <- fluidPage(
selectInput("var1","Select var1", choices = names(iris)),
selectInput("var2","Select var2", choices = names(iris)),
plotOutput("myplot"),
downloadLink("downloadPlot", label = icon("download")))
server <- function(input, output, session) {
data <- reactive(iris)
var1 <- reactive({input$var1})
var2 <- reactive({input$var2})
# Genearte plot
draw_boxplot <- function(data, var1, var2){
ggplot(data=data(), aes(x=.data[[input$var1]], y = .data[[input$var2]]))+
geom_boxplot()
}
plot1 <- reactive({
req(data(), input$var1, input$var2)
draw_boxplot(data(), var1(), var2())
})
output$myplot <- renderPlot({
plot1()
})
#Download
output$downloadPlot <- downloadHandler(
filename = function() {
return("Plot.png")
},
content = function(file) {
png(file)
print(plot1())
dev.off()
})
#Write csv
eventReactive(input$downloadPlot, {
dat <- as.data.frame(c(input$num_var_1, input$num_var_2))
write.csv(dat, "C:/dat.csv", row.names = FALSE)
})
}
shinyApp(ui, server)
library(shiny)
library(ggplot2)
library(AlphaPart)
library(spsComps)
ui <- fluidPage(
selectInput("var1","Select var1", choices = names(iris)),
selectInput("var2","Select var2", choices = names(iris)),
plotOutput("myplot"),
downloadLink("downloadPlot", label = icon("download")))
server <- function(input, output, session) {
data <- reactive(iris)
var1 <- reactive({input$var1})
var2 <- reactive({input$var2})
# Genearte plot
draw_boxplot <- function(data, var1, var2){
ggplot(data=data(), aes(x=.data[[input$var1]], y = .data[[input$var2]]))+
geom_boxplot()
}
plot1 <- reactive({
req(data(), input$var1, input$var2)
draw_boxplot(data(), var1(), var2())
})
output$myplot <- renderPlot({
plot1()
})
#Download
downloaded <- reactiveVal(0)
output$downloadPlot <- downloadHandler(
filename = function() {
return("Plot.png")
},
content = function(file) {
png(file)
print(plot1())
dev.off()
on.exit({spsComps::incRv(downloaded)})
})
#Write csv
observeEvent(downloaded(), {
dat <- as.data.frame(c(input$num_var_1, input$num_var_2))
utils::write.csv(dat, "dat.csv", row.names = FALSE)
print("File saved")
}, ignoreInit = TRUE)
}
shinyApp(ui, server)
Unfortunately, you can't observe download event. So here we do, introduce another reactiveVal which we can change inside the download event so we will know if the download button has been clicked.
spsComps::incRv is a short hand function for downloaded(isolate(downloaded()) + 1), so it increase the reactiveVal every time by one.
use on.exit on the end to make sure this happens only when the plot is successful.
Instead of using eventReactive, observeEvent should be used since you are not returning any value but just write a file.

How to conditionally download a plot?

The below reproducible code allows the user to select either a data table or a plot of the data for viewing (via input$view). I'm trying to create a conditional around the downloadHandler() so that if the user is viewing the data table and chooses to download, then the data is downloaded; otherwise if the user is viewing the plot and chooses to download then a plot in PNG format is downloaded. I'm running into issues around input$view reactivity. How would I modify the code below to conditionally download whichever (data or plot) the user is viewing?
The code as posted below works for viewing either data or plot, but only allows the data table to be downloaded. Offending lines of code that otherwise cause a crash are commented out.
Reproducible code:
library(shiny)
library(ggplot2)
ui <- fluidPage(
radioButtons("view",
label = "View data or plot",
choiceNames = c('Data','Plot'),
choiceValues = c('viewData','viewPlot'),
selected = 'viewData',
inline = TRUE
),
conditionalPanel("input.view == 'viewData'",tableOutput("DF")),
conditionalPanel("input.view == 'viewPlot'",plotOutput("plotDF")),
downloadButton("download","Download",style = "width:20%;")
)
server <- function(input, output, session) {
data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
data1 <- reactiveValues()
inputView <- reactive(input$view) # attempt to make input$view reactive
observeEvent(input$view,{data1$plot <- ggplot(data, aes(Period,Value)) + geom_line()})
output$DF <- renderTable(data)
output$plotDF <- renderPlot(data1$plot)
output$download <-
# if(inputView() == 'viewData'){
downloadHandler(
filename = function()
paste("dataDownload","csv",sep="."),
content = function(file){
write.table(
data,
na = "",
file,
sep = ",",
col.names = TRUE,
row.names = FALSE)
}
)
# }
# else{
# downloadHandler(
# filename = function(){paste("plotDownload",'.png',sep='')},
# content = function(file){
# ggsave(file,plot=data1$plot)
# }
# )
# }
}
shinyApp(ui, server)
Try this
library(shiny)
library(ggplot2)
ui <- fluidPage(
radioButtons("view",
label = "View data or plot",
choiceNames = c('Data','Plot'),
choiceValues = c('viewData','viewPlot'),
selected = 'viewData',
inline = TRUE
),
conditionalPanel("input.view == 'viewData'",tableOutput("DF")),
conditionalPanel("input.view == 'viewPlot'",plotOutput("plotDF")),
#downloadButton("download","Download",style = "width:20%;")
uiOutput("plotrtable")
)
server <- function(input, output, session) {
data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
data1 <- reactiveValues()
inputView <- reactive(input$view) # attempt to make input$view reactive
observeEvent(input$view,{data1$plot <- ggplot(data, aes(Period,Value)) + geom_line()})
output$DF <- renderTable(data)
output$plotDF <- renderPlot(data1$plot)
output$plotrtable <- renderUI({
if(input$view == 'viewData'){downloadButton("download","Download",style = "width:20%;") }
else {downloadButton("downloadp","Download",style = "width:20%;") }
})
output$download <- downloadHandler(
filename = function()
paste("dataDownload","csv",sep="."),
content = function(file){
write.table(
data,
na = "",
file,
sep = ",",
col.names = TRUE,
row.names = FALSE)
}
)
output$downloadp <- downloadHandler(
filename = function(){paste("plotDownload",'.png',sep='')},
content = function(file){
ggsave(file,plot=data1$plot)
}
)
}
shinyApp(ui, server)

Make a Shiny module reactive when creating the module via a function

I'm trying to generalise Shiny modules so different functions can be passed through, but the expected behaviour of reactivity is not working - could someone point me in the right direction? I have a reprex below that illustrates my problem.
I expect that the dynamic selection of view_id to change values in the renderShiny() function. It works on app load but changing selections do not flow through.
Is it something to do with the environment the module function is created within?
library(shiny)
create_shiny_module_funcs <- function(data_f,
model_f,
outputShiny,
renderShiny){
server_func <- function(input, output, session, view_id, ...){
gadata <- shiny::reactive({
# BUG: this view_id is not reactive but I want it to be
data_f(view_id(), ...)
})
model_output <- shiny::reactive({
shiny::validate(shiny::need(gadata(),
message = "Waiting for data"))
model_f(gadata(), ...)
})
output$ui_out <- renderShiny({
shiny::validate(shiny::need(model_output(),
message = "Waiting for model output"))
message("Rendering model output")
model_output()
}, ...)
return(model_output)
}
ui_func <- function(id, ...){
ns <- shiny::NS(id)
outputShiny(outputId = ns("ui_out"), ...)
}
list(
shiny_module = list(
server = server_func,
ui = ui_func
)
)
}
# create the shiny module
ff <- create_shiny_module_funcs(
data_f = function(view_id) mtcars[, view_id],
model_f = function(x) mean(x),
outputShiny = shiny::textOutput,
renderShiny = function(x) shiny::renderText(paste("Mean is: ", x))
)
## ui.R
ui <- fluidPage(title = "module bug Shiny Demo",
h1("Debugging"),
selectInput("select", label = "Select", choices = c("mpg","cyl","disp")),
textOutput("view_id"),
ff$shiny_module$ui("demo1"),
br()
)
## server.R
server <- function(input, output, session){
view_id <- reactive({
req(input$select)
input$select
})
callModule(ff$shiny_module$server, "demo1", view_id = view_id)
output$view_id <- renderText(paste("Selected: ", input$select))
}
# run the app
shinyApp(ui, server)
The problem was the renderShiny function needs to wrap another function that creates the actual output, so its actually two separate capabilities confused by me as one: renderShiny should take the output of another function that actually creates the thing to render. The below then works:
library(shiny)
module_factory <- function(data_f = function(x) mtcars[, x],
model_f = function(x) mean(x),
output_shiny = shiny::plotOutput,
render_shiny = shiny::renderPlot,
render_shiny_input = function(x) plot(x),
...){
ui <- function(id, ...){
ns <- NS(id)
output_shiny(ns("ui_out"), ...)
}
server <- function(input, output, session, view_id){
gadata <- shiny::reactive({
data_f(view_id(), ...)
})
model <- shiny::reactive({
shiny::validate(shiny::need(gadata(),
message = "Waiting for data"))
model_f(gadata(), ...)
})
output$ui_out <- render_shiny({
shiny::validate(shiny::need(model(),
message = "Waiting for model output"))
render_shiny_input(gadata())
})
return(model)
}
list(
module = list(
ui = ui,
server = server
)
)
}
made_module <- module_factory()
## ui.R
ui <- fluidPage(title = "module bug Shiny Demo",
h1("Debugging"),
selectInput("select", label = "Select", choices = c("mpg","cyl","disp")),
textOutput("view_id"),
made_module$module$ui("factory1"),
br()
)
## server.R
server <- function(input, output, session){
callModule(made_module$module$server, "factory1", view_id = reactive(input$select))
output$view_id <- renderText(paste("Selected: ", input$select))
}
# run the app
shinyApp(ui, server)
I think you want something like this.
library(shiny)
library(plyr)
library(dplyr)
library(DT)
library(data.table)
ui <- pageWithSidebar(
headerPanel = headerPanel('data'),
sidebarPanel = sidebarPanel(fileInput(
'mtcars', h4('Uplaodmtcardata in csv format')
),
uiOutput('tabnamesui')),
mainPanel(uiOutput("tabsets"))
)
server <- function(input, output, session) {
mtcarsFile <- reactive({
input$mtcars
})
xxmtcars <-
reactive({
read.table(
file = mtcarsFile()$datapath,
sep = ',',
header = T,
stringsAsFactors = T
)
})
tabsnames <- reactive({
names(xxmtcars())
})
output$tabnamesui <- renderUI({
req(mtcarsFile())
selectInput(
'tabnamesui',
h5('Tab names'),
choices = as.list(tabsnames()),
multiple = T
# selected = SalesGlobalDataFilter1Val()
)
})
tabnamesinput <- reactive({
input$tabnamesui
})
output$tabsets <- renderUI({
req(mtcarsFile())
tabs <-
reactive({
lapply(tabnamesinput(), function(x)
tabPanel(title = basename(x)
,fluidRow(splitLayout(cellWidths = c("50%", "50%"),
plotOutput(paste0('plot1',x)),
plotOutput(paste0('plot2',x)
))),fluidRow(splitLayout(cellWidths =
c("50%", "50%"),
plotOutput(paste0('plot3',x)),
plotOutput(paste0('plot4',x)
))),
dataTableOutput(paste0('table',x))))
})
do.call(tabsetPanel, c(tabs()))
})
# Save your sub data here
subsetdata<-reactive({
list_of_subdata<-lapply(tabnamesinput(), function(x) {
as.data.table((select(xxmtcars(),x)))
})
names(list_of_subdata)<-tabnamesinput()
return(list_of_subdata)
})
observe(
lapply(tabnamesinput(), function(x) {
output[[paste0('table',x)]] <-
renderDataTable({
subsetdata()[[x]]
})}))
observe(
lapply(tabnamesinput(), function(x) {
for(i in paste0("plot",1:4)){
output[[paste0(i,x)]] <-
renderPlot({subsetdata()[[x]]%>%plot()#CODE REPEATED
})
}
})
)
}
runApp(list(ui = ui, server = server))
Data Source:
https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv

Argument improper in shiny ggplot

I want to create a shiny app that plots a graph of the various data inside a table. I have created the shiny app which
Tells the user to select a file to plot
Loads the data file into a Data database
Asks the user which column to plot
Inserts various data into respective datframes
Then plots the respective selected column
The code is as follows
library(shiny)
library(ggplot2)
ui <- fluidPage(
titlePanel("Creating a database"),
sidebarLayout(
sidebarPanel(
textInput("name", "Company Name"),
numericInput("income", "Income", value = 1),
numericInput("expenditure", "Expenditure", value = 1),
dateInput("date", h3("Date input"),value = Sys.Date() ,min = "0000-01-01",
max = Sys.Date(), format = "dd/mm/yy"),
actionButton("Action", "Submit"),#Submit Button
actionButton("new", "New")),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Table", tableOutput("table")),
tabPanel("Download",
textInput("filename", "Enter Filename for download"), #filename
helpText(strong("Warning: Append if want to update existing data.")),
downloadButton('downloadData', 'Download'), #Button to save the file
downloadButton('Appenddata', 'Append')),#Button to update a file )
tabPanel("Plot",
actionButton("filechoose", "Choose File"),
br(),
selectInput("toplot", "To Plot", choices = c("Income" = "inc",
"Expenditure" = "exp",
"Gross Profit" = "gprofit",
"Net Profit" = "nprofit"
)),
actionButton("plotit", "PLOT"),
plotOutput("Plot"))
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output){
#Global variable to save the data
Data <- data.frame()
Results <- reactive(data.frame(input$name, input$income, input$expenditure,
as.character(input$date),
as.character(Sys.Date())))
#To append the row and display in the table when the submit button is clicked
observeEvent(input$Action,{
Data <<- rbind(Data,Results()) #Append the row in the dataframe
output$table <- renderTable(Data) #Display the output in the table
})
observeEvent(input$new, {
Data <<- NULL
output$table <- renderTable(Data)
})
observeEvent(input$filechoose, {
Data <<- read.csv(file.choose()) #Choose file to plot
inc <- as.numeric(Data[ ,2])
exp <- as.numeric(Data[ ,3])
date <- Data[,4]
gprofit <- exp - inc
nprofit <- (exp - inc) * 0.06
output$table <- renderTable(Data) #Display the choosen file details
})
output$downloadData <- downloadHandler(
filename = function() {
paste(input$filename , ".csv", sep="")}, # Create the download file name
content = function(file) {
write.csv(Data, file,row.names = FALSE) # download data
})
output$Appenddata <- downloadHandler(
filename = function() {
paste(input$filename, ".csv", sep="")},
content = function(file) {
write.table( Data, file=file.choose(),append = T, sep=',',
row.names = FALSE, col.names = FALSE) # Append data in existing
})
observeEvent(input$plotit, {
bab <- input$toplot
output$Plot <- renderPlot("Plot",
ggplot()+ geom_bar(data = Data, aes(x= input$toplot,
y= date)))})
}
# Run the application
shinyApp(ui = ui, server = server)
but when i press the "plot" button, it gives the error
Error in *: non-numeric argument to binary operator`
Where i am wrong? Also i have used the as.numeric to convert the data into numeric so as to remove the error. Open for suggestions to change it also. Please Help. Thank You.
The data is like
Use switch case from switch() statement usage
or How to use the switch statement in R functions? to aid your choice option.
library(shiny)
library(ggplot2)
ui <- fluidPage(
titlePanel("Creating a database"),
sidebarLayout(
sidebarPanel(
textInput("name", "Company Name"),
numericInput("income", "Income", value = 1),
numericInput("expenditure", "Expenditure", value = 1),
dateInput("date", h3("Date input"),value = Sys.Date() ,min = "0000-01-01",
max = Sys.Date(), format = "dd/mm/yy"),
actionButton("Action", "Submit"),#Submit Button
actionButton("new", "New")),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Table", tableOutput("table")),
tabPanel("Download",
textInput("filename", "Enter Filename for download"), #filename
helpText(strong("Warning: Append if want to update existing data.")),
downloadButton('downloadData', 'Download'), #Button to save the file
downloadButton('Appenddata', 'Append')),#Button to update a file )
tabPanel("Plot",
actionButton("filechoose", "Choose File"),
br(),
selectInput("toplot", "To Plot", choices = c("Income" = "inc",
"Expenditure" = "exp",
"Gross Profit" = "gprofit",
"Net Profit" = "nprofit"
)),
actionButton("plotit", "PLOT"),
plotOutput("Plot")
)
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output){
#Global variable to save the data
Data <- data.frame()
Results <- reactive(data.frame(input$name, input$income, input$expenditure,
as.character(input$date),
as.character(Sys.Date())))
#To append the row and display in the table when the submit button is clicked
observeEvent(input$Action,{
Data <<- rbind(Data,Results()) #Append the row in the dataframe
output$table <- renderTable(Data) #Display the output in the table
})
observeEvent(input$new, {
Data <<- NULL
output$table <- renderTable(Data)
})
observeEvent(input$filechoose, {
Data <<- read.csv(file.choose()) #Choose file to plot
output$table <- renderTable(Data) #Display the choosen file details
})
output$downloadData <- downloadHandler(
filename = function() {
paste(input$filename , ".csv", sep="")}, # Create the download file name
content = function(file) {
write.csv(Data, file,row.names = FALSE) # download data
})
output$Appenddata <- downloadHandler(
filename = function() {
paste(input$filename, ".csv", sep="")},
content = function(file) {
write.table( Data, file=file.choose(),append = T, sep=',',
row.names = FALSE, col.names = FALSE) # Append data in existing
})
observeEvent(input$plotit, {
inc <- c(Data[ ,2])
exp <- c(Data[ ,3])
date <- c(Data[,4])
gprofit <- c(Data[ ,3]- Data[ ,2])
nprofit <- (exp - inc) * 0.06
y = input$toplot
switch(EXPR = y ,
inc = output$Plot <- renderPlot(ggplot(data = Data, aes(x= date, y= inc))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Income")),
exp = output$Plot <- renderPlot(ggplot(data = Data, aes(x= date, y= exp))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Expenditure")),
gprofit = output$Plot <- renderPlot(ggplot(data = Data, aes(x= date, y= gprofit))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Gross Profit")),
nprofit = output$Plot <- renderPlot(ggplot(data = Data, aes(x= date, y= nprofit))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Net Profit")))})
}
# Run the application
shinyApp(ui = ui, server = server)

How to use built-in data instead of uploaded data

I have an app like below. I want to either read-in data from file upload or use the built-in data. I thought I could put an action button and if somebody hit it the input data will mount on and it goes to the next levels. My problem is later in my real app, some widgets such as selectInput have to be updated and I want to be empty until user decided whether to use uploaded data or the built-in one.
library(shiny)
x <- mtcars
ui <- fluidPage(
fileInput(inputId = "uploadcsv", "", accept = '.csv'),
actionButton(inputId = "a", label = "action button"),
selectInput("select",label = h3("Select box"),choices = "",selected = 1)
)
server <- function(input, output, session) {
data <- reactive({
infile <- input$uploadcsv
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE, sep = ",")
})
DataToUse <- NULL
observe(!is.null(input$uploadedcsv),
DataToUse <- data()
)
observeEvent(input$a,
DataToUse <- x
)
observe({
req(DataToUse)
if (max(DataToUse$cyl) %% 4 == 0){
numberofinterval <- max(DataToUse$cyl) %/% 4
} else {
numberofinterval <- (max(DataToUse$cyl) %/% 4)+1
}
NumPeriod <- seq(0, numberofinterval)
updateSelectInput(session, inputId = "select",
choices = NumPeriod,
selected = NumPeriod)
})
}
shinyApp(ui = ui, server = server)
Something like this should do:
library(shiny)
x <- mtcars
ui <- fluidPage(
fileInput(inputId = "uploadcsv", "", accept = '.csv'),
actionButton(inputId = "a", label = "action button"),
selectInput("select",label = h3("Select box"),choices = "",selected = 1)
)
server <- function(input, output, session) {
data <- reactive({
infile <- input$uploadcsv
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE, sep = ",")
})
v <- reactiveValues()
v$DataToUse <- NULL
observeEvent(input$uploadcsv,{
if(!is.null(input$uploadcsv)){
v$DataToUse <- data()
}
})
observeEvent(input$a,v$DataToUse <- x)
observeEvent(v$DataToUse,{
req(v$DataToUse)
if (max(v$DataToUse$cyl) %% 4 == 0){
numberofinterval <- max(v$DataToUse$cyl) %/% 4
} else {
numberofinterval <- (max(v$DataToUse$cyl) %/% 4)+1
}
NumPeriod <- seq(0, numberofinterval)
updateSelectInput(session, inputId = "select",
choices = NumPeriod,
selected = NumPeriod)
})
}
shinyApp(ui = ui, server = server)

Resources