High Resolution Figures in R


LogisticAs I was recently preparing a manuscript for PLOS ONE, I realized the default resolution of R and RStudio images are insufficient for publication. PLOS ONE requires 300 ppi images in TIFF or EPS (encapsulated postscript) format. In R plots are exported at 72 ppi by default. I love RStudio but was disappointed to find that there was no options for exporting figures at high resolution.

PLOS ONE has extensive instructions for scaling, compressing, and converting image files to meet their standards. Unfortunately, there is no good way to go from low resolution to high resolution (i.e. rescaling in Photoshop) as my friend Liam Revell, and phytools author, pointed out with entertaining illustration from PhD comics (upper right panel). The point is if the original image isn’t created at a high enough resolution, then using Photoshop to artificially increase the resolution has problems of graininess because Photoshop can only guess how to interpolate between the points. This might not be a big problem with simple plots created in R because interpolation between points in a line shouldn’t be difficult, particularly when starting with a PDF.

Even if scaling up from a low resolution PDF would work, it would be better to have a direct solution in R.

[UPDATE: In the original post, I wrote about my trial and error when first trying this out. It was helpful for me but less helpful for others. Since this post gets a fair amount of traffic, I now have the solution first and the rest of the original post below that]

If you need to use a font not included in R, such as the Arial family of fonts for a publisher like PLOS, the extrafont package is very useful but takes a long time to run (but should only have to run once – except maybe when you update R you’ll have to do it again).

install.packages("extrafont")
library(extrafont)
font_import() # this gets fonts installed anywhere on your computer, most commonly from MS Office install fonts. It takes a LONG while.

Now to make a nice looking plot with a higher resolution postscript is the best but you may need to download another program to view it on you computer. TIFF is good for Raster data including photos and color gradients. PDF should be good for line and point based plots. JPEG is not going to be good for high resolution figures due to compression and detail loss but is easy to view and use for presentations, and PNG is lower quality that is useful for websites. Here are some high resolution figure examples. They all start by telling R to open a connection (device) to make a PDF or TIFF or EPS rather than just print to the R/RStudio plot default device. Then making the plot, then closing the device, at which point the file is saved. It won’t show up on the screen but will be saved to your working directory.

x = 1:20
y = x * 2

setwd('/Users/.../Folder/') # place to save the file - can be over-ridden by putting a path in the 
                              file = “ “ part of the functions below.

pdf(file = "FileName.pdf", width = 12, height = 17, family = "Helvetica") # defaults to 7 x 7 inches
plot(x, y, type = "l")
dev.off()

postscript(“FileName.eps", width = 12, height = 17, horizontal = FALSE, 
           onefile = FALSE, paper = "special", colormodel = "cmyk", 
           family = "Courier")
plot()
dev.off()

bitmap(“FileName.tiff", height = 12, width = 17, units = 'cm', 
       type = "tifflzw", res = 300)
plot()
dev.off()

tiff(“FileName.tiff", height = 12, width = 17, units = 'cm', 
     compression = "lzw", res = 300)
plot()
dev.off()

[ORIGINAL POST Follows]

It took some time to figure out but here are some trials and the ultimate solution I came up with:

x <- 1:100
y <- 1:100
plot(x, y) # Make plot
tiff("Plot1.tiff")
dev.off()
[/code]

Nothing happens in this case. However, by setting up the tiff file first, then making the plot, the resulting TIFF file is saved to your working directory and is 924 KB, 72 ppi, 480 x 480 pixels.

To increase the resolution I tried the following:
tiff("Plot2.tif", res = 300)
plot(x, y) # Make plot
dev.off()

but in RStudio the plot could not be printed and hence not saved because it was too large for the print area. Therefore, I had to open up R directly and run the code. Interestingly, a blank TIFF file was created of the same size as Plot1.tiff. This is where I got hung up for a while. I eventually found that R can’t figure out the other image parameters when resolution is changes or because the default is too big to print, so they have to be specified directly as such:

tiff("Plot3.tiff", width = 4, height = 4, units = 'in', res = 300)
plot(x, y) # Make plot
dev.off()

This creates a TIFF file that is 5,800 KB, 300 ppi, 4 inches by 4 inches. Surprisingly, on a Mac it still indicates that it’s only 72 ppi when viewed in Preview. The larger size indicates that it is actually 300 ppi. I ran the same code but specifically specified res = 72 and the file was only 334 KB, suggesting that Preview is incorrect and the file is really 300 ppi. I played with various compressions but lzw and none were the same while rle resulted in a larger file (less compression). That seems odd again.

Finally, I tried using the bitmap function to create a TIFF:

bitmap("Plot7.tiff", height = 4, width = 4, units = 'in', type="tifflzw", res=300)
plot(x, y)
dev.off()
par(mfrow = c(1,1))

Interestingly, this file is only 9 KB but is listed as 300 dpi, 1200 x 1200 pixels. I’m really not sure why these functions don’t seem to be working as smoothly as expected but hopefully this can help get high resolution images directly from R for publication. I plan to use the bitmap function in the future to create high resolution TIFF files for publication. This is what is desired by outlets such as PLOS ONE. It’s easier than dealing with postscript. I also don’t know if EPS files from R or RStudio are created with LaTeX. I know that can be a problem for PLOS ONE.

[UPDATE: Here is the code for my final figure for PLOS ONE with both postscript and tiff options plus it uses the extrafonts package to allow Arial fonts in postscript figures as required by PLOS ONE]

install.packages("extrafont")
library(extrafont)
font_import() # this gets fonts installed anywhere on your computer, 
# most commonly from MS Office install fonts. 
# It takes a long while.

bitmap("CummulativeCaptures.tiff", height = 12, width = 17, 
units = 'cm', type="tifflzw", res=300)
postscript("CummulativeCaptures.eps", width = 8, height = 8, 
horizontal = FALSE, onefile = FALSE, paper = "special", 
colormodel = "cmyk", family = "Arial")
par(mar = c(3.5, 3.5, 1, 1), mgp = c(2, 0.7, 0), tck = -0.01)
plot(refmCumm$date, refmCumm$cumm, type = "n", xaxt = "n",
xlab = "Date",
ylab = "Cumulative number of salamanders per plot",
xlim = c(r[1], r[2]),
ylim = ylims)
axis.POSIXct(1, at = seq(r[1], r[2], by = "year"), format = "%b %Y")
lines(refmCumm$date, refmCumm$cumm, lty = 1, pch = 19)
lines(depmCumm$date, depmCumm$cumm, lty = 2, pch = 24)
arrows(refmCumm$date, refmCumm$cumm+refmCumm$se, refmCumm$date, refmCumm$cumm-refmCumm$se, angle=90, code=3, length=0)
arrows(depmCumm$date, depmCumm$cumm+depmCumm$se, depmCumm$date, depmCumm$cumm-depmCumm$se, angle=90, code=3, length=0)
dev.off()

 EDIT: Just found a nice blog post with recommendations on device 
outputs on Revolutions here

Below is all the code that includes comparison of sizes with PDF, PNG, JPEG, and EPS files as well.

plot(x, y) # Make plot
tiff("Plot1.tiff")
dev.off()

tiff("Plot2.tiff", res = 300)
plot(x, y) # Make plot
dev.off()

tiff("Plot3.tiff", width = 4, height = 4, units = 'in', res = 300)
plot(x, y) # Make plot
dev.off()

tiff("Plot3.72.tiff", width = 4, height = 4, units = 'in', res = 72)
plot(x, y) # Make plot
dev.off()

tiff("Plot4.tiff", width = 4, height = 4, units = 'in', res = 300, compression = 'lzw')
plot(x, y) # Make plot
dev.off()

tiff("Plot5.tiff", width = 4, height = 4, units = 'in', res = 300, compression = 'none')
plot(x, y) # Make plot
dev.off()

tiff("Plot6.tiff", width = 4, height = 4, units = 'in', res = 300, compression = 'rle')
 # Make plot
dev.off()

bitmap("Plot7.tiff", height = 4, width = 4, units = 'in', type="tifflzw", res=300)
plot(x, y)
dev.off()
par(mfrow = c(1,1))

bitmap("Plot8.tiff", height = 480, width = 480, type="tifflzw", res=300)
plot(x, y)
dev.off()
par(mfrow = c(1,1))

jpeg("Plot3.jpeg", width = 4, height = 4, units = 'in', res = 300)
plot(x, y) # Make plot
dev.off()

tiff("Plot4b.tiff", width = 4, height = 4, pointsize = 1/300, units = 'in', res = 300)
plot(x, y) # Make plot
dev.off()

png("Plot3.png", width = 4, height = 4, units = 'in', res = 300)
plot(x, y) # Make plot
dev.off()

pdf("Plot3.pdf", width = 4, height = 4)
plot(x, y) # Make plot
dev.off()postscript("Plot3.eps", width = 480, height = 480)
plot(x, y) # Make plot
dev.off()

24 thoughts on “High Resolution Figures in R

  1. For true EPS you need to set additional arguments in the postscript() call, namely onefile = FALSE and paper = "special". Also note the height and width are by default inches in that function, not pixels. Hence the postscript() isn’t really doing what you think it is.

    For the first example, where you do the plot before calling tiff(), that is just creating an empty TIFF. It isn’t really very useful at all.

    For a plot like the one at the top of your posting, EPS should give the best results – it is largely composed of lines and characters. TIFFs come into there own where the plot is best described by a raster – lots of pixel-level colour changes etc, or the plot contains a large amount of data (thought there may be better graphical approaches than brute-force plotting all the data as actual observations).

  2. Just curious, but when PLOS ONE accepts a vector format such as EPS, why would you even consider a raster format such as TIFF? I thought that was the whole point of the vector format – to scale well…

      • Hi John – the truth is that I was focused on using a TIFF for PLOS ONE because I had no idea what an EPS was, so I had no clue how to manipulated it and make it look right. The comment by ucfagls above was definitely helpful for that. Since starting to prepare the figure for this manuscript I’ve learned a bit about the pros and cons of different file formats (not addressed in the blog) and I will try EPS for the final submission if it’s accepted.

  3. EPS is definitely the way to go. I used EPS files in a recent paper (link below) and was really happy with the finished product. I’ve got Adobe Acrobat Pro, so when I open an EPS file it converts to a PDF for viewing. But I’m sure there are other utilities for viewing EPS files on different operating systems.

    Note: I wish I had changed the point line-width setting (lwd in the points function). My only gripe was with how “bold” the points look when you zoom in. I suppose that is just nitpicking.

    http://www.sciencedirect.com/science/article/pii/S037811271200477X

    • The figures look great in that pub. I don’t have Adobe Pro but I know things like Ghostscript and Inkscape are supposed to be able to open EPS files. I believe they’re both free, open source projects, which is nice. Hopefully my manuscript is accepted and I can submit the final figures with EPS. R is great for plotting, but the flexibility comes at the cost of learning time (even just for exporting). I’m sure I will be making some figures very similar to yours in the near future, Dan. Hopefully mine come out as well now that I’ve finally got some good, working hierarchical models.

      Thanks,
      Dan

  4. PLoS One figure requirements are so extensive they are impossible to reach. I have learned to ignore their quality control failure notices. As long as you send tiffs or eps, they seem to let them through.

  5. Pingback: Great figures in your paper are worth the time | Sociobiology

    • Yeah, I love RStudio but it doesn’t yet have the ability to export high resolution figures. Hopefully in a future version. It’s amazing what they’ve done with the IDE in such a short time. In the meantime, at least there are ways to get good figures for publication, even if it takes a while to figure out. EPS is great but can be difficult to work with if you’re not familiar with the format.

  6. Pingback: 2013 in review | Daniel J. Hocking

  7. Thank you so much for this! Saved me a whole lot of googling and resulted in lovely EPS files. Much appreciated.

  8. Thank you so much! I’ve been pulling my hair out all day. Once I figured out the proper search terms, this popped up & I had my maps beautiful in PDF. You made my day!

  9. Pingback: Year in Review: 2014 | Daniel J. Hocking

  10. Hi Dan,
    Thanks for your interesting article. I don’t know how old this information is, but, after looking at your examples and reading some of the documentation files in R I was able to export high resolution TIFFS from RStudio (I haven’t used any of the other image formats) and I thought I’d share. You have to specify the size of your image first, using DPI and pixel units. For example, if you want a 4in by 4in graphic you would use code that might look like the following:

    tiff(“Example.tif”, width = 1200, height = 1200, units = “px”, res = 300)
    plot(1:10, 1:10)
    dev.off()

    Thought that might be useful for others.

  11. Hi Daniel, I also found this post quite helpful. I am wondering though- were you able to specify a resolution for your EPS exports? I didn’t notice that anywhere in the code

    • You actually don’t need to specify resolution with postscript (EPS). It is a vector-based graphics system. If you’re familiar with GIS, think of it as a polygon shapefile compared to jpeg or tiff which are more like raster and need resolution defined. That is why if you have only lines and polygons and no images, postscript makes for a nice, scalable figure format.

  12. The workflow I use for saving optimal figures straight out of RStudio is the following:

    1) copy the figure from the graphic device to a pdf file, using “dev.copy2pdf”: dev.copy2pdf(“image.pdf”, width=8.5, height=11)

    2) use imagemagick to convert the pdf into a high-res png, using this command: convert -density 600 image.pdf image.png

    3) optional – also with imagemagick, remove all the white borders and leave only the contents that matter: convert image.png -trim image_trimmed.png

    I found that, to me, this is the best way possible to save high-res figures.

    I hope this is useful to someone else.

    • Yeah, since I originally posted this I’ve become quite the convert to the Hadley-verse, including ggplot2. It makes MANY things much easier but does require changing the way you think about R programming. Still good to know how to get high quality figures straight out of base R.

Leave a comment