36
votes

I am trying to create a shiny application that will allow you to download a nicely formatted PDF report, according to user-defined sub-analyses. I found this gist containing a minimal example, which works just fine. However, when I tried to add a plot, based on the 'Miles-per-gallon' example from the Rstudio gallery, I ran into some errors when I tried adapting the code.

Here is my server.R code:

library(knitr)
library(datasets)
library(ggplot2)

mpgData <- mtcars
mpgData$am <- factor(mpgData$am, labels = c("Automatic", "Manual"))

shinyServer(function(input, output) {
formulaText <- reactive({
    paste("mpg ~", input$variable)
})

# Return the formula text for printing as a caption
output$caption <- renderText({
    formulaText()
})

# Generate a plot of the requested variable against mpg and only 
# include outliers if requested
output$mpgPlot <- renderPlot({
    boxplot(as.formula(formulaText()), 
            data = mpgData,
            outline = input$outliers)
})

myPlot1 <- reactive({
    p <- print(ggplot(mpgData, aes(mpg, input$variable)) +
    geom_line())
})

 myPlot2 <- reactive({
     #renderPlot({
     p <- print(
         boxplot(as.formula(formulaText()), 
                 data = mpgData,
                 outline = input$outliers)
     )
 })

output$report = downloadHandler(
    filename = 'myreport.pdf',
    content = function(file) {
        out = knit2pdf('input.Rnw', clean = TRUE)
        file.rename(out, file) # move pdf to file for downloading
    },
    contentType = 'application/pdf'
)
})

and here is my ui.r code

library(shiny)
library(datasets)

shinyUI(fluidPage(

# Application title
titlePanel("Miles Per Gallon"),

# Sidebar with controls to select the variable to plot against mpg
# and to specify whether outliers should be included
sidebarLayout(
    sidebarPanel(
        textInput('firstname', 'First name', value = 'Adam'),
        textInput('lastname', 'Last name', value = 'Smith'),
        downloadButton('report'),

        selectInput("variable", "Variable:",
                    c("Cylinders" = "cyl",
                      "Transmission" = "am",
                      "Gears" = "gear")),

        checkboxInput("outliers", "Show outliers", FALSE)
    ),

    # Show the caption and plot of the requested variable against mpg
    mainPanel(
        h3(textOutput("caption")),

        plotOutput("mpgPlot")

    )
)
))

while the input.Rnw file looks like this:

\documentclass{article}

\begin{document}

<<names>>=
input$firstname
input$lastname
@

<<>>=
#output$mpgPlot ## N.B. This threw an error! Cannot call an object like this from shiny
print(myPlot1())
@

<<>>=
print(myPlot2())
@

\end{document}

I've been playing around with this for a few hours now, and I'm pretty stuck. The input$names part works fine, but I cannot figure out how to bring in a reactive plot. The error/warning message is 'Error: object ’input’ not found', so I know it is not detecting the input$variable changes being passed from the ui.R script. Thanks for your help solving this

sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-apple-darwin13.1.0 (64-bit)

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] ggplot2_0.9.3.1.99 knitr_1.6          shiny_0.10.0      

loaded via a namespace (and not attached):
 [1] bitops_1.0-6       caTools_1.17       colorspace_1.2-4   digest_0.6.4       evaluate_0.5.5     formatR_0.10       grid_3.1.0         gtable_0.1.2      
 [9] highr_0.3          htmltools_0.2.4    httpuv_1.3.0       labeling_0.2       MASS_7.3-33        munsell_0.4.2      plyr_1.8.1         proto_0.3-10      
[17] RColorBrewer_1.0-5 Rcpp_0.11.2        reshape2_1.4       RJSONIO_1.2-0.2    scales_0.2.4       stringr_0.6.2      tools_3.1.0        xtable_1.7-3
1
That is interesting. Can you replace ggplot2 graphics with base graphics and see if it works? e.g. plot(as.formula(formulaText()), data = mpgData)Yihui Xie
@Yihui Thank you, your suggestion worked, by replacing print(myplot1()) with plot(as.formula(formulaText()), data = mpgData) in input.Rnw. I have tried adapting this to ggplot2, by adding ggPlotText <- reactive({paste('mpg,', input$variable)}) to server.R and then ggplot(mpgData, aes(ggPlotText())) + geom_line() to input.Rnw, which seems to follow the logic of formulaText(), but the error message produced says Error: could not find function "ggPlotText". Is there an equivalent to as.formula() that I can use for the aes(x, y) convention of ggplot2? toString didn't workJonny
It sounds like a ggplot2 variable scope problem. However, before you report this issue to ggplot2 authors, please make sure you have the latest version of ggplot2 (do update.packages()).Yihui Xie
Have you tried ggplot with aes_string() ? Here is the documentation: docs.ggplot2.org/0.9.3/aes_string.htmlniczky12
@niczky12 please write an answer to ur suggestion. I did this already and would delete it then. I also guess this is the solution.drmariod

1 Answers

5
votes

As suggested in my comment, you should use aes_string() to programmatically pass in arguments into ggplot. The error you are getting is because 'input' is a character value while aes() expects unquoted names. Here is how you should replace the call to aes(mpg, input$variable):

myPlot1 <- reactive({
    p <- print(ggplot(mpgData, aes_string('mpg', input$variable)) +
    geom_line())
})