基础绘图系统最不如人意的地方应该就是其默认状态下导出的图片清晰度非常低,这大概也是其人气不如ggplot2
包的主要原因。本篇就介绍在使用基础绘图系统时如何尽可能地导出高清图片。
导出位图
位图包括BMP、PNG、JPEG、TIFF等多种格式。基础绘图系统中的图片导出函数由grDevices
工具包提供,函数名基本就是对应图片拓展名的小写字母拼写。如bmp
函数用于导出BMP格式图片;比较特殊的是jpeg
函数导出的图片既可以以JPEG命名,也可以以JPG命名。
导出图片时须将对应的导出函数放置在所有绘图命令之前,并在绘图命令之后加上dev.off()
语句表示结束。以jpeg
函数为例:
jpeg(...)
plot(...)
dev.off()
按照官方说明文档,几种类型的位图各有特点:
- PNG format is lossless and is best for line diagrams and blocks of colour;
- JPEG format is lossy, but may be useful for image plots;
- BMP format is standard on Windows, and supported by most viewers elsewhere;
- TIFF is a meta-format.
各函数的使用方法基本一致,这里以最常用的JPEG格式为例进行介绍,语法结构如下:
jpeg(filename = "Rplot%03d.jpg",
width = 480, height = 480, units = "px", pointsize = 12,
quality = 75,
bg = "white", res = NA, family = "", restoreConsole = TRUE,
type = c("windows", "cairo"), antialias)
包含filename
在内的所有参数均有默认值,即使不进行任何参数设置也可以导出图片。这里,仅设置filename
参数来观察导出图片的效果:
jpeg("21-1.jpeg")
curve(sin, -2*pi, 2*pi)
dev.off()
- 上图稍微放大之后就会出现明显的锯齿,清晰度很低。
通过调整以下三个参数可以提高位图清晰度:
- width:输出图片宽度;
- height:输出图片高度;
- res:输出图片分辨率。
- 增大分辨率可以提高图片清晰度,但必须同比例地调整图片的大小参数(即宽和高)。
res
的默认值只有72,而高清图片起码需要在300以上,这也是上幅图锯齿问题比较严重的主要原因。width
和height
的默认值均为480,为了与300的分辨率相适应,width
和height
一般要设置在2000左右,具体可根据需要的宽高比例进行调整。这里,我们让输出图片的宽、高之比为4:3:
jpeg("21-2.jpeg", width = 2000, height = 1500, res = 300)
curve(sin, -2*pi, 2*pi)
dev.off()
- 可以看出,图片变得清晰了不少。
分辨率越高,图片就越清晰。如果将分辨率增大为原来的2倍,但不改变大小参数:
jpeg("21-3.jpeg", width = 2000, height = 1500, res = 600)
curve(sin, -2*pi, 2*pi)
dev.off()
- 可以发现,输出图片上的文本显得很大,非常不协调。
或者,在分辨率不变的情况下,将图片大小参数增大为原来的2倍:
jpeg("21-4.jpeg", width = 4000, height = 3000, res = 300)
curve(sin, -2*pi, 2*pi)
dev.off()
- 可以看出,输出图片上的文本显得很小,也不协调。
以上问题的解决办法就是同时将图片大小和分辨率参数增大为原来的2倍:
jpeg("21-5.jpeg", width = 4000, height = 3000, res = 600)
curve(sin, -2*pi, 2*pi)
dev.off()
这样频繁调整多个参数会显得很麻烦,尽管可以通过下面的参数直接调整文本大小:
- pointsize:控制输出图片的文本大小。
pointsize
的默认值是12。比如在分辨率仍为300的情况下将此参数调整为24:
jpeg("21-6.jpeg", width = 4000, height = 3000,
res = 300, pointsize = 24)
curve(sin, -2*pi, 2*pi)
dev.off()
- 虽然避免了调整
res
参数,但频繁调整pointsieze
参数同样会很麻烦。
之所以需要这么调整参数,原因就在于jpeg
函数的width
和height
参数默认单位都是px,即像素;而pointsize
的单位大小是1英寸的1/72;分辨率的单位是ppi(pixels per inch)。从ppi的英文全称很明显可以看出,ppi、px和in三者的关系是:
也就是说,默认情况下通过设置width
和height
参数固定的是图片大小的像素值,在调整分辨率参数后,图片大小的英寸值也会随之反比例变化,而文本大小的英寸值直接由pointsize
参数控制,这样就使得图片和文本的相对大小发生了变化。所以,要么同比例改变图片大小参数和分辨率参数,这样图片的英寸值大小就不会发生改变;要么通过调整pointsiez
参数改变文本大小以与图片大小相适应。
下面参数可调整图片大小参数的单位:
- units:
width
和height
的单位,默认是px(像素),可选的有in(英寸)、cm(厘米)和mm(毫米)。
当把units
参数设置为in(英寸)时,即使不改变width
、height
和pointsize
三个参数,也可以调整分辨率而不会出现图片大小和文本大小不协调的情况。根据经验,当单位为英寸时,width
和height
设置在6左右比较合适。
jpeg("21-7.jpeg", width = 6, height = 4.5, units = "in", res = 300)
curve(sin, -2*pi, 2*pi)
dev.off()
jpeg("21-8.jpeg", width = 6, height = 4.5, units = "in", res = 600)
curve(sin, -2*pi, 2*pi)
dev.off()
- 因为单位改为英寸后,调整分辨率后图片大小的变化只是体现在像素值上,而英寸值不会变,也就是文本与图片的相对大小不会变。
其他函数和jpeg
函数的用法类似。不过由于JPEG是经过压缩的图片,它还有一个专门的参数:
- quality:以百分比表示JPEG格式图片的压缩程度,数值越大压缩程度越低,图片质量越高;默认值为75。
导出矢量图形
如果对图片清晰度有更高的要求,可以先导出矢量图形,再使用图形编辑软件Adobe Illustrator (AI)导出位图,其清晰度远高于直接导出的位图。
常用的矢量图形格式有PDF、SVG和EPS。以pdf
函数为例,语法结构如下:
pdf(file = if(onefile) "Rplots.pdf" else "Rplot%03d.pdf",
width, height, onefile, family, title, fonts, version,
paper, encoding, bg, fg, pointsize, pagecentre, colormodel,
useDingbats, useKerning, fillOddEven, compress)
但是R语言导出PDF时对中文字符不是很友好,一些特殊符号在PDF中也会乱码。
使用RMarkdown运行代码
还有一种导出高清图片的方法就是使用RMarkdown书写代码,然后导出HTML(网页)格式。网页上的图片也相当清晰,可以直接将其复制到WORD中。下图就是由RMarkdown导出的:
curve(sin, -2*pi, 2*pi)