user6777840 user6777840 - 1 month ago 17
R Question

How to modularize a simple bar plot in Shiny?

This is my app code:

app.R

library(shiny)

source("func.R")

# create data
name <- c("Moller", "Mayer", "Bernard")
sales <- c(35000, 40000, 60000)
df <- data.frame(name, sales)

# app
server <- function(input, output, session) {
x <- callModule(testPlot, "test", data = reactive(df), xAxis = reactive("name"), yAxis = reactive("sales"))
}
ui <- fluidPage(
testPlotUI(id = "test", stringName = "test")
)

shinyApp(ui = ui, server = server)


And this is my module code:

func.R

library(shiny)
library(ggplot2)

testPlotUI <- function(id, stringName){
ns <- NS(id)
fluidRow(
column(12,
plotOutput(stringName)
)
)
}

testPlot <- function(data, xAxis, yAxis){
output$test <- renderPlot({
ggplot(data(), aes_string(x=xAxis(), y=yAxis())) + geom_bar(stat = "identity")
})
}


This code ends up with this error:


Error in module(childScope$input, childScope$output, childScope, ...)
: unused arguments (childScope$input, childScope$output,
childScope)


How can I make this work?

Answer

The reason you are getting that error is that it is essential that the first three arguments to the server part of the module be input, output and session. So you need to change:

testPlot <- function(data, xAxis, yAxis){
  output$test <- renderPlot({
    ggplot(data(), aes_string(x=xAxis(), y=yAxis())) + geom_bar(stat = "identity")
  })
}

into:

testPlot <- function(input, output, session, data, xAxis, yAxis){
  output$test <- renderPlot({
    ggplot(data(), aes_string(x=xAxis(), y=yAxis())) + geom_bar(stat = "identity")
  })
}

With that change alone, your code will now run without any errors. However, nothing will appear. That is because you forgot another key component of using modules, which is to wrap all input/output ids in the ns() function. So change:

column(12,
       plotOutput(stringName)
)

into:

column(12,
       plotOutput(ns(stringName))
)

Now you should see your plot appear with no problems.