Render images in a Shiny app
When you want to have R generate a plot and send it to the client browser, the
renderPlot() function will in most cases do the job. But when you need finer control over the process, you might need to use the
renderImage() function instead. This is demonstrated in the image output demo application.
renderPlot() is useful for any time where R generates an image using its normal graphical device system. In other words, any plot-generating code that would normally go between
dev.off() can be used in
renderPlot(). If the following code works from the console, then it should work in
renderPlot() takes care of a number of details automatically: it will resize the image to fit the output window, and it will even increase the resolution of the output image when displaying on high-resolution (“Retina”) screens.
The limitation to
renderPlot() is that it won’t send just any image file to the browser – the image must be generated by code that uses R’s graphical output device system. Other methods of creating images can’t be sent by
renderPlot(). For example, the following won’t work:
- Image files generated by the
writePNG()function from the png package.
- Image files generated by the
rgl.snapshot()function, which creates images from 3D plots made with the rgl package.
- Images generated by an external program.
- Pre-rendered images.
The solution in these cases is the
Image files can be sent using
renderImage(). The expression that you pass to
renderImage() must return a list containing an element named
src, which is the path to the file. Here is a very basic example of a Shiny app with an output that generates a plot and sends it with
Each time this output object is re-executed, it creates a new PNG file, saves a plot to it, then returns a list containing the filename along with some other values.
deleteFile argument is
TRUE, Shiny will delete the file (specified by the
src element) after it sends the data. This is appropriate for a case like this, where the image is created on-the-fly, but it wouldn’t be appropriate when, for example, your app sends pre-rendered images.
In this particular case, the image file is created with the
png() function. But it just as well could have been created with
writePNG() from the png package, or by any other method. If you have the filename of the image, you can send it with
Structure of the returned list
The list returned in the example above contains the following:
src: The output file path.
contentType: The MIME type of the file. If this is missing, Shiny will try to autodetect the MIME type, from the file extension.
height: The desired output size, in pixels.
alt: Alternate text for the image.
contentType, all values are passed through directly to the
<img> DOM element on the web page. The effect is similar to having an image tag with the following:
Note that the
src="..." is shorthand for a longer URL. For browsers that support the data URI scheme, the
contentType from the returned list are put together to create a special URL that embeds the data, so the result would be similar to something like this:
For browsers that don’t support the data URI scheme, Shiny sends a URL that points to the file.
Sending pre-rendered images with renderImage()
If your Shiny app has pre-rendered images saved in a subdirectory, you can send them using
renderImage(). Suppose the images are in the subdirectory
images/, and are named
image2.jpeg, and so on. The following
server function would send the appropriate image, depending on the value of
In this example,
FALSE because the images aren’t ephemeral; we don’t want Shiny to delete an image after sending it.
Note that this might be less efficient than putting images in
www/images and emitting HTML that points to the images, because in the latter case the image will be cached by the browser.
Using clientData values
In the first example above, the plot size was fixed at 400 by 300 pixels. For dynamic resizing, it’s possible to use values from
session$clientData to detect the output size.
In the example below, the output object is
output$myImage, and the width and height on the client browser are sent via
session$clientData$output_myImage_height. This example also uses
session$clientData$pixelratio to multiply the resolution of the image, so that it appears sharp on high-resolution (Retina) displays:
height values passed to
png() specify the pixel dimensions of the saved image. These can differ from the
height values in the returned list: those values are the pixel dimensions to used display the image. For high-res displays (where
pixelratio is 2), a “virtual” pixel in the browser might correspond to 2 x 2 physical pixels, and a double-resolution image will make use of each of the physical pixels.
If you have questions about this article or would like to discuss ideas presented here, please post on RStudio Community. Our developers monitor these forums and answer questions periodically. See help for more help with all things Shiny.