I am trying to save a ggplot2 object made in a shiny app. Basically this code allows .xlsx files to be uploaded and plots created after selecting from some options. I have then included a download button so that the user may download the plot they have created. I am using downloadHandler() and grDevices::png(). Pressing the button does cause a .png file to be downloaded, but when I open it, it is just a blank, white square. I am so close! Any help would be much appreciated. Thank you.
#initialize
library(shiny)
library(ggplot2)
library(purrr)
library(dplyr)
library(plotly)
#example data
data(iris)
#make some factors
#easier to let ggplot2 control plotting (color, fill) based on type
data(mtcars)
uvals<-sapply(mtcars,function(x){length(unique(x))})
mtcars<-map_if(mtcars,uvals<4,as.factor) %>%
as.data.frame()
#plotting theme for ggplot2
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
# UI for app
ui<-(pageWithSidebar(
# title
headerPanel("Select Options"),
#input
sidebarPanel
(
# Input: Select a file ----
fileInput("file1", "Choose xlsx File",
multiple = TRUE,
accept = c(".xlsx")),
# Horizontal line ----
tags$hr(),
#download button
fluidPage(downloadButton('down')),
# Input: Select what to display
selectInput("dataset","Data:",
choices =list(iris = "iris", mtcars = "mtcars",
uploaded_file = "inFile"), selected=NULL),
selectInput("xaxis","X axis:", choices = NULL),
selectInput("yaxis","Y axis:", choices = NULL),
selectInput("fill","Fill:", choices = NULL),
selectInput("group","Group:", choices = NULL),
selectInput("plot.type","Plot Type:",
list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
),
checkboxInput("show.points", "show points", TRUE)
),
# output
mainPanel(
h3(textOutput("caption")),
#h3(htmlOutput("caption")),
uiOutput("plot") # depends on input
)
))
# shiny server side code for each call
server<-function(input, output, session){
#update group and
#variables based on the data
observe({
#browser()
if(!exists(input$dataset)) return() #make sure upload exists
var.opts<-colnames(get(input$dataset))
updateSelectInput(session, "xaxis", choices = var.opts)
updateSelectInput(session, "yaxis", choices = var.opts)
updateSelectInput(session, "fill", choices = var.opts)
updateSelectInput(session, "group", choices = var.opts)
})
output$caption<-renderText({
switch(input$plot.type,
"boxplot" = "Boxplot",
"histogram" = "Histogram",
"density" = "Density plot",
"bar" = "Bar graph")
})
output$plot <- renderUI({
plotOutput("p")
})
#get data object
get_data<-reactive({
if(!exists(input$dataset)) return() # if no upload
check<-function(x){is.null(x) || x==""}
if(check(input$dataset)) return()
obj<-list(data=get(input$dataset),
yaxis=input$yaxis,
xaxis=input$xaxis,
fill=input$fill,
group=input$group
)
#require all to be set to proceed
if(any(sapply(obj,check))) return()
#make sure choices had a chance to update
check<-function(obj){
!all(c(obj$yaxis,obj$xaxis, obj$fill,obj$group) %in% colnames(obj$data))
}
if(check(obj)) return()
obj
})
#plotting function using ggplot2
output$p <- renderPlot({
plot.obj<-get_data()
#conditions for plotting
if(is.null(plot.obj)) return()
#make sure variable and group have loaded
if(plot.obj$yaxis == "" | plot.obj$xaxis =="" | plot.obj$fill ==""| plot.obj$group =="") return()
#plot types
plot.type<-switch(input$plot.type,
"boxplot" = geom_boxplot(),
"histogram" = geom_histogram(alpha=0.5,position="identity"),
"density" = geom_density(alpha=.75),
"bar" = geom_bar(position="dodge")
)
if(input$plot.type=="boxplot") { #control for 1D or 2D graphs
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
y = plot.obj$yaxis,
fill = plot.obj$fill,# let type determine plotting
group = plot.obj$group
)
) + plot.type
if(input$show.points==TRUE)
{
p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
}
} else {
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
fill = plot.obj$fill,
group = plot.obj$group
#color = as.factor(plot.obj$group)
)
) + plot.type
}
p<-p+labs(
fill = input$fill,
x = "",
y = input$yaxis
) +
.theme
print(p)
})
# set uploaded file
upload_data<-reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
#could also store in a reactiveValues
read_excel(inFile$datapath)
})
observeEvent(input$file1,{
inFile<<-upload_data()
})
# downloadHandler contains 2 arguments as functions, namely filename, content
output$down <- downloadHandler(
filename = function() {
paste(input$dataset,"png" , sep=".")
},
# content is a function with argument file. content writes the plot to the device
content = function(file) {
png(file) # open the png device
p # for GGPLOT
dev.off() # turn the device off
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
I responded as a comment, but I recognize it's a little hard to follow, so I'll post the full revised code to make it clearer.
I generally recommend to not do too much within render*() calls. Rather, set up the object you're looking to create in a separate reactive() object, and just refer to that in renderPlot(). In the code below, I moved all your code that creates the plot into a reactive object named p, and then I can refer to it in ggsave() for the downloading.
#initialize
library(shiny)
library(ggplot2)
library(purrr)
library(dplyr)
library(plotly)
#example data
data(iris)
#make some factors
#easier to let ggplot2 control plotting (color, fill) based on type
data(mtcars)
uvals<-sapply(mtcars,function(x){length(unique(x))})
mtcars<-map_if(mtcars,uvals<4,as.factor) %>%
as.data.frame()
#plotting theme for ggplot2
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
# UI for app
ui<-(pageWithSidebar(
# title
headerPanel("Select Options"),
#input
sidebarPanel
(
# Input: Select a file ----
fileInput("file1", "Choose xlsx File",
multiple = TRUE,
accept = c(".xlsx")),
# Horizontal line ----
tags$hr(),
#download button
fluidPage(downloadButton('down')),
# Input: Select what to display
selectInput("dataset","Data:",
choices =list(iris = "iris", mtcars = "mtcars",
uploaded_file = "inFile"), selected=NULL),
selectInput("xaxis","X axis:", choices = NULL),
selectInput("yaxis","Y axis:", choices = NULL),
selectInput("fill","Fill:", choices = NULL),
selectInput("group","Group:", choices = NULL),
selectInput("plot.type","Plot Type:",
list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
),
checkboxInput("show.points", "show points", TRUE)
),
# output
mainPanel(
h3(textOutput("caption")),
#h3(htmlOutput("caption")),
uiOutput("plot") # depends on input
)
))
# shiny server side code for each call
server<-function(input, output, session){
#update group and
#variables based on the data
observe({
#browser()
if(!exists(input$dataset)) return() #make sure upload exists
var.opts<-colnames(get(input$dataset))
updateSelectInput(session, "xaxis", choices = var.opts)
updateSelectInput(session, "yaxis", choices = var.opts)
updateSelectInput(session, "fill", choices = var.opts)
updateSelectInput(session, "group", choices = var.opts)
})
output$caption<-renderText({
switch(input$plot.type,
"boxplot" = "Boxplot",
"histogram" = "Histogram",
"density" = "Density plot",
"bar" = "Bar graph")
})
output$plot <- renderUI({
plotOutput("p")
})
#get data object
get_data<-reactive({
if(!exists(input$dataset)) return() # if no upload
check<-function(x){is.null(x) || x==""}
if(check(input$dataset)) return()
obj<-list(data=get(input$dataset),
yaxis=input$yaxis,
xaxis=input$xaxis,
fill=input$fill,
group=input$group
)
#require all to be set to proceed
if(any(sapply(obj,check))) return()
#make sure choices had a chance to update
check<-function(obj){
!all(c(obj$yaxis,obj$xaxis, obj$fill,obj$group) %in% colnames(obj$data))
}
if(check(obj)) return()
obj
})
p <- reactive({
plot.obj<-get_data()
#conditions for plotting
if(is.null(plot.obj)) return()
#make sure variable and group have loaded
if(plot.obj$yaxis == "" | plot.obj$xaxis =="" | plot.obj$fill ==""| plot.obj$group =="") return()
#plot types
plot.type<-switch(input$plot.type,
"boxplot" = geom_boxplot(),
"histogram" = geom_histogram(alpha=0.5,position="identity"),
"density" = geom_density(alpha=.75),
"bar" = geom_bar(position="dodge")
)
if(input$plot.type=="boxplot") { #control for 1D or 2D graphs
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
y = plot.obj$yaxis,
fill = plot.obj$fill,# let type determine plotting
group = plot.obj$group
)
) + plot.type
if(input$show.points==TRUE)
{
p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
}
} else {
p<-ggplot(plot.obj$data,
aes_string(
x = plot.obj$xaxis,
fill = plot.obj$fill,
group = plot.obj$group
#color = as.factor(plot.obj$group)
)
) + plot.type
}
p<-p+labs(
fill = input$fill,
x = "",
y = input$yaxis
) +
.theme
print(p)
})
#plotting function using ggplot2
output$p <- renderPlot({
p()
})
# set uploaded file
upload_data<-reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
#could also store in a reactiveValues
read_excel(inFile$datapath)
})
observeEvent(input$file1,{
inFile<<-upload_data()
})
# downloadHandler contains 2 arguments as functions, namely filename, content
output$down <- downloadHandler(
filename = function() {
paste(input$dataset,"png" , sep=".")
},
# content is a function with argument file. content writes the plot to the device
content = function(file) {
ggsave(file, p())
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
Related
I want to adapt this code to be able to choose which plot I want to download in pdf format. I have tried to assign the plot to an object called "p1" for plot1 and "p2" for plot2 and then call the objects in each condition but it doesn't work.
The only way it works is as it is now that I put the complete function of the plot, but I can't choose which of the two.
I also want to put the download button inside the sidebarPanel but then it stops working. How can I make it to be in the sidebar?
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel("Download base plot in Shiny - an example"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "var1", label = "Select the X variable", choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4)),
selectInput(inputId = "var2", label = "Select the Y variable", choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4), selected = 2),
radioButtons(inputId = "var3", label = "Select the plot", choices = list("plot1", "plot2"))
),
mainPanel(
plotOutput("plot"),
plotOutput("plot2"),
downloadButton(outputId = "down", label = "Download the plot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# x contains all the observations of the x variable selected by the user. X is a reactive function
x <- reactive({
iris[,as.numeric(input$var1)]
})
# x contains all the observations of the y variable selected by the user. Y is a reactive function
y <- reactive({
iris[,as.numeric(input$var2)]
})
# xl contains the x variable or column name of the iris dataset selected by the user
xl <- reactive({
names(iris[as.numeric(input$var1)])
})
# yl contains the y variable or column name of the iris dataset selected by the user
yl <- reactive({
names(iris[as.numeric(input$var2)])
})
# render the plot so could be used to display the plot in the mainPanel
output$plot <- renderPlot({
plot(x=x(), y=y(), main = "iris dataset plot", xlab = xl(), ylab = yl())
})
# render the plot so could be used to display the plot in the mainPanel
output$plot2 <- renderPlot({
plot(x=x(), y=y(), main = "iris plot 2", xlab = xl(), ylab = yl(), col = "blue")
})
# downloadHandler contains 2 arguments as functions, namely filename, content
output$down <- downloadHandler(
filename = function() {
paste("iris", input$var3, sep=".")
},
# content is a function with argument file. content writes the plot to the device
content = function(file) {
if(input$var3 == "plot1")
pdf(file) # open the png device
# if(input$var3 == "png2")
# pdf(file)
else
pdf(file) # open the pdf device
plot(x=x(), y=y(), main = "iris dataset plot", xlab = xl(), ylab = yl())
dev.off() # turn the device off
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
You can use recordPlot() to put the plot in an object and replayPlot() in an opened device:
library(shiny)
# Define UI
ui <- fluidPage(
titlePanel("Download base plot in Shiny - an example"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "var1", label = "Select the X variable",
choices = c(
"Sepal.Length" = 1,
"Sepal.Width" = 2,
"Petal.Length" = 3,
"Petal.Width" = 4
)
),
selectInput(
inputId = "var2", label = "Select the Y variable",
choices = c(
"Sepal.Length" = 1,
"Sepal.Width" = 2,
"Petal.Length" = 3,
"Petal.Width" = 4
),
selected = 2
),
radioButtons(
inputId = "var3", label = "Select the plot",
choices = list("plot1", "plot2")
)
),
mainPanel(
plotOutput("plot"),
plotOutput("plot2"),
downloadButton(outputId = "down", label = "Download the plot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# x contains all the observations of the x variable selected by the user. X is a reactive function
x <- reactive({
iris[, as.numeric(input$var1)]
})
# x contains all the observations of the y variable selected by the user. Y is a reactive function
y <- reactive({
iris[, as.numeric(input$var2)]
})
# xl contains the x variable or column name of the iris dataset selected by the user
xl <- reactive({
names(iris[as.numeric(input$var1)])
})
# yl contains the y variable or column name of the iris dataset selected by the user
yl <- reactive({
names(iris[as.numeric(input$var2)])
})
Plot1 <- reactive({
plot(
x=x(), y=y(), main = "iris dataset plot", xlab = xl(), ylab = yl()
)
recordPlot()
})
Plot2 <- reactive({
plot(
x=x(), y=y(), main = "iris plot 2", xlab = xl(), ylab = yl(), col = "blue"
)
recordPlot()
})
# render the plot so could be used to display the plot in the mainPanel
output$plot <- renderPlot({
Plot1()
})
# render the plot so could be used to display the plot in the mainPanel
output$plot2 <- renderPlot({
Plot2()
})
# downloadHandler contains 2 arguments as functions, namely filename, content
output$down <- downloadHandler(
filename = function() {
paste("iris", input$var3, "pdf", sep=".")
},
# content is a function with argument file. content writes the plot to the device
content = function(file) {
if(input$var3 == "plot1"){
pdf(file)
replayPlot(Plot1())
dev.off()
}else{
pdf(file)
replayPlot(Plot2())
dev.off()
}
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
I am currently trying to make an interactive app on shiny where with my data frame "keep_df" you can choose which kind of plot you want to use and for the x and y axes you can choose any of the columns from keep_df. Below is my code. I'm not getting any error messages, but the code is not running as desired. I was wondering if anyone had any suggestions. Thanks!
ui <- navbarPage ("Title",
tabPanel("Chart builder",
sidebarLayout(
sidebarPanel(
pickerInput(inputId = 'chart', label = '1. Select chart type', choices = c("Scatter plot", "Bar chart", "Histogram", "Pie chart", "Box plot"), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'xaxis', label = '2. Select X-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'yaxis', label = '3. Select Y-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE),
uiOutput("picker2"),
actionButton("view", "View selection"),
),
mainPanel(ui <- DT::dataTableOutput("charttable"), plotOutput("plots")),
)
)
)
server <- function(input, output, session) {
data <- reactive(
keep_df
)
plots <- reactive({
if (input$chart == 'Scatter plot') {
ggplot(data(), aes(x = input$xaxis, y = input$yaxis)) +
geom_point(colour = "black")
}
if (input$chart == 'Bar chart') {
ggplot(data(), aes(x = input$xaxis, y = input$yaxis)) +
geom_point(colour = "black")
}
})
output$plots <- renderPlot(
plots()
)
}
You were pretty close with your code, I noticed a few issues. First, you have an extra ui <- which I could see causing an error. Second, in the plots reactive, where you had x = input$xaxis, it would send a string to the ggplot, rather than a variable. Meaning it wouldn't read the column. I also made the plots reactive as an if and else if, rather than two if statements. Hope this helps!
Note that I didn't have the dataframe, so I just used mtcars for simplicity. There were a few lines I blocked out too. I also added the library and the shinyApp call too, since it wasn't in your example.
library(shiny)
library(ggplot2)
library(shinyWidgets)
keep_df<-mtcars #Don't have the data, just using mtcars
ui <- navbarPage ("Title",
tabPanel("Chart builder",
sidebarLayout(
sidebarPanel(
pickerInput(inputId = 'chart', label = '1. Select chart type', choices = c("Scatter plot", "Bar chart", "Histogram", "Pie chart", "Box plot"), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'xaxis', label = '2. Select X-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE),
pickerInput(inputId = 'yaxis', label = '3. Select Y-axis', choices = colnames(keep_df), selected = NULL, multiple = FALSE)#,
# uiOutput("picker2"), #Not doing anything
# actionButton("view", "View selection") #Not doing anything
),
mainPanel(DT::dataTableOutput("charttable"), plotOutput("plots")), #Removed the ui <-
)
)
)
server <- function(input, output, session) {
data <- reactive(
keep_df
)
plots <- reactive({
if (input$chart == 'Scatter plot') {
#without the eval(parse(text =)), it reads as string, not variable
ggplot(data(), aes(x = eval(parse(text = input$xaxis)), y = eval(parse(text = input$yaxis)))) +
geom_point(colour = "black")
} else if (input$chart == 'Bar chart') {
ggplot(data(), aes(x = eval(parse(text = input$xaxis)), y = eval(parse(text = input$yaxis)))) +
geom_boxplot(colour = "black")
}
})
output$plots <- renderPlot(
plots()
)
}
shinyApp(ui, server)
I am building a shiny app that would allow me to select a data file using a widget "choose file" and "select file" as well as plotting a bar graph using geom_bar object of the library ggplot2. The plot consists of a bar graph representing the revenue ("Revenue") per type of operation ("Type") and has a different colour of the bar for each type.
When I run the app I get the following error : Error in FUN: object 'Type' not found.
I have changed aes by aes_string but it doesn't change anything. I have also tried to add inherit.aes = FALSE in the geom_bar object. I made sure the data I use is saved as data frame.
library(shiny)
library(ggplot2)
library(dplyr)
#user interface
ui <- fluidPage(
headerPanel(title = "Shiny File Upload"),
sidebarLayout(
sidebarPanel(
fileInput(inputId = "file",
label = "Upload the file",
multiple = TRUE),
checkboxInput(inputId = "header", label = "Header"),
radioButtons("sep","Seperator", choices = c(Comma=",", Period = ".", Semicolon = ";")),
# Select variable for y-axis
selectInput(inputId = "y",
label = "Revenue:",
choices = "Revenue",
selected = ""),
# Select variable for x-axis
selectInput(inputId = "x",
label = "X-axis:",
choices = "Type",
selected = ""),
# Select variable for color
selectInput(inputId = "z",
label = "Color by:",
choices = "Type",
selected = "")
),
# Outputs
mainPanel(
uiOutput("input_file"),
plotOutput(outputId = "Barplot")
)
)
)
# Define server function required to create the scatterplot
server <- function(input, output) {
#Dispays the content of the input$file dataframe
output$filedf <- renderTable({
if(is.null(input$file)){return()}
input$file
})
output$filedf2 <- renderTable({
if(is.null(input$file)){return()}
input$file$datapath
})
#Side bar select input widget coming through render UI()
output$selectfile <- renderUI({
if(is.null(input$file)){return()}
list(hr(),
helpText("Select the files for which you need to see data and summary stats"),
selectInput("Select", "Select", choices=input$file$name)
)
})
# Create the scatterplot object the plotOutput function is expecting
output$Barplot <- renderPlot({
ggplot(data = input$file, aes_string(x = input$x , y = input$y, fill = input$x)) + geom_bar( stat ="identity") + coord_flip()
})
}
shinyApp(ui = ui, server = server)
I expect to have a bar plot with revenues bar for the 14 type of operation, with bar color differing depending on the observation.
I expect to be able to select the data I want and get this bar plot for this dataset.
I am still learning Shiny and R and feel it is a sea where I still need to learn quite a lot. Please excuse me if my method of coding is not ideal and do suggest where the code can be improvised.
I am creating this app where I need to generate cross tabs and charts. I need to filter my data basis variable selected by the user and based on that the tables and charts need to get updated.
So for example if user selects "Store_location" as the filter variable, I want to display the list of values for this variable below it with check box, so
loc1
loc2
loc3
loc4
should get displayed with checkbox, and user can select single / multiple of these values. Basis this my data should get filtered. So if user selects loc1 and loc2, data should get filtered based on the condition (Store_location == "loc1" | Store_location == "loc2")
Once the user unchecks a checkbox OR selects a different variable for filter, accordingly the data should get updated and the crosstabs and charts. I believe this should be possible to be done in Shiny, I was trying to use checkboxGroupInput but not able pass the variable selected and hence getting errors. Currently have commented this so that the code runs. I have created a sample data which is in CSV format and is been read in the app. Data is huge and hence using data.table fread to read the data. So any sub-setting would need to be done in data.table. I do some reformatting / creating of variables when the button "Prepare data for Analysis" is clicked. For this I am using the observeEvent({}) and all my renderTable / renderplot are inside this event. I feel there would be a better way to handle this. If yes do suggest.
Finally, my downloader is giving me error, "only 'grobs' allowed in "gList"" and sometimes error like "replacement has 17 rows, data has 0". I want generate a pdf file with the crosstabs and plot one below the other. Do suggest where I am going wrong.
Sample data can be found here - sample data
Below is the code snippet for my app -
library("shiny")
library("shinythemes")
library("tools")
library("readxl")
library("data.table")
library("bit64")
library("gmodels")
library("ggplot2")
library("plotly")
library("gridExtra")
### User Interface
ui <- shinyUI(
navbarPage('My Shiny App',
tabPanel("Insights",
sidebarPanel(
fileInput('file1', 'Choose input data',
accept=c('text/csv', 'text/comma-separated-values,text/plain', '.csv')),
tags$hr(),
actionButton(inputId = 'run1', label = "Prepare data for Analysis"),
tags$br(),
tags$br(),
fluidRow(
column(10,
div(style = "font-size: 13px;", selectInput("filtervar", label = "Select Filter Variable", ''))
),
tags$br(),
tags$br(),
wellPanel(
# checkboxGroupInput("filteroptions", "Filter Options", choices = sort(unique(fil)))
),
column(10,
div(style = "font-size: 13px;", selectInput("rowvar", label = "Select Row Variable", ''))
),
tags$br(),
tags$br(),
column(10,
div(style = "font-size: 13px;", selectInput("columnvar", "Select Column Variable", ''))
)),
downloadButton('export',"Download Outputs")
)
,
mainPanel(
tabsetPanel(id='mytabs',
tabPanel("Data", tags$b(tags$br("Below is the top 6 rows of the data prepared" )),tags$br(),tableOutput("table.output")),
tabPanel("Table",tags$b(tags$br("Table Summary" )),tags$br(),tableOutput("crosstab1"),tags$br(),verbatimTextOutput("datatab1")),
tabPanel("Chart",tags$b(tags$br("Graphical Output" )),tags$br(),plotlyOutput("plot1"))
)
)),
tabPanel("Help")
))
server <- shinyServer(function(input, output,session){
#Below code is to increase the file upload size
options(shiny.maxRequestSize=1000*1024^2)
observeEvent(input$run1,{
updateTabsetPanel(session = session
,inputId = 'myTabs')
inFile <- input$file1
if (is.null(inFile))
return(NULL)
data_input <- fread(inFile$datapath)
data_input[,`:=` (YN2014 = ifelse(Year == "Y2014",1,0),YN2015 = ifelse(Year == "Y2015",1,0))]
## vals will contain all plot and table grobs
vals <- reactiveValues(t1=NULL,t2=NULL,t3=NULL,p1=NULL,p2=NULL)
output$table.output <- renderTable({
# top6rows
head(data_input)
})
s <- reactive(
data_input
)
observe({
updateSelectInput(session, "rowvar", choices = (as.character(colnames(data_input))),selected = "Store_location")
})
observe({
updateSelectInput(session, "columnvar", choices = (as.character(colnames(data_input))),selected = "Year")
})
observe({
updateSelectInput(session, "filtervar", choices = (as.character(colnames(data_input))),selected = "Store_location")
})
output$conditionalInput <- renderUI({
if(input$checkbox){
selectInput("typeInput", "Product type",
choices = sort(unique(input$filtervar)))
}
})
output$crosstab1 <- renderTable({
validate(need(input$rowvar,''),
need(input$columnvar,''))
vals$t1 <- addmargins(xtabs(as.formula(paste0("~",input$rowvar,"+",input$columnvar)), s()))
},caption = "<b>Cross-Tab - 1</b>",
caption.placement = getOption("xtable.caption.placement", "top"),
caption.width = getOption("xtable.caption.width", 200))
output$datatab1 <- renderPrint({
validate(need(input$rowvar,''),
need(input$columnvar,''))
vals$t2 <- as.data.frame(with(s(), CrossTable(get(input$rowvar),get(input$columnvar),max.width = 1,prop.c = T,prop.r = F,prop.t = F,prop.chisq = F,chisq = F,format = "SPSS",dnn = c(input$rowvar,input$columnvar))))
})
#plotting theme
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
output$plot1 <- renderPlotly({
vals$p1 <- ggplot(data_input, aes(get(input$rowvar), ..count..)) +
geom_bar(aes(fill = get(input$columnvar)), position = "dodge") +
theme(axis.text.x=element_text(angle=90, hjust=1),
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()) +
xlab(input$rowvar) +
ylab("Frequency") +
labs(fill=input$columnvar)
})
## clicking on the export button will generate a pdf file
## containing all grobs
output$export = downloadHandler(
filename = function() {paste0("RES_Insights_Outputs_",Sys.Date(),".pdf")},
content = function(file) {
pdf(file, onefile = TRUE)
grid.arrange(vals$t1,vals$p1)
dev.off()
}
)
})
})
shinyApp(ui = ui, server = server)
So to summarize, need to your help to run this app for -
Dynamic display of values for the filter variable selected and filter the data so that crosstabs and plots get updated. Note data is big and in data.table
Downloader to download the outputs in pdf format.
Thank you!!
Here is a way to subset your data frame in function of selected values for the desired column.
I didn't really understand what you wanted to do with the row and column select input though.
ui <- navbarPage("My Shiny App",
tabPanel("Insights",
sidebarPanel(
fileInput("file1", "Choose input data"),
selectInput("filtervar", "Select Filter Variable", NULL),
checkboxGroupInput("filteroptions", "Filter Options", NULL)
),
mainPanel(
tabsetPanel(id = "mytabs",
tabPanel("Data", tableOutput("table.output"))
)
)
)
)
server <- function(input, output,session) {
values <- reactiveValues()
observe({
file <- input$file1
if (is.null(file))
return()
values$data <- fread(file$datapath)
vars <- names(values$data)
updateSelectInput(session, "filtervar", choices = vars)
})
observe({
data <- isolate(values$data)
filter.var <- input$filtervar
if (is.null(filter.var) || filter.var == "")
return()
values <- data[[filter.var]]
if (is.factor(values)) {
options <- levels(values)
} else {
options <- unique(values[order(values)])
}
updateCheckboxGroupInput(session, "filteroptions",
choices = options,
selected = as.character(options))
})
output$table.output <- renderTable({
isolate({
data <- values$data
var <- input$filtervar
})
values <- input$filteroptions
if(is.null(data)) {
return()
} else if (is.null(var) || var == "") {
return(data)
} else if (is.null(values)) {
return(data[FALSE])
} else {
if (is.numeric(data[[var]]))
values <- as.numeric(values)
setkeyv(data, var)
return(data[.(values)])
}
})
}
shinyApp(ui = ui, server = server)
Shiny newbie here.
I am trying to write a R shiny script, and one of things I want to do is generate various plots.
I have a written this code for plotting by taking input from user but getting error of
Error in exists(name, envir = env, mode = mode) :
argument "env" is missing, with no default
Need Help to solve this
I am uploading my server and ui code.
Server.r
shinyServer(function(input,output){
data<-reactive({
file1<-input$file
if(is.null(file1)){return()}
read.table(file=file1$datapath,sep = input$sep,header = input$header,stringsAsFactors = input$stringAsFactors)
})
output$variable <- renderUI({
obj<-data()
if (is.null(obj))
return(NULL)
var.opts<-namel(colnames(obj))
selectInput("variable","Variable:", var.opts)
})
# y variable
output$group <- renderUI({
obj<-data()
if (is.null(obj))
return(NULL)
var.opts<-namel(colnames(obj))
selectInput("group","Groups:", var.opts)
})
#caption
output$caption<-renderText({
switch(input$plot.type,
"boxplot" = "Boxplot",
"histogram" = "Histogram",
"density" = "Density plot",
"bar" = "Bar graph")
})
#plot
output$plot <- renderUI({
plotOutput("p")
})
#plotting function using ggplot2
output$p <- renderPlot({
obj<-data()
plot.type<-switch(input$plot.type,
"boxplot" = geom_boxplot(),
"histogram" = geom_histogram(alpha=0.5,position="identity"),
"density" = geom_density(alpha=.75),
"bar" = geom_bar(position="dodge")
)
require(ggplot2)
#plotting theme
.theme<- theme(
axis.line = element_line(colour = 'gray', size = .75),
panel.background = element_blank(),
plot.background = element_blank()
)
if(input$plot.type=="boxplot") { #control for 1D or 2D graphs
p<-ggplot(data=obj,
aes(
x = obj$group,
y = obj$variable,
fill = as.factor(obj$group)
)
) + plot.type
if(input$show.points==TRUE)
{
p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
}
} else {
p<-ggplot(data=obj,
aes(
x = obj$variable,
fill = as.factor(obj$group),
group = as.factor(obj$group)
#color = as.factor(plot.obj$group)
)
) + plot.type
}
p<-p+labs(
fill = input$group,
x = "",
y = input$variable
) +
.theme
print(p)
})
})
ui.R
shinyUI(fluidPage(
#Heading panel
titlePanel(title="Machine Learning and Statistics",),
#input data set
sidebarLayout(position = "right",
sidebarPanel(fileInput('file', 'Choose a File', multiple = T, accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
#default size for dataset
helpText("Default max. size is 7mb"),
#input number of observations
numericInput("obs", "Number of observations to view:", 10),
tags$hr(),
checkboxInput(inputId = 'header',label = 'Header',value = TRUE),
checkboxInput(inputId = "stringAsFactors","stringAsFactors",TRUE),
br(),
radioButtons(inputId = 'sep',label = 'Seprator',choices=c(comma=',',Semicolon=';',Tab='\t',Space=' '),selected = ','),
sliderInput("train_percent",
"Training Percentage:",
min = 10, max = 90,
value = 20, step = 10),
uiOutput("variable"), # depends on dataset ( set by output$variable in server.R)
uiOutput("group"), # depends on dataset ( set by output$group in server.R)
selectInput("plot.type","Plot Type:",
list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
),
checkboxInput("show.points", "show points", TRUE)
),
mainPanel(
("output"),
h3(textOutput("caption")),
uiOutput("plot")
)
)))
Help?Thanks.
My solution to this error message when using ggplot in Shiny is:
ggplot(data = obj, aes(...), environment = environment())
Would appreciate if someone could explain the reason behind the extra need for this in a Shiny app.