R绘图所占的区域,被分成两大部分,一是外围边距,一是绘图区域。
外围边距可使用par()函数中的oma来进行设置。比如oma=c(4,3,2,1),就是指外围边距分别为下边距:4行,左边距3行,上边距2行,右边距1行。很明显这个设置顺序是从x轴开始顺时针方向。这里的行是指可以显示1行普通字体。所以当我们使用mtext中的line参数时,设置的大小就应该是[0,行数)的开区间。当我们使用mtext在外围边距上书写内容时,设置mtext中的outer=TRUE即可。
绘图区域可使用par()函数中的mfrow, mfcol来进行布局。mfrow和mfcol可以使用绘图区域被区分为多个区域。默认值为mfrow(1,1)。
比如mfrow(2,3)就是指将绘图区域分成2行3列,并按行的顺序依次绘图填充;
比如mfcol(3,2)就是指将绘图区域分成3行2列,并按列的顺序依次绘图填充;
我们将每一个细分的绘图区域分为两个部分,一是绘图边距,一是主绘图。
绘图边距需要容纳的内容有坐标轴,坐标轴标签,标题。通常来讲,我们都只需要一个x轴,一个y轴,所以在设置时,一般的下边距和左边距都会大一些。如果多个x轴或者y轴,才考虑将上边距或者右边距放大一些。绘图边距可以使用par()函数中mar来设置。比如mar=c(4,3,2,1),与外围边距的设置类似,是指绘图边距分别为下边距:4行,左边距3行,上边距2行,右边距1行。很明显这个设置顺序是从x轴开始顺时针方向。行的概念与之前的相同。也可以使用mai来设置。mai与mar唯一不同之处在于mai不是以行为单位,而是以inch为单位。
SOUTH<-1; WEST<-2; NORTH<-3; EAST<-4; GenericFigure <- function(ID, size1, size2) { plot(0:10, 0:10, type="n", xlab="X", ylab="Y") text(5,5, ID, col="red", cex=size1) box("plot", col="red") mtext(paste("cex",size2,sep=""), SOUTH, line=3, adj=1.0, cex=size2, col="blue") title(paste("title",ID,sep="")) } MultipleFigures <- function() { GenericFigure("1", 3, 0.5) box("figure", lty="dotted", col="blue") GenericFigure("2", 3, 1) box("figure", lty="dotted", col="blue") GenericFigure("3", 3, 1.5) box("figure", lty="dotted", col="blue") GenericFigure("4", 3, 2) box("figure", lty="dotted", col="blue") } par(mfrow=c(2,2),mar=c(6,4,2,1),oma=c(4,3,2,1)) MultipleFigures() box("inner", lty="dotted", col="green") box("outer", lty="solid", col="green") mtext("Outer Margin Area (oma) of South: 6", SOUTH, line=1, cex=1, outer=TRUE) plotline<-function(n,direc){ for(i in 0:n){ mtext(paste("line",i,sep=""), direc, line=i, cex=1, col="black", adj=1, outer=TRUE) } } plotline(4,SOUTH) |
但是,使用mfrow,mfcol只能是矩阵似的布局,如果我们需要简单地实际不规则的布局,那该怎么办呢?还有强大的layout()专门用于布局。
layout(mat, widths = rep(1, ncol(mat)), heights = rep(1,nrow(mat)),respect = FALSE)
其中,mat就是一个距阵,假设我们要画N个图,那么,mat就要描述每个图所在的位置,其中1…N-1都必须至少出现过一次。比如有三个图,我们希望的布局是第一排有一个图,第二排有两个图,那么mat<-matrix(c(1,1,2,3), nrow=2, ncol=2, byrow = TRUE);如果希望第一排有两个图,第二排有一个图,那么就是mat<-matrix(c(1,2,3,3),nrow=2,ncol=2,byrow=TRUE)。很明显,还是将画布分成许多小格矩阵,这里就是2X2的,如果希望第1个图放入第一排的1,2格,那就在矩阵的第1,2的位置写入1,如果是希望第2个图放在第一排的1,2格,那就在矩阵的第1,2的位置写入2。
> attach(mtcars) > layout(matrix(c(1,1,2,3), 2, 2, byrow = TRUE)) > hist(wt) > hist(mpg) > hist(disp) |
那么参数中的widths和heights又是做什么用的呢?它们就是用来指定每行或者每列的宽度和高度的。我们可以做以下的比较:
> attach(mtcars) > layout(matrix(c(1,1,1,1,2,2,2,3,2,2,2,3),3,4,byrow=TRUE)) > hist(wt) > hist(mpg) > hist(disp) > layout(matrix(c(1,1,2,3), 2, 2, byrow = TRUE), + widths=c(3,1), heights=c(1,2)) > hist(wt) > hist(mpg) > hist(disp) |
我们发现,这两种方法得到的是相同的结果,在代码的书写上,第2种方法要更清晰一些。
想象一下,似乎每个图的位置必须是连在一起的小矩阵,如果,不构成连在一起小矩阵,会成为怎么样的一个结果呢?
> attach(mtcars) > layout(matrix(c(1,1,2,1,1,1),nrow=2,ncol=3,byrow=T)) > hist(wt) > hist(mpg) |
如果需要大图,小图,内嵌图这layout()虽然很容易实现,但多少有点麻烦,不是那么随心所欲。还是回过头来使用par()吧。使用par()的中fig=在画布任意位置上画图。在使用fig参数时,需要把画布理解成左下角为坐标(0,0),右上角为(1,1)的一个坐标系。fig=c(x1,x2,y1,y2)来设置该参,x1<x2,y1<y2,x1,y1定位绘图区的左下角,x2,y2定位绘图区的右上角。使用new=TRUE参数来确认是否在原画布上继续画,还重新在一张新画布上开始画。
> par(fig=c(0,0.85,0,0.85), new=F) > plot(mtcars$wt, mtcars$mpg, xlab="Miles Per Gallon", + ylab="Car Weight") > par(fig=c(0,0.8,0.55,1), new=TRUE) > boxplot(mtcars$wt, horizontal=TRUE, axes=FALSE) > par(fig=c(0.65,1,0,0.8),new=TRUE) > boxplot(mtcars$mpg, axes=FALSE) > mtext("Enhanced Scatterplot", side=3, outer=TRUE, line=-3) > par(fig=c(0.4,0.75,0.4,0.7),new=TRUE,mar=c(2,2,0,0),mgp=c(1,.4,0),cex=1,cex.lab=0.7,cex.axis=0.7) > hist(mtcars$mpg, main="") |