R的基础绘图系统由Ross Ihaka编写,功能非常强大,主要由graphics包和grDevices包组成,它们在启动R时会自动加载。基础绘图系统中有两类函数,一类是高水平作图函数,另一类是低水平作图函数。所谓高水平作图函数是用于直接产生图形的函数,包括plot( )、hist( )、boxplot( )和pairs( )等。低水平作图函数是用于在高水平作图函数所绘图形的基础上添加新的图形或元素的函数,包括points( )、lines( )、text( )、title( )、legend( )和axis( )等。
4.1.1 函数plot( )函数plot( )是一个泛型函数,对于不同类型的数据,它可以绘制出不同的图形。例如,对于数值型数据,它可以绘制出散点图;对于分类数据,它可以绘制出箱线图;对于一些统计模型,它可以绘制出相应的图形,比如对于生存分析,它可以绘制出生存曲线。因此,函数plot( )的使用频率非常高,建议读者打开它的帮助文档查看其各种常用参数的用法。
下面创建一个示例数据,表示某病病人对2种药物(drugA和drugB)、5个剂量(dose)水平上的响应情况。
> dose <- c(20, 30, 40, 45, 60)> drugA <- c(16, 20, 27, 40, 60)> drugB <- c(15, 18, 25, 31, 40)
用上面的数据绘制药物A的剂量和响应关系的图形:
> plot(dose, drugA)> plot(dose, drugA, type = "b")
上面的命令创建了两幅图,函数plot( )里的参数type默认为“p”(代表点),所以得到的图4-1(a)是散点图。在第二行命令里,参数type改为了“b”(代表点和线),所以得到的图4-1(b)是点线图。
(a) (b)
图4-1 药物A剂量与响应关系散点图(a)和点线图(b)
函数plot( )用于新建一幅图形,我们还可以用低水平作图函数,例如lines( )、legend( )等,在一幅现有图形上添加新的图形元素。例如:
> plot(dose, drugA, type = "b", + xlab = "Dosage",ylab = "Response",+ lty = 1,pch = 15)> lines(dose, drugB, type = "b", lty = 2, pch = 17)> legend("topleft", title = "Drug Type",+ legend = c("A", "B"), + lty = c(1, 2), + pch = c(15, 17))
如图4-2所示,为了比较两种药物不同剂量下的响应情况,我们在一幅图上展示两个点线图,并用不同类型的线(lty)和不同特征的点(pch)加以区分。为了增强可读性,还添加了图例(legend)。需要注意的是,函数legend( )里面点和线的属性必须与前面函数plot( )和lines( )中设置的属性一致。
图4-2 药物A与药物B剂量与响应关系的比较
4.1.2 直方图和密度曲线图直方图(histogram)是用于展示连续型变量分布的最常用的工具,它本质上是对密度函数的一种估计。直方图和密度曲线图一般用于探索分布,很少用于报告结果。函数hist( )可用于绘制直方图。
数据集anorexia位于MASS包中,来自一项关于年轻女性厌食症患者体重变化的研究。该数据集包含72例观察对象、3个变量,其中变量Treat(治疗方式)是一个包含3个水平的因子,变量Prewt和Postwt均为数值型,分别表示治疗前后的体重(单位:lb)。下面绘制变量Prewt的直方图,代码如下:
> data(anorexia, package = "MASS")> str(anorexia)'data.frame': 72 obs. of 3 variables: $ Treat : Factor w/ 3 levels "CBT","Cont","FT": 2 2 2 2 2 2 2 2 2 2 ... $ Prewt : num 80.7 89.4 91.8 74 78.1 88.3 87.3 75.1 80.6 78.4 ... $ Postwt: num 80.2 80.1 86.4 86.3 76.1 78.1 75.1 86.7 73.5 84.6 ...> attach(anorexia)> hist(Prewt)
图4-3(a)给出了变量Prewt的频数分布,由于函数hist( )中没有设置任何参数,图中使用了默认的组距、坐标轴标签和标题等。需要注意的是,直方图的形状受到组距的影响,有时我们需要尝试设定参数breaks的不同的值以得到合适的图形。函数hist( )的输出结果中包含一些计算返回值,这些值可用于进一步地作图或者分析,例如为区间划分端点、频数(或密度)、区间中点等。
密度曲线为数据的分布提供了一种更为平滑的描述,绘制密度曲线的方法为:
> plot(density(Prewt))
从图4-3(b)可以看出,变量Prewt的分布是单峰的,基本是对称的。我们还可以在一幅直方图上添加一条密度曲线和轴须图。此时,需要在函数hist( )里面设定参数freq为FALSE,即把纵坐标换成频率,否则将会几乎看不到密度曲线。参数las设为1是为了将纵轴的刻度标签横向显示。
> hist(Prewt, freq = FALSE, col = "red",+ xlab = "体重(lbs)", + main = "治疗前体重分布直方图",+ las = 1)> lines(density(Prewt), col = "blue", lwd = 2)> rug(Prewt)> detach(anorexia)
图4-3(c)使用红色填充了条形,添加了信息量更大的坐标轴标签和标题,还通过设置参数las为1把纵轴的刻度标签换成了横向显示。然后使用函数lines( )在直方图上叠加了一条蓝色的、两倍于默认线条宽度的密度曲线。最后使用函数rug( )在横轴上添加了轴须图,以展示数据分布的密集趋势。
(a) (b) (c)
图4-3 直方图示例
条形图(bar chart)在医学科技论文中经常用到,它通过垂直的或水平的矩形展示分类变量的频数分布。函数barplot( )可用于绘制条形图。下面以vcd包里的Arthritis数据集为例介绍函数barplot( )的用法。该数据集来自一项关于治疗类风湿性关节炎新方法的成组对照双盲临床试验研究。其中的反应变量Improved记录了每位接受药物治疗(Treated,41例)或安慰剂(Placebo,43例)的患者的治疗效果,分为3个级别(None、Some、Marked)。
> library(vcd)> data(Arthritis)> attach(Arthritis)> counts <- table(Improved)> countsImproved None Some Marked 42 14 28
函数table( )用于生成分类变量的频数统计表。从上面的输出可以看到,有28位患者有了明显改善、14人有部分改善,而有42人没有改善。条形图可以用于展示这个频数分布,如图4-4(a)所示。
> barplot(counts, xlab = "Improvement", ylab = "Freqency", las = 1)
函数barplot( )还可以用于展示二维列联表的数据。图4-4(b)绘制了一幅分组条形图体育,并添加了颜色和图例,代码如下:
> counts <- table(Improved, Treatment)> barplot(counts, + col = c("red", "yellow", "green"),+ xlab = "Improvement", ylab = "Freqency",+ beside = TRUE, las = 1)> legend("top", legend = rownames(counts), + fill = c("red", "yellow", "green"))
(a) (b)
图4-4 条形图示例
条形图有时候也可以用于展示不同分类下的均值、中位数、标准差、置信区间等。用基本包里的函数可以实现这个功能,但是需要很多个步骤。而epiDisplay包里的函数aggregate.plot( )可以简化这个过程。下面的代码以数据集anorexia为例绘制了不同治疗方式下治疗后体重的均值条形图,结果如图4-5所示。
> library(epiDisplay)> aggregate.plot(anorexia$Postwt, by = list(anorexia$Treat), + 体育 error = "sd", legend = FALSE, + bar.col = c("red", "yellow", "green"),+ ylim = c(0,100), las = 1,+ main = "")
图4-5 均值标准差条形图示例
上面的误差棒表示的是标准差,我们可以通过改变函数aggregate.plot( )里面的参数error设置显示标准误或置信区间。
4.1.4 饼图饼图(pie chart)可用于展示分类数据的占比情况。例如,下面的代码绘制的饼图(图4-6)展示了某医院一周内急诊入院的疾病类型分布。
> percent <- c(5.8, 27.0, 0.5, 20.8, 12.8, 33.1)> disease <- c("上感", "中风", "外伤", "昏厥", "食物中毒", "其他")> lbs <- paste0(disease, percent, "%")> pie(percent, labels = lbs, col = rainbow(6))
体育
图4-6 某医院一周内急诊患者入院诊断分布
多数统计学家不建议使用饼图,他们更推荐用条形图或点图代替饼图,因为人们对长度的判断比对面积的判断更精确。因此,基本包的函数pie( )绘制饼图的选项有限。不过,一些捐赠包扩展了R绘制饼图的功能,例如plotrix包。该包提供的函数pie3D( )可以绘制三维饼图,另一个函数fan.plot( )可以绘制功能与饼图相似的扇形图,感兴趣的读者可以安装该包并查看其帮助文档。
4.1.5 箱线图和小提琴图箱线图(box plot)又称箱须图(box-whisker plot),常用于展示数据的大致分布特征,也用于探索异常值和离群点。函数boxplot( )可用于绘制箱线图。下面用箱线图展示数据集anorexia里体重前后变化的分布。
> anorexia$wt.change <- anorexia$Postwt - anorexia$Prewt> boxplot(anorexia$wt.change, ylab = "Weight change (lbs)", las = 1)
为了让读者更好地理解箱线图各部分的含义,作者在图4-7中添加了手工标注。如果数据是对称分布,中位数(Median)应该位于上四分位数(Upper quartile)和下四分位数(Lower quartile)的中间,即箱线图的方盒关于中位线对称。在上边缘(Upper hinge)和下边缘(Lower hinge)以外的值通常被认为是异常值。
图4-7 添加标注的箱线图示例
平行排列的箱线图可以用于比较在某个分类变量各个类别下某指标的分布。例如,要比较不同治疗方式下体重变化的情况,可以使用下面的命令:
> boxplot(wt.change ~ Treat, data = anorexia,+ ylab = "Weight change (lbs)", las = 1)
函数boxplot( )的第一个参数输入的是一个公式。R里公式一般用符号“~”连接变量,“~”左边可以看作因变量,“~”右边可以看作自变量。从图4-8(a)可以看出,“FT”(family treatment)组体重的改变量高于其他两组。但是,差异的显著性需要进一步的显著性检验才能确定,我们将在第5章里详细讨论。
小提琴图(violin plot)可以看作是箱线图和密度图的结合。vioplot包里的函数vioplot( )可用于绘制小提琴图,使用前请先安装并加载该包。例如,图4-8(a)可以换成小提琴图展示,如图4-8(b)所示。
> library(vioplot)> vioplot(wt.change ~ Treat, data = anorexia, + ylab = "Weight change (lbs)",+ col = "gold", las = 1)
(a) (b)
图4-8 不同治疗方式下体重改变量的箱线图(a)和小提琴图(b)
克利夫兰点图(Cleveland dot plot)本质上也是散点图,它通过点的位置展示数据的大小,是一种在简单水平刻度上绘制大量有标签的值的方法,其功能与条形图类似,但强调数据的排序以及相互之间的差距。函数dotchart( )可用于绘制克利夫兰点图。datasets包里的数据集VADeaths是1940年美国弗吉尼亚州城市和农村不同年龄段人群的死亡率(以‰表示)情况。克利夫兰点图(图4-9)可以比较好地展示该数据,代码如下:
> dotchart(VADeaths)> dotchart(t(VADeaths), pch = 19)
从图4-9可以看出,死亡率随着年龄的升高而升高;在同一年龄段,农村地区的死亡率均高于城市地区;在同一年龄段同一地区,男性的死亡率均高于女性。
图4-9 克利夫兰点图示例
4.1.7 导出图形如果想要把图形保存下来,可以通过图形用户界面和代码两种方式。在RStudio右下方的“Plots”下,单击“Export”,选择“Save as Image”或“Save as PDF”,可以把图形保存在指定的文件夹下。我们还可以选择“Copy to Clipboard”把图形直接复制到Word或PowerPoint文档。需要注意的是,这种方式保存的图形与RStudio图形窗口的尺寸有关,即不同大小的窗口得出的图形会有差异。如果想把图形保存下来用于报告或论文中,笔者建议使用代码的方式,将绘图语句放置在开启目标图形设备的语句和关闭目标图形设备的语句之间即可。例如,下面的代码会把图形保存到当前工作目录中并命名为“mygraph.pdf”:
> pdf("mygraph.pdf")> boxplot(wt.change ~ Treat, + data = anorexia, + ylab = "Weight change (lbs)",+ las = 1)> boxplot(wt.change ~ Treat, data = anorexia, ylab = "Weight change (lbs)")> dev.off()
除了函数pdf( ),我们还可以使用函数png( )、jpeg( )、tiff( )和postscript( )等将图形保存为其他格式。bmp、png和jpeg格式的图形文件都是非矢量格式,容易受到分辨率的影响,但它们占用的空间很小,适合运用于Word和PowerPoint文档中;ps格式的图形文件是矢量格式文件,它与分辨率无关,适合运用于排版印刷;而tiff(或tif)格式的图形文件可以支持很多色彩系统,而且独立于操作系统,在各类出版物中运用得最为广泛。例如:
> tiff(filename = "mygraph.tiff",+ width = 15, height = 12, units = "cm", res = 300)> boxplot(wt.change ~ Treat, data = anorexia, ylab = "Weight change (lbs)")> dev.off()
上述命令生成了一个名为“mygraph.tiff”的图形文件,参数width和height分别用于设置图形的宽度和高度,参数units用于设置宽度和高度的单位,参数res用于设置分辨率,这里设为了大多数出版物要求的最低值300。
本文截选自《R语言医学数据分析实战》
本书以医学数据为例,讲解如何使用R进行数据分析,结合大量精选的实例对常用分析方法进行了深入浅出的介绍,以帮助读者解决医学数据分析中的实际问题。
本书共分为14章,第1章~第3章介绍了R语言的基本用法;第4章介绍了数据可视化;第5章介绍了基本的统计分析方法;第6章~第8章介绍了医学研究中最常用的三种回归模型;第9章介绍了生存分析的基本方法;第10章~第12章介绍了几种常用的多元统计分析方法;第13章介绍了临床诊断试验的统计评价指标和计算方法;第14章介绍了在医学科研实践中常用的Meta分析方法。
本书适用于临床医学、公共卫生及其他医学相关专业的本科生和研究生使用,亦可作为其他专业的学生和科研工作者学习数据分析的参考书。阅读本书,读者不仅能掌握使用R及相关包快速解决实际问题的方法,还能更深入地理解数据分析。
平台