上一篇里我大概写了R语言的简单作图元素,这里我们开始使用一些稍微高级的绘图函数,这些函数主要用来做各种统计图,比如箱线图,条形图,散点图等等……这些图再几百年前就开始使用,至今依然是学术界最为流行的图。或许它们相比于现在那些最酷的做图工具来说不够炫目,但是这些图依然是最容易让你看懂,也是最容易让你一行代码写出来的做图函数。
散点图
简而言之就是再图上画出一个一个的点,这是科研领域最常用也是最耐用的图,作图的时候,你必须知道横纵坐标分别是什么然后把点绘制出来。
> plot(sample(1:10),sample(1:10),main="散点图")
上图中,plot里有两个vector参数,前一个代表横坐标,后一个代表纵坐标。
线图
线图的代码其实和之前的散点图非常非常像:
> plot(sample(1:10),type = "l",main="线图")
这样就做出了线图,要注意的是,这里的线图是把每一个节点连接起来的。所以这与你vector里的点的顺序有关系了,做散点图,前后两个点顺序相反没关系,但是做线图,如果你把点的位置弄反了,绘制出来的线条会非常乱。所以,绘制线图的时候,一定要根据x坐标将所有点进行排序。
有时候我们想要绘制连贯的曲线,这个可不容易,因为这需要做拟合,所谓拟合就是绘制一条大致趋近你的曲线的线,但是那条线更为圆滑,这需要使用loess函数:
> x <- 1:10
> y <- c(2,4,6,8,7,12,14,16,18,20)
> lo <- loess(y~x)
> plot(x,y)
> lines(predict(lo), col='red', lwd=2)
再上面loess
函数完成了y因变量伴随着x自变量发生变化的拟合曲线,predict(lo)
函数的意思就是,提取出这个模型中根据每一个对应的x至拟合出来的y值。然后我们将其plot出来。
箱线图
boxplot在之前我们介绍异常值的时候介绍过,它的优点是可以很快让人看到中位数,上下四分位点等数值,缺点是只有box,看不到细部的数据细节,所以有时候,100个点和10000个点做出来的boxplot很类似很类似。所以看到boxplot,要小心的时候,除了总体的描述统计量,细节数据有没有直接关注的地方。
在这里我们展示一种更为特殊的boxplot:
boxplot(len~supp*dose, data=ToothGrowth, notch=TRUE,
col=(c("gold","darkgreen")),
main="Tooth Growth", xlab="Suppliment and Dose")
上述结果就是再boxplot函数中将notch
参数设置为TRUE,这样的boxplot会展现出更多细节。
值得一提的是,做boxplot的方法很多,我的意思是,boxplot的前几个参数有很多种写法,可以输入一个matrix,这样boxplot会自动提取每一列做一个boxplot,也可以输入单个的一个个vector,无限多的输入。另外,也可以先输入一个长长的vector,然后用~
符号跟一个分割vector,意思也就是,前一个vector根据后一个vector进行分割,其中每一个部分,都绘制一个boxplot。
条形图
barplot一般来说很简单:
# Stacked Bar Plot with Colors and Legend
counts <- table(mtcars$vs, mtcars$gear)
barplot(counts, main="Car Distribution by Gears and VS",
xlab="Number of Gears", col=c("darkblue","red"),
legend = rownames(counts))
)
在这里,我们输入的数据是一个矩阵:
> table(mtcars$vs, mtcars$gear)
3 4 5
0 12 2 4
1 3 10 1
再作图的时候,程序就自动将每一列做成一个bar,其中不同的部分,就叠放再一起。这里有一个很重要的参数就是beside
,如果你把beside参数设置为TRUE,做出了来的图是这样的:
散点图矩阵
散点图矩阵是散点图的高维扩展,它从一定程度上克服了在平面上展示高维数据的困难,在展示多维数据的两两关系时有着不可替代的作用。负责这方面工作的函数是pairs()
函数。
pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species",
pch = 21,
bg = c("red", "green3", "blue")[unclass(iris$Species)])
散点图矩阵的意思就是,针对一个矩阵中的不同的列,每两列做一个散点图,直接看出是否有两个列之间是显著相关的,这在你的数据有很多维度,你想要确定分析那两个维度的时候尤其有用。
从上图的分析,我们可以看出,Petal.length与Petal.Width关系是最紧密的。
三维散点图、三维曲面图
library("scatterplot3d")
z <- sample(1:100)
x <- sample(1:100)
y <- sample(1:100)
scatterplot3d(x,
y,
z,
highlight.3d=TRUE,
col.axis="blue",
col.grid="lightblue",
main="scatterplot3d - 1",
pch=20)
)
这个图很简单,参数也一目了然。不过在这里,我要强烈推荐另一个3D作图工具:rgl
,不过安装它很费时间,它的依赖包太多了,shiny一类的重量级作图配件它都需要。
代码是:
library(rgl)
with(mtcars,
{
plot3d(wt, disp, mpg, col="red", size=3)
}
)
最后出来的这个图是可以交互的,你可以拖拽,拉扯这个图形,老厉害了……
气泡图
气泡图是散点图的升级版,大致的作用是显示出,一个点的数量多少等等,这样其实很有用,等于再原有的横纵坐标两个维度上再增加了一个维度。额外说一句,作图就是这样,你可以往图上增加越来越多的维度,唯一的问题就是,难度可能不小。
裸代码写气泡图是很难的,我曾经做过一次这样的工作,当然最后的效果还是不错的:
这是我用来处理自己科研课题上的一些问题而绘制的气泡图,用的都是最简单最简单的绘图元素,通过调整图形,半径,颜色,位置等等,最终绘制出了上图。
但是在这里,我介绍一下ggplot2,R语言历史上一个很重要的做图工具,无他,就是因为它作图的效果很漂亮。核心理念是:
将数据,数据相关绘图,数据无关绘图分离。这点可以说是ggplot2最为吸引人的一点。众所周知,数据可视化就是将我们从数据中探索的信息与图形要素对应起来的过程。ggplot2将数据,数据到图形要素的映射,以及和数据无关的图形要素绘制分离,有点类似java的MVC框架思想。这让ggplot2的使用者能清楚分明的感受到一张数据分析图真正的组成部分,有针对性的进行开发,调整。
图层式的开发逻辑。在ggplot2中,图形的绘制是一个个图层添加上去的。举个例子来说,我们首先决定探索一下身高与体重之间的关系;然后画了一个简单的散点图;然后决定最好区分性别,图中点的色彩对应于不同的性别;然后决定最好区分地区,拆成东中西三幅小图;最后决定加入回归直线,直观地看出趋势。这是一个层层推进的结构过程,在每一个推进中,都有额外的信息被加入进来。在使用ggplot2的过程中,上述的每一步都是一个图层,并能够叠加到上一步并可视化展示出来。
各种图形要素的*组合。由于ggplot2的图层式开发逻辑,我们可以*组合各种图形要素,充分*发挥想象力。
上述描述出自网络博客
countries = c('IND', 'AUS', 'CHI', 'JAP', 'BAT', 'SING')
frequencies = matrix(sample(1:100, 36), 6, 6, dimnames = list(countries, countries))
diag(frequencies) = 0
library(reshape2)
frequencies_df = melt(frequencies)
names(frequencies_df) = c('origin', 'destination', 'frequency')
library(ggplot2)
ggplot(frequencies_df, aes(x = origin, y = destination, size = as.vector(frequencies))) + geom_point()
reshape2
和ggplot2
包需要被用到。用上述的代码就可以产生这样的气泡图。
当然,还有一种更为神奇的包叫做plotly
,这个包是我的挚爱,因为它的实现效果实在是太好太好了。这里可以看到用plotly实现的气泡图。
圆形关系图
其实这个图不应该这么说,但是我也不知道该怎么说,准确来说,英文叫做Circular plot,意思就是圆形的图,但是图有很多意义,可以有很多作用。比如说下面的代码:
name=c(3,10,10,3,6,7,8,3,6,1,2,2,6,10,2,3,3,10,4,5,9,10)
feature=paste("feature ", c(1,1,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5) , sep="")
dat <- data.frame(name,feature)
dat <- with(dat, table(name, feature))
# Charge the circlize library
library(circlize)
# Make the circular plot
chordDiagram(as.data.frame(dat), transparency = 0.5)
这个图非常浮夸地显示了feature与name之间的关系,我们通过table(name,feature)
可以看出一些相关的关系:
> table(name,feature)
feature
name feature 1 feature 2 feature 3 feature 4 feature 5
1 0 0 1 0 0
2 0 0 2 1 0
3 1 1 1 2 0
4 0 0 0 0 1
5 0 0 0 0 1
6 0 1 2 0 0
7 0 1 0 0 0
8 0 1 0 0 0
9 0 0 0 0 1
10 1 1 1 1 1
>
图中1就是圆环上的一小段边长,2就是两倍,其中中间的每一条联线,寓意着从其中一个feature到其中一个name的关系。在绘图的时候,feature全部再绘制再上方,而name全部在下方。
通过这样的方法,我们再拥有两个重要的维度,而且每一个维度上拥有好几个值的时候,就可以看出他们之间的关联。举例:加入每一列是一个国家的名字,每一行是运动会一个项目的名字,其中每一个值就是该国家再该项目上获得过的金牌总数。那么这样一个关系图就可以很直接地让人看出来,什么国家对于什么项目特别擅长。
在这里,我们稍微介绍了一下R的绘图函数,其中捎带讲了一点点ggplot和其他绘图包,总而言之,R语言绘图功能极为强大,基本上除了你想不到,没有什么是做不到。