1
votes

Hi my second week with shiny. I'm coding an app, where a plot window and some plot control buttons needs to appear at some point. I use renderUI() and renderPlot(). I can have the user to update plot parameters renderPlot(expr={ [inside here] }).

,but I cannot have the user to change the plot resolution renderPlot(res=[some reactive variable outside here],expr={ })

I have posted test example below, Thanks alot.

library(shiny)

ui = fluidPage(
  uiOutput('thisPlot'),
  uiOutput('plotOptions')
)

server <- function(input, output) {
  #some plot options which will appear by some event
  output$plotOptions <- renderUI({
    if(TRUE) {list(
      radioButtons('plot.log', 'log axis',
                   c('none'= '' ,
                     'x'   = 'x',
                     'y'   = 'y',
                     'xy'  = 'xy'),sel=NULL),
    sliderInput('plotRes', "resolution",min=50,max=200,value=75)

    )}
  })


#render plot // plotRes does not respond
output$thisGraphicsDev <- renderPlot(res=input$plotRes,expr={
 plot(x=runif(1000),y=runif(1000),log=input$plot.log)
})

#write plot to ui
output$thisPlot <- renderUI({plotOutput('thisGraphicsDev')})

}
shinyApp(ui, server)
2

2 Answers

4
votes

The inside of every renderXX function is reactive, but not the function call itself. You have to wrap it inside another reactive environment.

Code fix:

library(shiny)

ui = fluidPage(
  uiOutput('thisPlot'),
  uiOutput('plotOptions')
)

server <- function(input, output) {
  #some plot options which will appear by some event
  output$plotOptions <- renderUI({
    if(TRUE) {list(
      radioButtons('plot.log', 'log axis',
                   c('none'= '' ,
                     'x'   = 'x',
                     'y'   = 'y',
                     'xy'  = 'xy'),sel=NULL),
    sliderInput('plotRes', "resolution",min=50,max=200,value=75)

    )}
  })


# Invalidates and re-evaluates whenever plotRes changes. 
observeEvent(input$plotRes, {
    output$thisGraphicsDev <- renderPlot(res=input$plotRes,expr={
     plot(x=runif(1000),y=runif(1000),log=input$plot.log)
    })
})

#write plot to ui
output$thisPlot <- renderUI({plotOutput('thisGraphicsDev')})

}
shinyApp(ui, server)

Note that you only have to observe plotRes, because plot.log already is inside a reactive expression.

1
votes

The res argument in renderPlot does not control the browser output resolution, from the renderPlot help file:

res Resolution of resulting plot, in pixels per inch. This value is passed to png. Note that this affects the resolution of PNG rendering in R; it won't change the actual ppi of the browser

Using info from this page http://shiny.rstudio.com/gallery/image-output.html you can save your plot as a temporary image whose resolution you control and then display the image.

library(shiny)

ui = fluidPage(
  imageOutput('plot'),
  uiOutput('plotOptions')
)

server <- function(input, output, session) {
  #some plot options which will appear by some event
  output$plotOptions <- renderUI({
    if(TRUE) {list(
      radioButtons('plot.log', 'log axis',
                   c('none'= '' ,
                     'x'   = 'x',
                     'y'   = 'y',
                     'xy'  = 'xy'),sel=NULL),
      sliderInput('plotRes', "resolution",min=10,max=200,value=75)

    )}
  })


  #render plot // plotRes does not respond

  output$plot <- renderImage({

    width  <-  session$clientData$output_plot_width
    height  <-  session$clientData$output_plot_height

    outfile <- tempfile(fileext=".jpeg")

    jpeg(outfile, 
        res = input$plotRes, 
        units = "px",
        width  = width,
        height  = height,
        pointsize = 12)
    plot(x=runif(1000),y=runif(1000),log=input$plot.log, cex = 1)
    dev.off()

    list(src = outfile,
         height = height,
         width = width)
  }, deleteFile = TRUE)


}
shinyApp(ui, server)