1. 散点图搭配边际分布图,到底解决了什么痛点
做过数据分析的人都有这种体会:手里攥着两个连续变量,想看看它们之间有没有关系,第一反应就是画个散点图。散点图确实直观,一个点代表一个样本,横轴纵轴各放一个变量,点的分布形态一眼就能看出正相关、负相关还是毫无规律。但问题也随之而来——当样本量大了,点会严重重叠,你根本看不清哪里密哪里疏;当样本量小了,你又很难判断每个变量各自的分布形态到底长什么样。
传统的做法是画完散点图,再单独画两个直方图或者密度曲线,分别看x和y的边缘分布。但这样有个麻烦:你得在脑子里把三张图拼起来,来回对照,效率低不说,还容易漏掉关键信息。比如x轴某个区间样本特别密集,同时y轴取值也集中,这种联合分布的特征在三张分离的图里很难快速捕捉到。
边际分布图(Marginal Distribution Plot)就是冲着这个痛点来的。它的核心思路很简单:在主散点图的顶部和右侧(或者左侧),各附加一个单变量的分布图,通常是直方图、密度曲线或者箱线图。这样一张图里,你既能看两个变量的联合关系,又能同时看到各自的边缘分布,信息密度直接翻倍。更妙的是,顶部和右侧的分布图会和主图的坐标轴严格对齐,哪个区间点密集,对应的边缘分布高峰在哪里,一目了然。
在R语言里,实现这种图的方式有好几种,最常用的组合是ggplot2加上ggExtra包,或者用cowplot、patchwork手动拼图,再或者用GGally包里的ggpairs做更复杂的多变量矩阵图。每种方案各有优劣,适合不同的场景。接下来我会从设计思路、核心细节、实操过程到问题排查,把这条路完整走一遍,让你看完就能直接上手,不用再到处翻文档。
这篇文章适合谁看?如果你已经会用R画基础的ggplot2图,但想让自己的探索性数据分析(EDA)输出更专业、信息更密集,那这篇就是为你准备的。如果你刚接触R,也没关系,我会把关键参数和逻辑都拆开讲清楚,你照着抄作业也能跑通。
2. 整体设计思路与方案选型
2.1 为什么首选ggplot2 + ggExtra组合
在R的可视化生态里,ggplot2是事实上的标准,它的图层语法让复杂图形的构建变得模块化。而ggExtra这个包,专门就是为了给ggplot2散点图加边际分布而生的。它的核心函数ggMarginal()可以直接接收一个已经画好的ggplot对象,然后在顶部和右侧自动添加指定类型的边际图。
这个方案的优势很明显:第一,代码量极少,基本上三行核心代码就能出图;第二,它完全兼容ggplot2的图层系统,你在主图上做的任何映射(颜色、大小、形状、分面)都能保留;第三,边际图的类型可以灵活选择,直方图、密度曲线、箱线图、小提琴图都支持,还能分别指定x轴和y轴用不同的类型。
相比之下,用cowplot或patchwork手动拼图虽然灵活性更高,但需要你自己计算坐标轴对齐、调整边距、处理图例位置,代码量至少翻三倍,而且很容易在拼图过程中出现对齐偏差。GGally的ggpairs更适合多变量矩阵图,如果你只有两个变量,用它有点杀鸡用牛刀的感觉,而且默认样式偏“矩阵”,不如ggExtra出来的图清爽。
所以我的建议很明确:两个变量的散点图加边际分布,无脑选ggplot2 + ggExtra。如果你需要更复杂的自定义布局,再考虑手动拼图。
2.2 边际图类型的选择逻辑
ggMarginal()支持几种边际图类型,每种都有适用的场景。选错了类型,图不仅不好看,还可能误导读者。
直方图(histogram)是最常见的选择,适合样本量中等(几百到几千)的情况。它能直观展示每个区间的频数,但缺点是 bin 的宽度需要手动调,调不好会显得很毛糙或者过度平滑。默认的 bin 数量在ggMarginal里是30,对于大多数场景够用,但如果你的数据范围特别大或者特别集中,就需要调整。
密度曲线(density)适合样本量较大(几千以上)的情况,它给出的是平滑的概率密度估计,看起来更优雅。但要注意,密度曲线的平滑带宽(bandwidth)会影响形态,带宽太小会过度拟合,出现很多毛刺;带宽太大又会把双峰抹成单峰。ggMarginal默认用的是ggplot2的geom_density,带宽由bw参数控制,通常用默认的“nrd0”规则就行,但如果你的数据有明显的多峰特征,可以手动调小一点。
箱线图(boxplot)适合你想快速看中位数、四分位数和异常值的情况。它的信息密度不如直方图和密度曲线,但胜在简洁,尤其适合在报告里展示。不过箱线图会隐藏分布的具体形态,如果数据是双峰的,箱线图完全看不出来,这时候就不如用密度曲线。
小提琴图(violin)是箱线图和密度曲线的结合,既能看分位数,又能看分布形态。但小提琴图在样本量小的时候会显得很怪异,因为核密度估计不稳定。一般来说,样本量低于100就不太建议用小提琴图。
我的经验是:探索阶段用直方图或密度曲线,看细节;展示阶段用箱线图或小提琴图,看概要。如果拿不准,就用密度曲线,它最不容易出错。
2.3 颜色与分组的处理策略
如果你的数据里有分组变量,比如不同实验条件、不同性别、不同地区,你肯定想在散点图里用颜色区分开。ggMarginal是支持这个的,但有个坑:默认情况下,边际图会把所有组混在一起画,颜色区分不明显。
解决办法是设置groupColour = TRUE和groupFill = TRUE,这样边际图也会按组着色。但要注意,如果组数太多(超过5组),边际图会变得非常花哨,反而看不清。这时候可以考虑用分面(facet)代替颜色分组,或者只对最重要的两组做颜色区分。
另外,边际图的透明度也很关键。默认的填充透明度是0.5左右,如果组间重叠严重,可以调低到0.3,让重叠区域的颜色叠加更明显。但太低又会让颜色发灰,看起来不干净。我一般用0.4到0.6之间的值,具体看数据密度。
3. 核心细节解析与实操要点
3.1 数据准备与预处理的关键步骤
在画图之前,数据清洗和预处理是绕不开的。散点图加边际分布对数据的要求其实不高,但有几个细节如果没处理好,图出来就会有问题。
第一,缺失值处理。ggplot2默认会忽略缺失值,但会在控制台给你一个警告。如果你的数据里缺失值很多,最好在画图前就用na.omit()或者tidyr::drop_na()明确去掉,避免警告信息干扰。更重要的是,你要清楚缺失值去掉后样本量还剩多少,如果去掉太多,边际分布的形态可能会严重失真。
第二,变量类型检查。散点图的x和y必须是连续变量,如果是因子或者字符,ggplot2会报错或者画出奇怪的东西。用str()或者class()确认一下,必要时用as.numeric()转换。但要注意,如果字符型数字转换后出现NA,说明里面有非数字字符,需要先清理。
第三,异常值处理。散点图对异常值非常敏感,一个极端的点会把整个坐标轴拉长,导致其他点挤在一起。边际分布也会因为异常值出现长长的拖尾。我的做法是先用箱线图或者summary()看一下变量的范围,如果发现明显偏离的异常值,可以考虑用filter()去掉,或者用scale_x_continuous(limits = c(...))限制坐标轴范围。但要注意,限制坐标轴范围只是视觉上截断,数据本身还在,边际分布的计算也会受影响。如果要去掉异常值,最好在数据层面操作。
第四,数据量控制。如果样本量超过几万,散点图会变得非常卡,边际分布的计算也会变慢。这时候可以考虑随机抽样,比如用sample_n(5000)抽5000个点画图。抽样不会改变分布形态,但能大幅提升绘图速度。如果不想抽样,可以用geom_point(alpha = 0.1)降低透明度,或者用geom_hex()做六边形分箱,但后者和ggMarginal的兼容性不太好。
3.2 ggMarginal核心参数详解
ggMarginal()的参数不多,但每个都很关键。我把最常用的几个列出来,配上解释和推荐值。
| 参数 | 作用 | 推荐值 | 注意事项 |
|---|---|---|---|
p | 输入的ggplot对象 | 必填 | 必须是散点图,其他类型可能不兼容 |
type | 边际图类型 | "density" | 可选"histogram"、"boxplot"、"violin" |
margins | 边际图位置 | "both" | 可选"x"或"y",只画一个 |
size | 主图与边际图的大小比例 | 5 | 默认5,数值越大主图占比越大 |
groupColour | 是否按组着色线条 | FALSE | 有分组时设为TRUE |
groupFill | 是否按组填充 | FALSE | 有分组时设为TRUE |
alpha | 填充透明度 | 0.5 | 0.3到0.7之间比较合适 |
bins | 直方图bin数量 | 30 | 仅type="histogram"时有效 |
xparams | x轴边际图的额外参数 | list() | 可传fill、color等 |
yparams | y轴边际图的额外参数 | list() | 同上 |
这里重点说几个容易踩坑的地方。
size参数控制的是主图和边际图的比例。默认值5意味着主图占5份,边际图占1份。如果你觉得边际图太小看不清,可以调到3或者4。但太小了主图又会被压缩,一般3到7之间比较平衡。
xparams和yparams是列表,里面可以传ggplot2的图层参数。比如你想让x轴边际图的填充色是浅蓝色,可以写xparams = list(fill = "lightblue")。但要注意,如果同时设置了groupFill = TRUE,这里的fill会被覆盖,所以分组和自定义颜色不要同时用。
还有一个隐藏坑:ggMarginal默认会继承主图的主题,但边际图的坐标轴标签、刻度线有时候会显得很挤。你可以在xparams和yparams里传theme()来调整,比如xparams = list(theme(axis.text = element_blank()))把边际图的坐标轴文字去掉,让图更干净。
3.3 主题与配色的一致性处理
一张专业的图,配色和主题必须统一。ggMarginal生成的边际图默认用的是ggplot2的默认主题(灰色背景、白色网格线),如果你主图用了自定义主题,比如theme_minimal()或者theme_bw(),边际图会显得格格不入。
解决办法是在画主图的时候就定义好主题,ggMarginal会尽量继承。但有些主题元素(比如背景色)在边际图里可能不会完全一致,这时候就需要在xparams和yparams里手动补上。比如:
xparams = list(theme_minimal(), theme(axis.title = element_blank()))配色方面,如果你在主图里用了scale_color_brewer()或者scale_fill_manual(),边际图的颜色不会自动跟随。你需要手动在xparams和yparams里指定相同的颜色。这确实有点麻烦,但为了图的一致性,值得花这几分钟。
我的习惯是:先定好一个配色方案,比如用RColorBrewer的"Set2"调色板,然后主图和边际图都用同一组颜色。如果组数少,直接手动指定十六进制色值,比如c("#66C2A5", "#FC8D62", "#8DA0CB"),这样最可控。
4. 完整实操流程与代码实现
4.1 环境准备与依赖安装
先把需要的包装好。ggplot2和ggExtra是核心,dplyr用来做数据处理,palmerpenguins提供一个干净的内置数据集用来演示。如果你不想用内置数据,换成自己的数据也行,但建议先用内置数据跑通流程,再换自己的数据。
# 安装包(如果还没装的话) install.packages(c("ggplot2", "ggExtra", "dplyr", "palmerpenguins")) # 加载包 library(ggplot2) library(ggExtra) library(dplyr) library(palmerpenguins)palmerpenguins这个数据集很干净,有344个样本,包含企鹅的喙长、喙深、鳍长、体重和物种等信息。我们用它来演示,因为变量都是连续型的,而且有分组变量(物种),很适合展示分组边际分布的效果。
4.2 基础散点图加边际分布
先画一个最基础的版本,不加分组,只看两个变量的关系。用喙长(bill_length_mm)做x轴,喙深(bill_depth_mm)做y轴。
# 基础散点图 p <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) + geom_point(alpha = 0.6, color = "#2c7fb8", size = 2) + theme_minimal() + labs(x = "喙长 (mm)", y = "喙深 (mm)") # 加边际密度图 p_marginal <- ggMarginal(p, type = "density", size = 5, alpha = 0.5, fill = "lightblue") # 显示 p_marginal这段代码跑出来,你会看到主图是散点,顶部和右侧各有一条密度曲线。alpha = 0.5让填充半透明,fill = "lightblue"指定填充色。size = 5是默认比例,主图占5份,边际图占1份。
如果你觉得密度曲线太细看不清,可以加粗线条:
p_marginal <- ggMarginal(p, type = "density", size = 5, alpha = 0.5, fill = "lightblue", xparams = list(size = 1.2), yparams = list(size = 1.2))size = 1.2控制的是密度曲线的线宽,默认是0.5,调到1以上会明显变粗。
4.3 分组边际分布的实现
现在加上物种分组,用颜色区分。这里有个关键点:ggMarginal默认不会按组着色边际图,需要显式设置groupColour = TRUE和groupFill = TRUE。
# 分组散点图 p_grouped <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm, color = species)) + geom_point(alpha = 0.7, size = 2) + scale_color_brewer(palette = "Set2") + theme_minimal() + labs(x = "喙长 (mm)", y = "喙深 (mm)", color = "物种") # 分组边际密度图 p_grouped_marginal <- ggMarginal(p_grouped, type = "density", size = 5, alpha = 0.4, groupColour = TRUE, groupFill = TRUE) p_grouped_marginal跑出来之后,边际图会按物种分成三条不同颜色的密度曲线,重叠区域的颜色会叠加。alpha = 0.4让叠加更明显,但又不至于太浑浊。
这里有个细节:scale_color_brewer(palette = "Set2")指定了主图的颜色,但边际图的颜色是ggMarginal自己处理的,它默认用的是ggplot2的默认色盘。如果你想让边际图也用"Set2"的颜色,需要在xparams和yparams里手动指定:
p_grouped_marginal <- ggMarginal(p_grouped, type = "density", size = 5, alpha = 0.4, groupColour = TRUE, groupFill = TRUE, xparams = list(fill = c("#66C2A5", "#FC8D62", "#8DA0CB")), yparams = list(fill = c("#66C2A5", "#FC8D62", "#8DA0CB")))这样颜色就完全一致了。注意fill传的是一个向量,顺序要和因子水平的顺序一致。用levels(penguins$species)可以查看顺序。
4.4 直方图与箱线图边际图的切换
密度曲线看多了会腻,换个直方图试试。直方图的好处是能看出具体的频数分布,尤其是当数据有明确的区间聚集时。
# 直方图边际图 p_hist <- ggMarginal(p, type = "histogram", size = 5, bins = 25, fill = "steelblue", alpha = 0.6) p_histbins = 25控制直方图的柱子数量。这个值需要根据数据范围调,太少会太粗,太多会太碎。一般来说,样本量在300左右,20到30个bin比较合适。你可以多试几个值,看哪个最能反映分布形态。
箱线图边际图更适合展示概要信息:
# 箱线图边际图 p_box <- ggMarginal(p, type = "boxplot", size = 5, fill = "lightgreen", alpha = 0.7) p_box箱线图边际图不会显示具体的分布形态,但中位数和四分位距一目了然。如果你的报告需要简洁,箱线图是很好的选择。
小提琴图是箱线图和密度曲线的结合:
# 小提琴图边际图 p_violin <- ggMarginal(p, type = "violin", size = 5, fill = "lightpink", alpha = 0.6) p_violin小提琴图在样本量大于100时效果不错,但样本量小的时候核密度估计会不稳定,出现奇怪的形状。企鹅数据有344个样本,用小提琴图没问题。
4.5 自定义布局与导出高分辨率图片
ggMarginal生成的图默认是ggplot对象,可以用ggsave()导出。但要注意,ggMarginal返回的对象类型是ggExtraPlot,ggsave()是支持的,但有时候需要显式指定设备。
# 导出为PNG,300 DPI ggsave("marginal_plot.png", plot = p_grouped_marginal, width = 8, height = 6, dpi = 300) # 导出为PDF,矢量图 ggsave("marginal_plot.pdf", plot = p_grouped_marginal, width = 8, height = 6)width和height的单位是英寸,dpi = 300是印刷级别的分辨率。如果是放在网页上,150 DPI就够了,文件会小很多。
如果你觉得默认的布局比例不合适,可以调size参数。比如想让边际图更大一点:
p_large_marginal <- ggMarginal(p_grouped, type = "density", size = 3, # 主图占3份,边际图占1份 alpha = 0.4, groupColour = TRUE, groupFill = TRUE)size = 3意味着主图和边际图的比例是3:1,边际图会明显变大。但主图会被压缩,点会显得更挤。一般3到7之间比较平衡,具体看你的输出尺寸。
还有一个技巧:如果边际图的坐标轴标签和主图重叠,可以在xparams和yparams里去掉坐标轴文字:
p_clean <- ggMarginal(p_grouped, type = "density", size = 5, alpha = 0.4, groupColour = TRUE, groupFill = TRUE, xparams = list(theme(axis.text = element_blank(), axis.title = element_blank())), yparams = list(theme(axis.text = element_blank(), axis.title = element_blank())))这样边际图就只有曲线,没有坐标轴文字,整体更干净。但要注意,去掉坐标轴文字后,读者可能无法准确读出边际图的数值,所以如果数值很重要,还是保留比较好。
5. 常见问题与排查技巧实录
5.1 边际图不显示或显示不全
这是最常见的问题。跑完ggMarginal()之后,图出来了,但边际图是空白的,或者只有一条线。原因通常有几个:
第一,数据里有缺失值。ggplot2画主图时会自动忽略缺失值,但ggMarginal计算边际分布时可能没有正确处理,导致边际图为空。解决办法是在画图前用drop_na()去掉缺失值:
penguins_clean <- penguins %>% drop_na(bill_length_mm, bill_depth_mm)第二,变量类型不对。如果x或y是字符型或者因子,ggMarginal无法计算密度或直方图。用class()检查一下,必要时转换。
第三,type参数和数据类型不匹配。比如用type = "density"但数据只有几个点,核密度估计会失败。这时候换成type = "histogram"或者type = "boxplot"。
第四,size参数太小。如果size设成10以上,边际图会被压缩到几乎看不见。调回5左右试试。
5.2 分组颜色不一致或重叠混乱
分组边际图最常见的问题是颜色不一致:主图用了自定义色盘,边际图还是默认色盘。解决办法前面提过,在xparams和yparams里手动指定fill向量。
另一个问题是组间重叠太严重,边际图看起来一团糟。这时候可以:
- 降低
alpha到0.3,让重叠区域的颜色叠加更明显 - 减少组数,只保留最重要的两组
- 改用分面(facet)代替颜色分组
分面的做法是在主图里加facet_wrap(~ species),然后ggMarginal会对每个分面单独加边际图。但要注意,ggMarginal对分面的支持有限,有时候会出错。如果分面不行,就手动用cowplot拼图。
5.3 图形导出后模糊或比例失调
导出图片模糊,通常是dpi设低了。ggsave()默认的dpi是300,但如果你的输出尺寸很小,比如width = 4, height = 3,300 DPI出来也只有1200x900像素,放大看还是会糊。解决办法是增大输出尺寸,或者提高dpi到600。
比例失调通常是width和height的比例和图形本身的比例不匹配。ggMarginal生成的图,主图是正方形的比例比较好看,所以width和height最好接近1:1。如果你设成width = 10, height = 4,主图会被拉扁,边际图也会变形。
还有一个坑:ggsave()导出ggExtraPlot对象时,有时候会丢失边际图。这是因为ggsave()默认用的是ggplot2的导出方法,而ggExtraPlot是ggExtra的自定义对象。解决办法是用png()或pdf()设备手动导出:
png("marginal_plot.png", width = 8, height = 6, units = "in", res = 300) print(p_grouped_marginal) dev.off()这样最稳妥,不会丢图层。
5.4 大数据量下的性能优化
样本量超过1万时,ggMarginal会明显变慢,因为密度估计和直方图计算都是O(n)的复杂度。优化方法有几个:
第一,随机抽样。用sample_n(5000)抽5000个点,分布形态基本不变,但速度会快很多。
第二,用geom_point(alpha = 0.1)降低透明度,减少渲染负担。但ggMarginal的边际图计算还是全量的,所以这个方法只对主图渲染有帮助。
第三,改用geom_hex()做六边形分箱,但ggMarginal不支持geom_hex,需要手动拼图。
第四,如果只是探索性分析,可以先用小样本跑通流程,确定参数后再用全量数据出最终图。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 边际图空白 | 数据有缺失值 | 用drop_na()清理 |
| 边际图只有一条线 | 变量类型不对 | 转换为numeric |
| 分组颜色不一致 | 未指定fill向量 | 在xparams/yparams里传fill |
| 导出后模糊 | dpi太低 | 提高dpi到600或增大尺寸 |
| 导出后丢边际图 | ggsave兼容性问题 | 用png()/pdf()手动导出 |
| 运行速度慢 | 样本量太大 | 随机抽样或降低透明度 |
| 边际图坐标轴重叠 | 布局太挤 | 去掉边际图坐标轴文字 |
| 密度曲线太毛糙 | 带宽太小 | 调大bw参数 |
6. 进阶技巧与个人实操心得
6.1 用patchwork手动拼图实现完全自定义
ggMarginal虽然方便,但灵活性有限。如果你想要完全自定义的布局,比如边际图放在左侧、或者主图和边际图之间加间距、或者边际图用不同的主题,那就需要手动拼图。
patchwork包是目前最优雅的拼图方案。核心思路是:分别画主散点图、x轴边际图、y轴边际图,然后用/和|操作符组合。
library(patchwork) # 主散点图(去掉x和y轴标签,因为边际图会提供) p_main <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm, color = species)) + geom_point(alpha = 0.7, size = 2) + scale_color_brewer(palette = "Set2") + theme_minimal() + theme(axis.title.x = element_blank(), axis.title.y = element_blank(), legend.position = "none") # x轴边际密度图 p_x <- ggplot(penguins, aes(x = bill_length_mm, fill = species)) + geom_density(alpha = 0.4) + scale_fill_brewer(palette = "Set2") + theme_minimal() + theme(axis.title = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), legend.position = "none") # y轴边际密度图(注意coord_flip) p_y <- ggplot(penguins, aes(x = bill_depth_mm, fill = species)) + geom_density(alpha = 0.4) + scale_fill_brewer(palette = "Set2") + theme_minimal() + coord_flip() + theme(axis.title = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank(), legend.position = "none") # 拼图:顶部是p_x,左侧是p_y,中间是p_main layout <- p_x + plot_spacer() + p_main + p_y + plot_layout(ncol = 2, widths = c(4, 1), heights = c(1, 4)) layout这个方案的优点是每个部分都可以独立控制,主题、颜色、坐标轴都能精确调整。缺点是代码量大,而且需要手动处理坐标轴对齐。plot_spacer()用来占位,让布局正确。widths和heights控制比例,这里主图占4份,边际图占1份。
手动拼图还有一个好处:你可以用不同的几何对象。比如x轴边际图用直方图,y轴边际图用箱线图,ggMarginal虽然也支持分别指定,但手动拼图更灵活。
6.2 边际分布图的常见误用与避坑
边际分布图虽然好用,但有几个常见的误用场景,我踩过坑,这里分享一下。
误用一:用边际图代替联合分布分析。边际图展示的是单变量分布,它不能告诉你两个变量之间的条件关系。比如x和y的边际分布都是单峰,但联合分布可能是双峰(辛普森悖论的视觉版本)。所以边际图是补充,不是替代,主散点图才是核心。
误用二:分组太多导致边际图不可读。我见过有人把10个组的边际密度曲线叠在一起,结果就是一团彩色乱麻。如果组数超过5个,建议要么合并小组,要么用分面,要么只画总体边际图,分组信息在主图里用颜色表示就够了。
误用三:忽略样本量对密度估计的影响。样本量小于50时,密度曲线会非常不稳定,出现很多虚假的峰。这时候用直方图或者箱线图更诚实。样本量小于20时,甚至箱线图都不太可靠,最好直接看散点图。
误用四:坐标轴范围不一致。主图和边际图的坐标轴必须严格对齐,否则读者会误读。ggMarginal自动处理了对齐,但手动拼图时很容易出错。检查方法是看主图的x轴范围和边际图的x轴范围是否一致,如果不一致,用coord_cartesian()或者scale_x_continuous(limits = ...)统一。
6.3 个人实操心得:从探索到展示的完整工作流
我自己的习惯是分两步走:探索阶段和展示阶段。
探索阶段,我用ggMarginal快速出图,type = "density",alpha = 0.5,不加分组或者只加最重要的分组。目的是快速看数据形态,发现异常值和有趣的现象。这个阶段不追求美观,追求速度。
展示阶段,我会花时间调主题、配色、布局。如果ggMarginal能满足需求,就用它,代码简洁;如果需要更精细的控制,就用patchwork手动拼图。导出时用png()设备,res = 300,尺寸根据输出场景定。如果是论文插图,用PDF矢量图;如果是PPT,用PNG,150 DPI就够了。
还有一个心得:边际图的类型不要一成不变。如果数据有明显的偏态,密度曲线会显示长长的拖尾,这时候直方图可能更直观。如果数据有异常值,箱线图能直接标出来。多试几种类型,选最能说明问题的那一种。
最后分享一个小技巧:如果你的数据有时间维度,比如按月份分组,可以在边际图里用facet_wrap按月份分面,这样能看到分布随时间的变化。但ggMarginal对分面的支持不好,需要用patchwork手动拼图。具体做法是先用facet_wrap画主图,然后对每个分面单独提取数据画边际图,再用patchwork组合。这个稍微复杂一点,但效果很好,适合做时间序列的探索性分析。
这个内容后续还可以这样扩展:把边际分布图扩展到三维,用plotly做交互式散点图,鼠标悬停时显示边际分布;或者用gganimate做动画,展示分布随某个变量的变化过程。这些都是很有意思的方向,等有时间再折腾。