☰
R语言作图基础:从base到ggplot2的实战教程
2026/10/17 2:33:18 网站建设 项目流程

很多人在接触到R语言之后,第一反应就是:这玩意儿真的是个正经编程语言吗?语法这么怪,一堆“管道”“向量”“数据框”,光看官网文档就能劝退一批人。但我这几年做数据分析、做科研配图、做各种小项目的实际经验是,如果你愿意花一个下午把R的基础作图搞明白,后面收获的回报远超投入。这个标题叫“R语言小程序(R作图基础)”,名字听着小,但本质上覆盖的是整个数据分析流程里最关键的输出环节——图。而图这个东西,在所有技术汇报、论文投稿、业务展示里,都直接决定了你的表达效率。

我把这个“小程序”理解成一条完整的学习链:从环境搭建开始,到基础的base绘图函数,再到更专业的ggplot2体系,最后落回到常见问题和导出规范。整个过程不需要高深的数学基础,也不需要你懂什么数据结构算法,只要你愿意跑代码、看结果、改参数,一个下午就能上手画出一批能用得上的图。适合的人群很广:刚接触统计分析的学生、需要频繁画科研图的研究人员、工作中要做数据可视化报表的分析师,甚至只是好奇R语言到底能干什么的编程爱好者,都能从中找到自己需要的东西。

这篇文章我不打算给你堆一本“教科书”。我会用自己的实操顺序来讲,哪些函数是真的高频,哪些参数是必须调的,哪些坑是新手百分百会踩的。你拿着这份内容,边看边在电脑上敲,比你看十遍文档都有用。

1. 先搞清楚:R里面的“作图”到底是怎么一回事

1.1 base绘图、ggplot2、其他扩展包怎么选

R语言里做图,严格来说有三套路线。第一套就是R自带的基础绘图系统,文档里常写成base graphics,你直接调plot()、barplot()、hist()、boxplot()这类函数就能出图。第二套是现在最主流的ggplot2,它属于“图形语法”流派,思路是用数据映射到图形的各种属性上,图层一层层叠上去。第三套是各种专业扩展包,比如交互式的plotly、做地图的sf加ggplot2、做热力图的pheatmap、做相关系数图的corrplot等等。

这三套路线不冲突,它们是互补的。很多教学材料一上来就推ggplot2,但你去看R官方文档、看很多老牌R包自带的绘图示例,用的还是基础绘图系统。我在实际工作中比较推崇的顺序是:先花一小时把基础绘图的常用函数过一遍,明白pch、col、type、main这些基础参数是怎么回事;然后花两三小时切入ggplot2,理解映射、图层、配色、主题这套核心理念。等这两步都通了,碰到任何特殊图表需求,你只要去搜对应的扩展包,看明白demo示例,马上就能改写出自己要的效果。

1.2 我为什么建议新手先玩透基础绘图

很多人嫌基础绘图画出来的图丑,觉得学它浪费时间,不如直接上ggplot2。这个想法我年轻的时候也有,后来发现自己错了。基础绘图虽然丑,但它逻辑极其简单直接——一个plot()函数,参数写清楚,图就出来了。没有任何“图层”“标度”“主题”的抽象概念,特别适合建立“参数影响图形”的条件反射。

举个例子,你在基础绘图里写一句plot(x, y, col = "red"),你就立刻看到点的颜色变红。你再改成pch = 19,点就从空心圈变成实心圈。这种即时反馈,对新手建立信心特别重要。而ggplot2里同样改一个属性,你得理解aes()里面的映射和外面设置的差异,经常出现“我明明指定了颜色为什么不变”的困惑。所以我认识的很多数据方向的前辈,包括我自己,都会建议新手不要跳过基础绘图,它是一座绕不开的桥。

注意:网络上有不少教程硬把base绘图和ggplot2对立起来,说“学ggplot2就够了”。实际上很多R包内部就是通过base绘图家谱生成图形的,很多脚本代码里也混着用。你两条腿走路,才能应付更多真实场景。

2. 环境准备与数据准备:开工前的那点讲究

2.1 安装R和RStudio,省事的配法

R语言本身只是一个引擎,官网下载对应的安装包装上就行。但我建议你一定要再装一个RStudio,它是目前最好用的图形化集成开发环境。RStudio的作用相当于把编辑器、控制台、环境变量、绘图窗口、帮助文档全部整合到一起,用起来非常顺手。装完R再装RStudio,第一次打开RStudio时会自动检测到本机的R解释器,基本不用额外配置。

关于版本选择,我的建议是:能用最新稳定版就上最新稳定版,不要贪图所谓的“兼容性”去装两三年前的旧版。R的包生态更新很快,很多包的新版本都会要求R内核版本达到一定数值,搞个太老的底层环境,后面装包会经常报错。至于操作系统,Windows、macOS、Linux都没问题。Windows上唯一要注意的是安装路径别带中文,这个算是老生常谈,但每次新电脑配置环境时总会有人踩到。

装好之后,你在RStudio右下角的Packages面板里能看到已经装好的包列表。没有的话,在控制台执行一句install.packages("ggplot2")就能联网安装。国内如果下载慢,可以换国内的镜像源,这个稍后讲配置的时候再说,但强烈建议先配置好,能省不少时间。

2.2 构造一份干净的测试数据

画图之前你得有数据。真实工作中你可能是从Excel、CSV、数据库里读数据,但对学习画图来说,最省事的办法是直接用R自带的数据集。R语言内置了一大批经典数据集,其中我觉得最适合拿来练作图的就是mtcars,这是一个关于32款汽车性能指标的数据框,里面有油耗、气缸数、排量、马力、车重等变量,量纲多样,分组特征明显,简直是为画图课量身定制的。

你可以在控制台输入data(),会弹出一个数据集列表。然后输入head(mtcars)查看前几行数据,用str(mtcars)查看数据结构。这里面的cyl是气缸数,wt是车重(单位是千磅),mpg是每加仑燃油行驶英里数,hp是马力。拿这些列做散点图,能直观看到变量之间的关系,特别适合讲解图表表达的含义。也有人喜欢用iris鸢尾花数据集,那个更适合练分类散点图和分组建模。反正你手上要有能分组的变量,后面学图例、调颜色才会顺手。

3. 核心图形实战:从零开始画5类常用图

3.1 散点图:看两个变量关系的第一选择

散点图大概是所有统计图里最基础、最常用的一种。它的核心作用是让你快速判断两个连续变量之间是否存在某种趋势,比如线性关系、非线性关系,或者根本没什么关系。在基础绘图中,plot()函数就是干这个的。

# 查看数据结构 str(mtcars) # 画散点图:车重对油耗的影响 plot(x = mtcars$wt, y = mtcars$mpg, xlab = "车辆重量(千磅)", ylab = "油耗(英里/加仑)", main = "车重与油耗的散点图", pch = 19, col = "#2c7bb6")

运行之后,RStudio的右下角绘图窗口会弹出一张散点图,一般情况下你会看到点整体呈现从左下到右上的趋势,直观表达出“车越重,油耗效率越低”这个结论。这里稍微解释几个参数的含义:pch是控制点样式的,19是实心圆点,1是空心圆,17是三角形,不同场景下你想突出重点数据点,就换不同的pch。col是颜色,可以写颜色名,也可以用十六进制色号,比如#2c7bb6是一种蓝色。xlab和ylab分别是横纵坐标轴标签,main是主标题。

我实际用下来的体会是,刚学plot()时,先把这几个参数混熟就够了。至于更多的比如点的大小(cex)、坐标轴范围(xlim、ylim)、轴的刻度位置,都属于按需查文档的范畴,用到再说。

3.2 柱状图:类别比较和频数统计的利器

柱状图在两类场景下特别管用:一是比较不同类别下的某个数值指标,二是展示某个变量的频数分布。你要先分清这两种情况,因为它们在数据准备和函数调用上是不一样的。

如果你想知道不同气缸数的车型在平均油耗上的差异,就得先把数据按cyl分组,计算每组的平均mpg。这里我用tapply函数,它有点像Excel里的分类汇总:

# 按气缸数分组计算平均油耗 avg_mpg <- tapply(mtcars$mpg, mtcars$cyl, mean) # 画柱状图 barplot(height = avg_mpg, names.arg = c("4缸", "6缸", "8缸"), col = c("#66c2a5", "#fc8d62", "#8da0cb"), ylab = "平均油耗(英里/加仑)", main = "不同气缸数的平均油耗对比")

barplot()的第一个核心参数是height,也就是每根柱子的高度。names.arg控制柱子下面的标签。很多人第一次画柱状图时会发现柱子上面的名字显示不全,这个多半是图形窗口太小,你手动把窗口拉大点,或者调整xlim、ylim就能解决。还有,画柱状图时柱子的顺序默认是按height里面的顺序走的,如果你想让柱子按从高到低排序,可以先sort()再画,视觉上更专业。

3.3 线图:趋势变化和时间序列的好搭档

线图最常用来表达连续时间或连续序列上的变化趋势。你可以在R里构造一个简单的模拟数据来练手。比如模拟一个网站用户数在一个月内逐日增长的情况。因为R画线图实际上是把各个点用线段连起来,所以plot()里要加上type = "l"这个参数。如果你既想要点又想要线,可以把type设成"o",也就是overplotted,点线叠加。

# 模拟30天的数据 day <- 1:30 users <- c(50, 55, 53, 60, 68, 72, 78, 85, 82, 90, 95, 100, 110, 115, 120, 128, 135, 140, 138, 145, 150, 160, 165, 170, 175, 180, 188, 192, 200, 210) # 画线图 plot(x = day, y = users, type = "l", col = "#d95f02", lwd = 2, xlab = "天数", ylab = "用户数", main = "30天用户增长趋势")

lwd的意思是线宽,数值越大线越粗。如果你在一张图里画多条线做对比,可以先plot()画第一条线,再用lines()函数把第二条线叠加上去。这里有个小坑:lines()必须在已有的绘图区域上调用,不能单独画图。所以你需要先有一个plot()创建了画布。很多人一开始不理解为什么自己单独运行lines()没反应,其实就是这个原因。

3.4 直方图:看单变量分布形态

直方图和柱状图表面长得很像,但它俩本质完全不同。柱状图的柱子是分类离散的,柱子之间可以随意调顺序;直方图的横轴是连续的数值区间,它是在把数据切分到一个个区间里,然后看每个区间里有多少数据掉进去。直方图的意义在于让你理解数据的“分布形态”——是集中在中间、偏向一边,还是出现两个峰。

# 画油耗数据的直方图 hist(mtcars$mpg, breaks = 10, col = "#99d594", border = "white", xlab = "油耗(英里/加仑)", main = "车辆油耗水平分布")

hist()函数里最重要的参数就是breaks,它决定你把数据切成多少个区间。区间太少,图形过于粗糙;区间太多,又会变得很碎。我的建议是你多尝试几个值,比如6、10、15,看看哪个最能体现分布特征。border参数是每根柱子的边框颜色,设成"white"会让整体更清爽。你还可以设置freq = FALSE,这样纵轴显示的不是频数而是密度,得到的直方图总面积是1,这个在后续做概率分布对比时特别有用。

3.5 箱线图:数据分布和异常点一起看

箱线图看起来简单,但信息量很大。它在一个图里同时展示了一组数据的中位数、上下四分位数、数据的整体范围以及异常点。当你想快速比较不同组数据之间的分布差异时,箱线图比多个直方图更紧凑、更高效。

# 按气缸数分组,比较油耗分布 boxplot(mpg ~ cyl, data = mtcars, col = c("#a6cee3", "#1f78b4", "#b2df8a"), xlab = "气缸数", ylab = "油耗(英里/加仑)", main = "不同气缸数车型的油耗分布对比")

这里的公式mpg ~ cyl意思是把mpg当作被解释变量,cyl当作分组变量,这样boxplot会自动按cyl的取值把数据分成三组并各自画一个箱子。从最终图形里你能看到,4缸车的油耗整体最高,8缸车普遍低,且组内差异也比较大。箱线图里那个看起来离群很远的点,就是箱线图通过“上下边界”规则筛出来的潜在异常点。你在做数据清洗时,这种可视化对于发现脏数据非常有帮助。

4. 用ggplot2让图表更好看

4.1 ggplot2的基本语法逻辑,认真读一遍就懂

ggplot2和基础绘图最大的区别在于它的“图层叠加”思想。你想想Photoshop,一个画布上,背景图层、主体图层、文字图层一层层摞上去,最后形成一张完整图。ggplot2也是这个思路,你先把数据背景和横纵轴映射好,然后通过一个个“几何对象”图层往上加内容。这个设计让你在改图的时候特别灵活:想加一条平滑线,就加一个图层;想改变点的颜色映射,改一个参数就行,完全不用推翻重画。

ggplot2最基本的模板有三大件:数据(data)、映射(aes)、几何对象(geom)。其中aes是指定“哪一列数据映射到x轴、哪一列映射到y轴、哪一列映射到颜色”,注意这一层只说明映射关系,并不会直接画出图形。真正画出图形的是geom_point()、geom_bar()、geom_line()这些几何对象函数。你还可以用labs()设置标题和坐标轴标签,用theme_*系列函数切换整体主题。

library(ggplot2) # 基本散点图 ggplot(data = mtcars, aes(x = wt, y = mpg)) + geom_point(size = 3, alpha = 0.7) + labs(title = "车重与油耗关系", x = "车辆重量(千磅)", y = "油耗(英里/加仑)") + theme_minimal()

运行这段代码,你会得到一张比base绘图干净得多的散点图。theme_minimal()就是极简主题,去掉了背景网格以外多余的东西。

4.2 升级实战:给散点图加颜色分组和拟合线

一张普通的散点图只能看整体趋势,但真实业务里我们通常还想知道“不同类别下这个关系是怎么变的”。比如不同气缸数下,车重和油耗的关系是否一致。在ggplot2里,这种分组探索简直太舒服了,因为你只需要在aes()里面加一个color = factor(cyl)。

ggplot(data = mtcars, aes(x = wt, y = mpg)) + geom_point(aes(color = factor(cyl)), size = 3, alpha = 0.7) + geom_smooth(method = "lm", se = FALSE, linetype = "dashed") + labs(title = "不同气缸数下车重与油耗的关系", x = "车辆重量(千磅)", y = "油耗(英里/加仑)", color = "气缸数") + theme_bw()

这个例子有两个关键点。第一个是geom_smooth(),它可以自动帮我们添加一条拟合曲线,method = "lm"表示线性回归拟合,se = FALSE意味着不显示置信区间。第二个是factor(cyl),因为cyl在数据里是数值型变量,如果不转成因子,ggplot2会把它当成一个连续颜色梯度来处理,而不是离散的分组颜色,那么图例就会变成渐变条而不是离散标签。这个就是很多新手困扰的“为什么颜色不对”的常见原因。

4.3 主题、配色和细节调整:怎么调出能投稿的图

很多人觉得R画出来的图难看,其实不是R的问题,而是默认参数确实比较老旧。ggplot2在这方面领先了很多。它的主题系统让你能一键切换风格,比如theme_minimal()、theme_bw()、theme_classic()。其中theme_bw()是黑白基调,特别适合论文投稿,因为它不会抢内容的焦点。theme_classic()则是横纵轴加框线的经典风格,适合做偏商业化的报表图。

如果你想进一步自定义,可以用theme()函数去修改各种细节,比如调整标题大小、去掉网格线、修改图例位置。常用的几个改动有:legend.position = "top"把图例移到顶部,panel.grid = element_blank()去掉所有网格线,text = element_text(size = 14)全局控制字体大小。这些属于高频操作,背下来没啥坏处。

配色方面,调色是最容易出效果也最容易翻车的。我的建议是:尽量别用默认彩色,多尝试RColorBrewer包的调色方案,或者直接用一些成熟的十六进制配色组合。比如下面这种做法:

library(RColorBrewer) # 查看可用配色方案 display.brewer.all()

你在绘图时把离散颜色映射到一个调色板,比如scale_color_brewer(palette = "Set1"),效果立刻专业很多。对于连续色,我比较常用scale_color_viridis_c(),这是viridis包提供的色盲友好渐变方案,在学术展示里特别受欢迎。

5. 保存与输出:别让你的图毁在最后一步

5.1 常用保存方式与格式选择

我看过太多人在RStudio里好不容易把图调满意了,然后鼠标右键“Save as Image”直接导出。这个操作不是不行,但导出的分辨率、清晰度、字体都不受控,结果放到PPT或者论文里一放大就糊了。正确做法是用R语言自带的一些设备函数来输出图片,比如png()、pdf()、jpeg()、tiff()。

# 先用png保存散点图 png("scatter_plot.png", width = 8, height = 6, units = "in", res = 300) plot(x = mtcars$wt, y = mtcars$mpg, pch = 19, col = "steelblue", xlab = "重量", ylab = "油耗") dev.off()

你会发现一个规律:png()函数负责打开一个图片输出设备,width控宽度,height控高度,res的300是每英寸像素数。中间的正常绘图代码不变,最后一定要有一个dev.off()来关闭设备。很多人第一次保存图片时只运行了png()和绘图代码,忘了dev.off(),结果文件一直写不进去,里面还是空的,就是因为图形设备没关闭。

如果是写论文要矢量图,用pdf()函数保存是最好的选择,矢量图放大缩小都不会失真。你还可以把多个图放在一个文件里,用par(mfrow = c(2, 2))先排一个2x2的版式,再用pdf()保存,这样一张PDF里就有四张小图。

5.2 分辨率和字体的坑,一次说清楚

关于导出图片,我积累了几个实用经验。第一,如果你最终应用场景是PPT投屏展示,分辨率至少要150,最好到300;如果只是网页上看看,96到150也够用。第二,width和height的单位建议选英寸(units = "in"),这样配合300的分辨率,导出尺寸就是8英寸乘6英寸,放到Word和PPT里大小很合适。第三,Windows上R的图形设备默认字体可能会把中文字符显示成方块或者乱码,这个很头疼,我在下一部分专门讲。

还有一个经验是,尽量把plot()或者ggplot()代码封装成一段完整的脚本,修改参数后重新跑一遍就能重新导出图。很多初学者在RStudio里靠鼠标反复调格式,把调试过程当产出过程,效率很低。你把脚本整理好,数据一更新,重新运行脚本,图自动就刷新了,这才是真正可复现的工作流。

6. 常见问题与避坑指南

6.1 中文显示成乱码,这是高频中的高频

中文乱码问题在Windows平台尤其突出。base绘图里,你如果在main或者xlab里写了中文,绘图窗口里可能显示正常,但用png()导出时会发现中文变成了框。这通常是因为图形设备用的字体不支持中文字符。

解决方案有很多,最省事的一个是:使用windowsFonts()指定支持中文的字体,再在绘图参数里设置家庭字体。比如:

# Windows下指定中文字体 windowsFonts(CN = windowsFont("Microsoft YaHei")) png("chart_cn.png", width = 8, height = 6, units = "in", res = 300) par(family = "CN") plot(x = mtcars$wt, y = mtcars$mpg, main = "车重与油耗关系图", xlab = "车重", ylab = "油耗") dev.off()

ggplot2里对应的方案则是通过theme()设置文本字体:

ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme(text = element_text(family = "CN"))

如果你用的是别的操作系统,需要根据系统看支持的字体名。与其花时间测试各种字体名,我建议直接用showtext包,它允许你直接从系统加载任意字体,兼容性好很多。设定完showtext_auto()之后,后面所有图的中文基本都能正常显示。

6.2 图片模糊、坐标轴文字被截断

图片模糊的根源几乎都在分辨率上。解决方法是把res参数加大到300以上,同时适当调大字体。比如在基础绘图里用cex.lab = 1.5放大坐标轴标签,用cex.main = 1.5放大标题。而坐标轴文字被截断,最常见的原因是图片输出窗口太小,或者导出尺寸设得太小但文字太多。你可以把图片尺寸调大,或者用par(mar = c(5, 5, 4, 2))调整页面边距,给坐标轴留出更多空间。

6.3 一页多图怎么排

做报告的时候经常需要把多个图组合到一页。普通做法是在base绘图里用par(mfrow = c(2, 2)),这样一行两列排4张图。如果你想控制不同子图的大小,那就得用layout()函数,它可以做出更多样式的版式。ggplot2体系下则可以用patchwork包,它的语法是现代又灵活的模式,核心就一个符号“+”,但要注意括号的配对,写错层级代码就会报错。

6.4 ggplot2绘图时常见的几个报错

ggplot2虽然好用,但对新手而言报错信息有时很不友好。最常见的两个:第一个是mapping里用了没引号的列名,说object not found,这时候就检查一下aes()里面写的列名是不是真的在数据框里,注意大小写。第二个是geom_smooth()报“method”相关错误,多是因为样本量太小或者变量不是数值型。第三个是y轴或x轴被截断或显示异常,通常是数值列被当成了因子列,你要检查一下是不是忘了做as.numeric()转换。

提示:碰到任何报错,先别慌。把报错信息复制到搜索引擎里搜,十有八九能搜到答案。R社区非常活跃,你遇到的问题大概率别人也踩过。

7. 我对R作图这件事的几个额外建议

最后聊点心得。

第一,建一个小型的“图库脚本库”。我会把自己画过的图对应的R脚本按类别存好,比如“散点图模板.R”、“柱状图模板.R”、“箱线图模板.R”。下次要画类似的图,复制过来改改列名就能用,效率高得惊人。学任何数据可视化工具都一样,你的第一张图是抄来的,不是创造出来的,多写几次也就变成了你自己的。

第二,配色不要贪多。真正见功底的图往往颜色很少。你能把黑白灰基础感做好,再点缀一两个强调色,就已经超过很多人了。一图超过五种颜色,往往会显得杂乱。

第三,反复检查图形的坐标轴含义。我在实际帮人看图时发现,很多图从“画图”本身来看没毛病,却把横纵坐标的物理意义搞混了——比如把离散的分类变量放在横轴,把连续的时间变量也硬塞到同一个坐标体系里,这种逻辑问题比美学问题更要命。画图之前问自己一句:这个图让别人看,到底是想传达什么信息?如果答不出来,那说明数据处理和问题定义还没到位。

如果你照着这篇文章的内容,把mtcarss数据集的各种图形都画了一遍,再用ggplot2把自己的业务数据或模拟数据画出来,至少你的R作图基础已经打下了。后面的路无非是遇到什么图就去学什么包的参数,用多了自然熟。关键要迈出第一步,打开那个绘图窗口,多折腾几条代码,很快你就会发现,R语言画图,真的就是一个积累细节的过程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询