modularize Shiny app: CSV and Chart modules - r

I want to create a modularized Shiny app where one module, dataUpload, is used to import a CSV and another module, chart, is used to
Create dynamic x and y dropdowns based on the column names within the CSV THIS WORKS
Create a plot based on the selected input$xaxis, input$yaxis This produces the error invalid type/length (symbol/0) in vector allocation
I think the issue is with my reactive ggplot in chart.R and I'd love any help - I added all the info here but I also have a github repo if that's easier I think this could be a really great demo into the world of interacting modules so I'd really appreciate any help!!
App.R
library(shiny)
library(shinyjs)
library(tidyverse)
source("global.R")
ui <-
tagList(
navbarPage(
"TWO MODULES",
tabPanel(
title = "Data",
dataUploadUI("datafile", "Import CSV")
),
tabPanel(
title = "Charts",
chartUI("my_chart")
)
)
)
server <- function(input, output, session) {
datafile <- callModule(dataUpload, "datafile", stringsAsFactors = FALSE)
output$table <- renderTable({ datafile() })
# PASS datafile WITHOUT () INTO THE MODULE
my_chart <- callModule(chart, "my_chart", datafile = datafile)
output$plot <- renderPlot({ my_chart() })
}
shinyApp(ui, server)
dataUpload.R
dataUpload <- function(input, output, session, stringsAsFactors) {
# The selected file, if any
userFile <- reactive({
# If no file is selected, don't do anything
# input$file == ns("file")
validate(need(input$file, message = FALSE))
input$file
})
# The user's data, parsed into a data frame
dataframe <- reactive({
read.csv(userFile()$datapath,
stringsAsFactors = stringsAsFactors)
})
# We can run observers in here if we want to
observe({
msg <- sprintf("File %s was uploaded", userFile()$name)
cat(msg, "\n")
})
# Return the reactive that yields the data frame
return(dataframe)
}
dataUploadUI.R
# The first argument is the id -- the namespace for the module
dataUploadUI <- function(id, label = "CSV file") {
# Create a namespace function using the provided id
#ALL UI FUNCTION BODIES MUST BEGIN WITH THIS
ns <- NS(id)
# Rather than fluidPage use a taglist
# If you're just returning a div you can skip the taglist
tagList(
sidebarPanel(
fileInput(ns("file"), label)),
mainPanel(tableOutput("table"))
)
}
chart.R
I believe this is the file that needs some minor changing in order to have the plot properly render?
chart <- function(input, output, session, datafile = reactive(NULL)) {
# SINCE DATAFILE IS A REACTIVE WE ADD THE PRERENTHESIS HERE
# WHERE/HOW CAN I ACCESS input$xaxis?
# Do I need to use ns? Can you do that in the server side of a module?
output$XAXIS <- renderUI(selectInput("xaxis", "X Axis", choices = colnames(datafile())))
output$YAXIS <- renderUI(selectInput("yaxis", "Y Axis", choices = colnames(datafile())))
# NOT WORKING
# Use the selectInput x and y to plot
p <- reactive({
req(datafile)
# WORKS: ggplot(datafile(), aes(x = Sepal_Length, y = Sepal_Width))
# DOES NOT WORK:
ggplot(datafile(), aes_(x = as.name(input$xaxis), y = as.name(input$yaxis))) +
geom_point()
})
return(p)
}
chartUI.R
chartUI <- function(id, label = "Create Chart") {
ns <- NS(id)
tagList(
sidebarPanel(
uiOutput(ns("XAXIS")),
uiOutput(ns("YAXIS"))
),
mainPanel(plotOutput("plot"))
)
}

We need to manually specify the name space within a renderUI function using session$ns
chart <- function(input, output, session, datafile = reactive(NULL)) {
# SINCE DATAFILE IS A REACTIVE WE ADD THE PRERENTHESIS HERE
# WHERE/HOW CAN I ACCESS input$xaxis?
# Do I need to use ns? Can you do that in the server side of a module?
output$XAXIS <- renderUI(selectInput(session$ns("xaxis"), "X Axis", choices = colnames(datafile())))
output$YAXIS <- renderUI(selectInput(session$ns("yaxis"), "Y Axis", choices = colnames(datafile())))
# NOT WORKING
# Use the selectInput x and y to plot
p <- reactive({
req(datafile)
# WORKS: ggplot(datafile(), aes(x = Sepal_Length, y = Sepal_Width))
# DOES NOT WORK:
ggplot(datafile(), aes_(x = as.name(input$xaxis), y = as.name(input$yaxis))) +
geom_point()
})
return(p)
}

Related

Problem in creating a test file for unit testing of Shiny modules using usethis::use_test()

My R shiny app has two modules. The "dataselect" module and the "plot" module. I want to write unit tests for the two modules using testthat package. I am following the instruction in the mastering Shiny book. It has been mentioned in this book that first, we should create a test file using usethis::use_test() in the R console.
But when I run this code, I get the following error:
Error: Open file must be in the 'R' directory of the active package. Actual path: 'app.R'
It might not be needed, but for more information, I put a minimal example of my Shiny app that I want to write the unit tests for its modules:
library(shiny)
library(plotly)
library(reshape2)
#----------------------------------------------------------------------------------------
# Dataselect module
dataselect_ui<- function(id) {
ns<-NS(id)
tagList(
selectInput(ns("Nametype"),"Select a name type",
choices=c("Name1","Name2","choose"),selected = "choose"),
selectInput(ns("Name"),"Select a name",
choices="",selected = "",selectize=TRUE),
DT::DTOutput(ns("tab"))
)
}
dataselect_server <- function(id) {
moduleServer(id, function(input, output, session) {
# Data preparation
df<-data.frame(Name1<-c("Aix galericulata","Grus grus"," Alces alces"),
Name2<-c("Mandarin Duck","Common Crane" ,"Elk"),
eventDate<-c("2015-03-11","2015-03-10","2015-03-10"),
individualCount<-c(1, 10, 1)
)
colnames(df)<-c("Name1","Name2","eventDate","individualCount")
# Putting columns Name1 and Nam2 of df in one column called nameType using melt()function
# This format of data is needed for the choices argument of updateSelectizeInput()
df2<-reshape2::melt(df,id=c("eventDate","individualCount"))
colnames(df2)<-c("eventDate","individualCount","nameType","Name")
observeEvent(
input$Nametype,
updateSelectizeInput(session, "Name", "Select a name",
choices = unique(df2$Name[df2$nameType==input$Nametype]),selected = ""))
# finalDf() is the data used to plot the table and plot
finalDf<-reactive({
if(input$Name=="choose"){
return(NULL)
}
if(input$Name==""){
return(NULL)
}
if(input$Nametype=="choose"){
return(NULL)
}
# if the first selectInput is set to Name1, from df select rows their Name1 column are
# equal to the second selectInput value
else if(input$Nametype=="Name1"){
finalDf<-df[which(df$Name1==input$Name) ,]
}
# if the first selectInput is set to Name2, from df select rows their Name2 column are
# equal to the second selectInput value
else if(input$Nametype=="Name2"){
finalDf<-df[which(df$Name2==input$Name) ,]
}
return(finalDf)
})
output$tab<-DT::renderDT({
req(input$Name)
datatable(finalDf(), filter = 'top',
options = list(pageLength = 5, autoWidth = TRUE),
rownames= FALSE)
})
return(
list("finalDf" = finalDf, "input_Name" = reactive(input$Name))
)
})
}
#--------------------------------------------------------------------------------------
# Plot module
plot_ui <- function(id) {
ns<-NS(id)
tagList(
plotlyOutput(ns("plot"))
)
}
plot_server <- function(id,input_Name ,finalDf) {
moduleServer(id, function(input, output, session) {
output$plot <- renderPlotly({
req(input_Name())
p<-ggplot(finalDf(),aes(x=eventDate,y=individualCount)) +geom_point(alpha=0.2, shape=21, color="black",fill="red",size=5)+
labs( x = "Date Event",y= "Individual Count") +theme_bw()
p<-ggplotly(p)
p
})
})
}
#--------------------------------------------------------------------------------------
# application
ui <- fluidPage(
dataselect_ui("dataselect"),
plot_ui("plot1")
)
server <- function(session,input, output) {
dataselect_outputs <- dataselect_server("dataselect")
plot_server("plot1",input_Name = dataselect_outputs$input_Name
,finalDf= dataselect_outputs$finalDf)
}
shinyApp(ui = ui, server = server)
I appreciate any help everybody can provide.

How can I import 2 datasets, have them persist in my environment, and pass one of the column names as a parameter in my modular plot function?

The Questions
I have revised my code to one file as opposed to being organized in multiple files. I believe that by calling my dataframes I am unable to call them again in another module for some reason, I am unsure why. In addition I am trying to get an already known before importing column name hardcoded as a parameter when calling my plotFactorOfValue_server module.
I have revised the ggplot inside of this module
to work with the mtcars dataframe (using weight factor as the y variable)
1. My mod_plotFactorOfValue_server function does not recognize my
dataset and does not see my parameter (which is a column name in
the dataset)
2. Are my datasetComparables <- mod_import_server("import_1") and
datasetWholeHood <- mod_import_server("import_2") reactive objects
when called like this? Or will they only exist while being called?
3. Is there just a better way to do this? I don't want to have the user selecting the x
variable (that would mean many selectors for each plot(calling plot module 7 times for
different column names). I want to keep this modular, I have tried this without modules,
and the code is way too long and cumbersome.
The Code - Modules - UI - Server
Modules in order for importing data, exporting data table,
and plotting with ggplot (which is where I am having trouble).
mod_import_ui <- function(id){
ns <- NS(id)
tagList(
fileInput(ns("file1"), label = "Choose CSV File", accept = ".csv")
#, checkboxInput(ns("header"), label = "Header", TRUE)
)
}
mod_import_server <- function(id){
moduleServer( id, function(input, output, session){
ns <- session$ns
dtreact <- reactive({
file <- input$file1
if(is.null(file))
return(NULL)
read.csv(file$datapath,
# header = input$header
)
})
# Return the reactive that yields the data frame
return(dtreact)
})
}
```
Module for displaying imported data as a table, this used the dataframe datasetComparables or datasetWholeHood when called.
```
mod_importedDataTable_ui <- function(id){
ns <- NS(id)
tagList(
DTOutput(ns("contents"))
)
}
#' importedDataTable Server Functions----
#'
#' #noRd
mod_importedDataTable_server <- function(id, dataset){
moduleServer( id, function(input, output, session){
ns <- session$ns
output$contents <- renderDT({
req(dataset())
df1 <- dataset()
return(datatable(df1))
})
})
}
```
A shiny Module that uses ggplot to plot a parameter(factorOfValue) from an imported
dataset.The user should NOT be selecting the factor to be plotted.
```
mod_plotFactorOfValue_ui <- function(id){
ns <- NS(id)
tagList(
plotOutput(ns("plotFactorOfValue"))
)
}
NEED HELP HERE CREATE THE FACTOROFVALUE VARIABLE TO PASS THROUGH AS PARAMETER IN THIS
FUNCTION
mod_plotFactorOfValue_server <- function(id, dataset, factorOfValue){
moduleServer( id, function(input, output, session){
ns <- session$ns
output$plotFactorOfValue <- renderPlot({
req(dataset())
mtdf <- dataset()
x <- mtdf[[factorOfValue]]
df2 <- dataset() %>%
ggplot(aes(x, mpg))+
geom_point(aes(color = mpg, size = 1,))+
geom_smooth(method = lm, se = F)+
theme( axis.line = element_line(colour = "darkblue",
size = 1, linetype = "solid"))
return(plot(df2))
})
})
}
```
UI and Server Sections of App
==============
```
ui <- fluidPage(theme = shinytheme("darkly"),
navbarPage(
theme = "cerulean",
"Market Analysis Tool",
# Import Tab----
tabPanel("Import",
sidebarPanel(
tags$h3("Input Comparables Data:"),
mod_import_ui("import_1"),
tags$h3("Input Whole Hood Data:"),
mod_import_ui("import_2")
),
mainPanel(
mod_importedDataTable_ui("importedDataTable_1"),
mod_importedDataTable_ui("importedDataTable_2")
), #main panel Import
), #tab panel import
# Comparables Graphs Tab----
tabPanel("Comparables Graphs",
sidebarPanel(
tags$h3("Check out these trends!"),
),
mainPanel(
mod_plotFactorOfValue_ui("plotFactorOfValue_1")
), #main panel Comparables Graphs
)
) #navbar page
) #fluid page
server <- function(input, output, session) {
####Import the Data----
datasetComparables <- mod_import_server("import_1")
datasetWholeHood <- mod_import_server("import_2")
#### Output the Data Tables----
mod_importedDataTable_server("importedDataTable_1", dataset = dtreact)
mod_importedDataTable_server("importedDataTable_2", dataset = datasetWholeHood)
######## STARTING THE PLOTS HERE----
```
#I am unable to get the dataframe to be recognized, I am also unable to get the
xvariable(factorOfValue) hardcoded as a parameter in my call function.
# Can you please help with this? THis is still part of the server section.
```
mod_plotFactorOfValue_server("plotFactorOfValue_1", dataset = datasetComparables,
factorOfValue = "SqFtTotal")
}
shinyApp(ui = ui, server = server)
```
You don't need to plot a ggplot object. Try this
library(shinythemes)
library(DT)
mod_import_ui <- function(id){
ns <- NS(id)
tagList(
fileInput(ns("file1"), label = "Choose CSV File", accept = ".csv")
#, checkboxInput(ns("header"), label = "Header", TRUE)
)
}
mod_import_server <- function(id){
moduleServer( id, function(input, output, session){
ns <- session$ns
dtreact <- reactive({
file <- input$file1
if(is.null(file))
return(NULL)
read.csv(file$datapath
# header = input$header
)
})
# Return the reactive that yields the data frame
return(dtreact)
})
}
### Module for displaying imported data as a table, this used the dataframe datasetComparables or datasetWholeHood when called.
mod_importedDataTable_ui <- function(id){
ns <- NS(id)
tagList(
DTOutput(ns("contents"))
)
}
mod_importedDataTable_server <- function(id, dataset){
moduleServer( id, function(input, output, session){
ns <- session$ns
output$contents <- renderDT({
req(dataset())
df1 <- dataset()
return(datatable(df1))
})
})
}
# A shiny Module that uses ggplot to plot a parameter(factorOfValue) from an imported
# dataset.The user should NOT be selecting the factor to be plotted.
mod_plotFactorOfValue_ui <- function(id){
ns <- NS(id)
tagList(
plotOutput(ns("plotFactorOfValue"))
)
}
### NEED HELP HERE CREATE THE FACTOROFVALUE VARIABLE TO PASS THROUGH AS PARAMETER IN THIS FUNCTION
mod_plotFactorOfValue_server <- function(id, dataset, factorOfValue){
moduleServer( id, function(input, output, session){
ns <- session$ns
output$plotFactorOfValue <- renderPlot({
req(dataset())
mtdf <- dataset()
x <- mtdf[[factorOfValue]]
df2 <- dataset() %>%
ggplot(aes(x, mpg)) +
geom_point(aes(color = mpg, size = 1))+
geom_smooth(method = lm, se = F)+
theme( axis.line = element_line(colour = "darkblue", size = 1, linetype = "solid"))
return(df2)
})
})
}
# UI and Server Sections of App
ui <- fluidPage(theme = shinytheme("darkly"),
navbarPage(
theme = "cerulean",
"Market Analysis Tool",
# Import Tab----
tabPanel("Import",
sidebarPanel(
tags$h3("Input Comparables Data:"),
mod_import_ui("import_1"),
tags$h3("Input Whole Hood Data:"),
mod_import_ui("import_2")
),
mainPanel(
mod_importedDataTable_ui("importedDataTable_1"),
mod_importedDataTable_ui("importedDataTable_2")
), #main panel Import
), #tab panel import
# Comparables Graphs Tab----
tabPanel("Comparables Graphs",
sidebarPanel(
tags$h3("Check out these trends!")
),
mainPanel(
mod_plotFactorOfValue_ui("plotFactorOfValue_1")
), #main panel Comparables Graphs
)
) #navbar page
) #fluid page
server <- function(input, output, session) {
####Import the Data----
datasetComparables <- mod_import_server("import_1")
datasetWholeHood <- mod_import_server("import_2")
#### Output the Data Tables----
mod_importedDataTable_server("importedDataTable_1", dataset = datasetComparables)
mod_importedDataTable_server("importedDataTable_2", dataset = datasetWholeHood)
######## STARTING THE PLOTS HERE----
# I am unable to get the dataframe to be recognized, I am also unable to get the
# xvariable(factorOfValue) hardcoded as a parameter in my call function.
# Can you please help with this? THis is still part of the server section.
mod_plotFactorOfValue_server("plotFactorOfValue_1", dataset = datasetComparables,
factorOfValue = "cyl" ) ## "SqFtTotal"
}
shinyApp(ui = ui, server = server)

Dynamic number of Plots with reactive data in R Shiny

I am trying to make an RShiny app that you can pick a gene from a list, and it will display different graphs using that gene's transcripts. However, each gene has a different number of transcripts, so a different number of graphs must be displayed every time a different gene is chosen. How I have it set right now is that when a person chooses a gene, a new table is created with the transcript numbers (data to be plotted) along with a new list of all the transcript names (length of this list is the amount of plots that I need). These are reactive values.
Below, in the server, I made a function that creates the graph that I want, and then I iterate through the creation of the function by indexing into the reactive list of names, so it creates a graph for each name (as each name is a different transcript). Right now, the code iterates through all the names correctly but only displays the last plot. Is there a way to have every plot displayed? I have tried a lot of different things, from renderUI to using local calls, but cannot figure it out.
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("var", label = "Choose a gene to display", names),
mainPanel(
plotOutput("tdot"))
))
server <- function(input, output) {
genename <- reactive({
input$var
})
transTable2 <- reactive ({
cbind(biofluids, select(transTable, starts_with(input$var)))
})
names <- reactive ({
tableBF <- cbind(biofluids, select(transTable, starts_with(input$var)))
n <- colnames(tableBF)
final <- n[-1]
})
createUI <- function(name, table) {
ggplot(table, aes_string(x = "biofluids", y = name))+geom_boxplot(aes(color = biofluids))+
geom_boxplot(aes(fill = biofluids)) + scale_y_log10()+ylab( 'log10 normalized counts')+
ggtitle(name)}
output$tdot <- renderPlot({
lapply(1:length(names()), function(i)
createUI(names()[i], transTable2()))
})
}
# Run the application
shinyApp(ui = ui, server = server)
A reproducible example is as follows with the iris dataset, which would have the user select a category (either "Sepal" or "Petal"), and then create a plot for every column in the dataset that starts with that word:
cats <- c("Sepal", "Petal")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("var", label = "Choose a category to display", cats),
mainPanel(
plotOutput("tdot"))
))
server <- function(input, output) {
category <- reactive({
input$var
})
iris2 <- reactive ({
select(iris, starts_with(input$var))
})
names <- reactive ({
table2 <- select(transTable, starts_with(input$var))
n <- colnames(table2)
})
createUI <- function(name, table) {
ggplot(table, aes_string(x = "species", y = name))+geom_boxplot(aes(color = species))+
geom_boxplot(aes(fill = species)) + scale_y_log10()+ylab( 'log10 normalized counts')+
ggtitle(name)}
output$tdot <- renderPlot({
lapply(1:length(names()), function(i)
createUI(names()[i], iris2()))
})
}
# Run the application
shinyApp(ui = ui, server = server)
The following code generates dynamic number of outputs with iris data. You should be able to adapt this to your data.
library(shiny)
library(tidyverse)
# Load data
data("iris")
# Add row id
iris2 <- iris %>% mutate(ID = 1:n())
# ui
ui <- fluidPage(
sidebarPanel(
selectInput(inputId = "sel", label = "Select one or more parameters",
choices = names(iris2), multiple = TRUE)
),
mainPanel(
uiOutput("plots")
)
)
# server
server <- function(input, output, session){
# Dynamically generate the plots based on the selected parameters
observe({
req(input$sel)
lapply(input$sel, function(par){
p <- ggplot(iris2, aes_string(x = "ID", y = par)) +
geom_boxplot(aes(fill = Species, group=Species, color=Species)) +
ggtitle(paste("Plot: ", par))
output[[paste("plot", par, sep = "_")]] <- renderPlot({
p
},
width = 380,
height = 350)
})
})
# Create plot tag list
output$plots <- renderUI({
req(input$sel)
plot_output_list <- lapply(input$sel, function(par) {
plotname <- paste("plot", par, sep = "_")
plotOutput(plotname, height = '250px', inline=TRUE)
})
do.call(tagList, plot_output_list)
})
}
shinyApp(ui, server)
It gives the following output:

Display and save a grid's gtable/gTree/grob/gDesc in a shiny app

I have a function that's arranging a plot in a grid:
plotFunc <- function(a,b)
{
p <- qplot(a,b)
p2 <- xyplot(1~1)
r <- grid::rectGrob(gp=gpar(fill="grey90"))
t <- grid::textGrob("text")
g <- gridExtra::grid.arrange(t, p, p2, r, ncol=2)
return(g)
}
So the return value is:
"gtable" "gTree" "grob" "gDesc"
I want to use a shiny app in order to be able to select a and b values display the resulting plot and also have the option to save it to a file.
Here's my code:
data:
set.seed(1)
vals.df <- data.frame(b=1:6,a=sample(1:2,6,replace=T))
Shiny code:
library(shiny)
library(ggplot2)
library(lattice)
library(SpaDES)
library(devtools)
server <- function(input, output)
{
output$b <- renderUI({
selectInput("b", "B", choices = unique(dplyr::filter(vals.df,a == input$a)$b))
})
my.plot <- reactive({function(){plotFunc(a = input$a,b == input$b)}})
output$plot <- renderPlot({
my.plot()
})
output$save <- downloadHandler(
filename = function() {
paste0(input$a,"_",input$b,".png")
},
content = function(file) {
ggsave(my.plot(),filename=file)
}
)
}
ui <- fluidPage(
# App title ----
titlePanel("Feature Plots"),
# Sidebar layout with a input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# select name
selectInput("a", "A", choices = unique(vals.df$a)),
uiOutput("b"),
downloadButton('save', 'Save to File')
),
# Main panel for displaying outputs ----
mainPanel(
# The plot is called feature.plot and will be created in ShinyServer part
plotOutput("plot")
)
)
)
When I run shinyApp(ui = ui, server = server) and select a and b values from their lists a figure is not displayed to the screen and when I click the Save to File button I get this error:
ERROR: no applicable method for 'grid.draw' applied to an object of class "function"
I tried wrapping the my.plot() calls with grid.draw but I get the same error:
no applicable method for 'grid.draw' applied to an object of class "function"
Any idea?
Note that I can't get it to work even if plotFunc returns the ggplot2 object (i.e., the grid calls are commented out). But solving this for the example above is more general and would also solve it for the ggplot2 more specific case.
You can do like this:
my.plot <- reactive({
if(!is.null(input$a) & !is.null(input$b)){
plotFunc(a = input$a,b = input$b)
}
})
The change i did was to remove the function. I wasnt sure why you need it and i think it caused the error in the download. Moreover, the second input you give over as a logical statement == which will create an error.
Full code would read:
set.seed(1)
vals.df <- data.frame(b=1:6,a=sample(1:2,6,replace=T))
plotFunc <- function(a,b)
{
p <- qplot(a,b)
p2 <- xyplot(1~1)
r <- grid::rectGrob(gp=gpar(fill="grey90"))
t <- grid::textGrob("text")
g <- gridExtra::grid.arrange(t, p, p2, r, ncol=2)
return(g)
}
library(shiny)
library(ggplot2)
library(lattice)
library(SpaDES)
library(devtools)
server <- function(input, output)
{
output$b <- renderUI({
selectInput("b", "B", choices = unique(dplyr::filter(vals.df,a == input$a)$b))
})
my.plot <- reactive({
if(!is.null(input$a) & !is.null(input$b)){
plotFunc(a = input$a,b = input$b)
}
})
output$plot <- renderPlot({
my.plot()
})
output$save <- downloadHandler(
filename = function() {
paste0(input$a,"_",input$b,".png")
},
content = function(file) {
ggsave(my.plot(),filename=file)
}
)
}
ui <- fluidPage(
# App title ----
titlePanel("Feature Plots"),
# Sidebar layout with a input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# select name
selectInput("a", "A", choices = unique(vals.df$a)),
uiOutput("b"),
downloadButton('save', 'Save to File')
),
# Main panel for displaying outputs ----
mainPanel(
# The plot is called feature.plot and will be created in ShinyServer part
plotOutput("plot")
)
)
)
shinyApp(ui = ui, server = server)

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)

Resources