John Gagnon
John Gagnon

Reputation: 915

How to use display a plot with high resolution in a shiny app?

I'm trying to display a plot in a shiny app with specific height and width dimensions and specific font size/family but when it renders in the app, the png seems to be very low resolution. If I try to change the res value it makes the plot being displayed larger (which is not what I want). Is there a way to increase the resolution/dpi of the plot without changing its size?

Optimally, I would want to be able to zoom in on the webpage without having the plot look blurry. Is this possible with a png? Would I need to display the plot using something other than renderPlot?

library(shiny)


# Define UI for app that draws a histogram ----
ui <- fluidPage(

  # App title ----
  titlePanel("Hello Shiny!"),
  mainPanel(
    plotOutput(outputId = "Plot", width = "auto", height = "auto")
  )
)

# Define server logic required to draw a histogram ----
server <- function(input, output, session) {

  output$Plot <- renderPlot({
    ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
      geom_point() +
      theme(
        line = element_line(
          colour = "black",
          size = 0.25
        ),
        text = element_text(
          family = "Helvetica",
          size = 9,
          colour = "black"
        ),
        rect = element_blank(),
        panel.grid = element_blank(),
        legend.position = "top",
        legend.title = element_text(
          family = "Helvetica",
          size = 9,
          colour = "black"
        ),
        legend.text = element_text(
          family = "Helvetica",
          size = 9,
          colour = "black"
        ),
        # axis.line = element_line(colour = "black", size = stroke),
        axis.line.x = element_line(colour = "black", size = 0.25),
        axis.line.y = element_line(colour = "black", size = 0.25),
        axis.ticks.x = element_blank(),
        axis.text.x = element_text(
          family = "Helvetica",
          size = 9,
          colour = "black"
        ),
        axis.text = element_text(
          family = "Helvetica",
          size = 9,
          colour = "black"
        ),
        plot.margin = margin(5, 5, 5, 5, "mm"),
        legend.margin = margin(0, 0, 0, 0, "mm")
      )

  }, height = 200, width = 200)

}

shinyApp(ui, server)

Upvotes: 7

Views: 3234

Answers (1)

John Gagnon
John Gagnon

Reputation: 915

I found a workaround using renderImage() which allows you to store a temporary .png file that is larger with higher resolution and then you can display it on the page at a smaller size which seems to preserve the higher resolution.

You may need to zoom in with your browser to appreciate the difference but it helped quite a bit!

library(shiny)


# Define UI for app that draws a histogram ----
ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  mainPanel(
    h3("Low resolution"),
    plotOutput(outputId = "Plot", width = "auto", height = "auto"),
    hr(),
    h3("High resolution"),
    imageOutput("myImage", height = "100%", width = "100%")
  )
)

# Define server logic required to draw a histogram ----
server <- function(input, output, session) {

  Plot <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
    geom_point()

  output$Plot <- renderPlot({
    Plot
  }, height = 200, width = 200)


  # Plot the data ####
  output$myImage <- renderImage({
    # A temp file to save the output.
    # This file will be removed later by renderImage
    outfile <- tempfile(fileext = '.png')

    # Generate the PNG
    png(outfile, 
        width = 200*8, 
        height = 200*8,
        res = 72*8)
    print(Plot)
    dev.off()

    # Return a list containing the filename
    list(src = outfile,
         contentType = 'image/png',
         width = 200,
         height = 200,
         alt = "This is alternate text")
  }, deleteFile = TRUE)

}

shinyApp(ui, server)

Upvotes: 7

Related Questions