Shiny allow users to choose which plot outputs to display - r

I have a shiny app and my server function looks like this:
shinyServer(function(input, output, session) {
filedata <- reactive({
infile <- input$file1
if (is.null(infile)) {
return(NULL)
}
myDF <- fread(infile$datapath)
return(myDF)
# Return the requested graph
graphInput <- reactive({
switch(input$graph,
"Plot1" = plot1,
"Plot2" = plot2)
})
output$selected_graph <- renderPlot({
paste(input$graph)
})
output$plot1 <- renderPlot({
#fill in code to create a plot1
})
output$plot2 <- renderPlot({
#fill in code to create plot2
})
The UI function looks like this:
shinyUI(pageWithSidebar(
headerPanel("CSV Viewer"),
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv', 'text/comma-separated-values,text/plain', '.csv')),
selectInput("graph", "Choose a graph to view:",
choices = c("Plot1", "Plot2"))
submitButton("Update View")
),#end of sidebar panel
mainPanel(
tabsetPanel(
tabPanel("Graph Viewer", plotOutput("selected_graph"))
)
I can't make the selected plot display on the screen. When I make a selection from the drop-down menu and click the "Update View" button the app does not display the plot. It does not display an error message. It displays nothing at all.
How can I fix this?

As mentioned in the comments, it's difficult to ensure that any answer will work, given the incomplete example in your question. Based on the skeleton server provided, however, this pattern for selecting a graph should work:
shinyServer(function(input, output, session) {
filedata <- reactive({
# Haven't tested that this will read in data correctly;
# assuming it does
infile <- input$file1
if (is.null(infile)) {
return(NULL)
}
myDF <- fread(infile$datapath)
return(myDF)
})
plot1 <- reactive({
# this should be a complete plot image,
# e.g. ggplot(data, aes(x=x, y=y)) + geom_line()
})
plot2 <- reactive({
# this should be a complete plot image,
# e.g. ggplot(data, aes(x=x, y=y)) + geom_line()
})
# Return the requested graph
graphInput <- reactive({
switch(input$graph,
"Plot1" = plot1(),
"Plot2" = plot2()
)
})
output$selected_graph <- renderPlot({
graphInput()
})
}
What changed:
plot1 and plot2 are reactive functions (and not outputs) that can be returned from the graphInput reactive function
graphInput returns the value (i.e. plot) of either plot1 or plot2 into output$selected_graph

Related

how to replace plot by another one or even just under it based on plot clik in R shiny? [duplicate]

In my app, I want plot1 to display by default, and then if an action button is clicked, have plot2 replace plot1. If it is clicked again, revert to plot1, and so on.
server <- function(input, output, session) {
plot1 <- (defined here)
plot2 <- (defined here)
which_graph <- reactive({
if (input$actionbutton == 1) return(plot1)
if (input$actionbutton == 2) return(plot2)
})
output$plot <- renderPlot({
which_graph()
})
}
You can create a reactiveValue and use an actioButton to toggle that value. For example
library(shiny)
ui <- fluidPage(
plotOutput("plot"),
actionButton("button", "Click")
)
server <- function(input, output, session) {
whichplot <- reactiveVal(TRUE)
plot1 <- ggplot(mtcars) + aes(mpg, cyl) + geom_point()
plot2 <- ggplot(mtcars) + aes(hp, disp) + geom_point()
observeEvent(input$button, {
whichplot(!whichplot())
})
which_graph <- reactive({
if (whichplot()) {
plot1
} else {
plot2
}
})
output$plot <- renderPlot({
which_graph()
})
}
shinyApp(ui, server)
Here whichplot starts off as TRUE and then evertime you press the actionButton it toggles between TRUE/FALSE. This way you are not changing the value of the actionButton; you are just updating state each time it's pressed.
If your plots need any input from the user, you can make them reactive as well
ui <- fluidPage(
selectInput("column", "Column", choices=names(mtcars)),
plotOutput("plot"),
actionButton("button", "Click")
)
server <- function(input, output, session) {
whichplot <- reactiveVal(TRUE)
plot1 <- reactive({ggplot(mtcars) + aes(mpg, .data[[input$column]]) + geom_point()})
plot2 <- reactive({ggplot(mtcars) + aes(.data[[input$column]], disp) + geom_point()})
observeEvent(input$button, {
whichplot(!whichplot())
})
which_graph <- reactive({
if (whichplot()) {
plot1()
} else {
plot2()
}
})
output$plot <- renderPlot({
which_graph()
})
}

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.

attempt to apply non-function

I'm trying to build a simple application that draws a histogram of a selected variable based on a subset filtered by the other input. I get the error in the line hist(dataX()$datasetInput()) which should return dataX$mpg. How can I fix it?
Full code:
library(shiny)
u <- shinyUI(pageWithSidebar(
headerPanel("Staz w bezrobociu"),
sidebarPanel(
selectInput("variable", "Variable:",
list("Milles/gallon",
"Horse power")
),
textInput("nc","Number of cylinders",value = 6)
),
mainPanel(
plotOutput("Plot")
)
))
s <- shinyServer(function(input, output)
{
dataX <- reactive({mtcars[mtcars$cyl==input$nc,,drop = FALSE]})
datasetInput <- reactive({
switch(input$variable,
"Milles/gallon" = mpg,
"Horse power" = hp)
})
output$Plot <- renderPlot({
hist(dataX()$datasetInput())
})
})
shinyApp(u,s)
You complicated the simple app.
You do not need to list all the columns in selectInput. You can just render it from the server side.
Same applies to the cylinders
Shortcuts like u and sare acceptable, but just stick to the naming conventions. It makes your life easy.
Below is a complete working app
library(shiny)
ui <- shinyUI(pageWithSidebar(
headerPanel("Staz w bezrobociu"),
sidebarPanel(uiOutput("SelectColname"),
uiOutput("Cylinders")),
mainPanel(plotOutput("Plot"))
))
server <- shinyServer(function(input, output){
# Create a reactive dataset
dataX <- reactive({
mtcars
})
# Output number cylinders as select box
output$Cylinders <- renderUI({
selectInput("cylinders", "cylinders:", unique(dataX()$cyl))
})
# Output column names as selectbox
output$SelectColname <- renderUI({
selectInput("variable", "Variable:", colnames(dataX()[,c(1,4)]))
})
# Based on the selection by user, create an eventreactive plotdata object
plotdata <- eventReactive(input$cylinders, {
plotdata = dataX()[dataX()$cyl == input$cylinders, , drop = FALSE]
})
# Render the plot, the plot changes when new cylinder is selected
output$Plot <- renderPlot({
if (is.null(plotdata()))
return(NULL)
hist(
plotdata()[, input$variable],
xlab = input$variable,
main = paste(
"Histogram of" ,
input$variable
)
)
})
})
shinyApp(ui, server)

Reactive function shiny+ggplot2 in shiny error

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

How to enable user to switch between ggplot2 and gVis graphs in R Shiny?

I'm making an app that allows the user to upload any csv file and the app will graph it. I'd like to allow the user to switch between graph styles, gVis and ggplot. The graphs work as implemented by themselves, but I can't seem to figure out how to enable the user to switch them with a checkboxInput (input$switchLine). I'll post only the sample code relative to the problem at hand, let me know if you need more info.
I've tried things like in server:
if (input$switchLine) {
output$gvisLine
} else {
output$plotLine
}
But the problem is that in the ui.R, ggplot line uses plotOutput while gVis uses html Output.
ui.R (I've commented out the gVis line as I only know how to plot one at a time right now)
library(shiny)
dataset <- list('Upload a file'=c(1))
shinyUI(pageWithSidebar(
headerPanel(''),
sidebarPanel(
wellPanel(
selectInput('xLine', 'X', names(dataset)),
selectInput('yLine', 'Y', names(dataset), multiple=T)
),
wellPanel(
checkboxInput('switchLine', 'Switch to gVis')
)
),
mainPanel(
tabPanel("Line Graph", plotOutput('plotLine', height="auto"), value="line"),
#Below is the gvis Line
#tabPanel("Line Graph", htmlOutput("gvisLine"), value="line")
)
))
server.R
library(reshape2)
library(googleVis)
library(ggplot2)
library(plyr)
library(scales)
require(xlsx)
require(xlsxjars)
require(rJava)
require(shiny)
options(shiny.maxRequestSize=-1)
shinyServer(function(input, output, session) {
if (is.null(input$file))
return(NULL)
else if (identical(input$format, 'CSV'))
return(read.csv(input$file$datapath))
else if (identical(input$format, 'XLSX'))
return(read.xlsx2(input$file$datapath, input$sheet))
else
return(read.delim(input$file$datapath))
})
observe({
df <- data()
str(names(df))
updateSelectInput(session, 'xLine', choices = names(df))
updateSelectInput(session, 'yLine', choices = names(df))
}
})
output$gvisLine<- renderGvis( {
tempX <- input$xLine
tempY <- input$yLine
if (is.null(data()))
return(NULL)
if (is.null(tempY))
return(NULL)
gvisLineChart(data(),xvar=tempX,yvar=tempY,
options=list(
title=paste("",tempX," VS ",tempY,""),
titlePosition='out',
hAxis="{slantedText:'true',slantedTextAngle:45}",
titleTextStyle="{color:'black',fontName:'Courier'}",
legend="{color:'black',fontName:'Courier'}",
fontSize="10",
chartArea="{left:40,top:30,width:'90%',height:'85%'}",
height=700, width=1100))
})
output$plotLine <- renderPlot(height=650, units="px", {
tempX <- input$xLine
tempY <- input$yLine
if (is.null(data()))
return(NULL)
if (is.null(tempY))
return(NULL)
widedata <- subset(data(), select = c(tempX, tempY))
melted <- melt(widedata, id = tempX)
p <- ggplot(melted, aes_string(x=names(melted)[1], y="value", group="variable", color="variable")) + geom_line() + geom_point()
p <- p + opts(axis.text.x=theme_text(angle=45, hjust=1, vjust=1))
p <- p + labs(title=paste("",tempX," VS ",tempY,""))
print(p)
})
})
Use
conditionalPanel(
condition = "input.switchLine == false",
plotOutput('plotLine', height="auto")
),
conditionalPanel(
condition = "input.switchLine == true",
htmlOutput("gvisLine")
)
or something similar in ui.R

Resources