【科研绘图复刻】经典边际密度散点回归图

前言

最近在做某类生态现象的环境驱动因子,恰好被这篇论文的图片吸引。图片虽然看着复杂,仔细分析拆解,其实也就是平常的那些主要的图杂糅在一起,现特将复刻的代码放出来,供有需要的人参考。

复刻图片如下:

图片来源

Fredston, A.L., Cheung, W.W.L., Frölicher, T.L. et al. Marine heatwaves are not a dominant driver of change in demersal fishes. Nature 621, 324--329 (2023). https://doi.org/10.1038/s41586-023-06449-y

原图信息:

  • x:MHW cumulative intensity(海洋热浪累积强度,℃・days)
  • a 图 y:Biomass log ratio;b 图 y:Absolute biomass log ratio
  • 线性回归 R²≈0.00/0.01,P 不显著,拟合线几乎水平
  • 密度图:红色(MHW),蓝色 (无 MHW)

首先来讲讲这个图叫什么名字,有什么用。

边际密度散点回归图将(散点 + 线性拟合 + 置信带 + 边缘 KDE 密度)本质上把「关系」和「分布」压缩进一张画布。

核心优势------信息密度高且不牺牲细节:一张图里同时承载个体观测、整体趋势、估计不确定性和分布形态,特别适合用来论证「某个环境因子并非主要驱动因素」这类需要同时展示「趋势」和「分布」的结论。


复刻思路

图中主要要素

  1. 主坐标轴:散点 + 线性拟合直线 + 灰色 95% 置信区间填充 + 重点样本箭头标注(text + 箭头)
  2. 右侧窄坐标轴:y 方向的 KDE 核密度曲线,分两组(红色 = 发生 MHW,蓝色 = 无 MHW)

复刻所需数据

1.事件总量

2.有MHW次数

3.无MHW次数

4.每次事件的MHW累积强度

5.每次事件的生物量(取对数)

6.事件标记,1=有MHW,0=无MHW

|--------|---------|--------|
| 事件标记 | MHW累积强度 | 生物量 |
| 1 | 25 | 0.2 |
| 0 | 0 | |
| ...... | ...... | ...... |
| 1 | 30 | 0.3 |

复刻方法

首先生成相关数据。

Matlab 复制代码
n_total = 369;
n_mhw = 139;    %有MHW
n_no = 230;     %无MHW
x = rand(n_total,1)*80;    %MHW累积强度
y = randn(n_total,1)*0.4;  %biomass log ratio
mhw_flag = [ones(n_mhw,1);zeros(n_no,1)]; %1=有MHW,0=无MHW

设置画布。

Matlab 复制代码
fig = figure('Position',[100,100,1200,600],'Color','w');
ax_main = axes('Position',[0.06,0.12,0.75,0.82]);
ax_kde  = axes('Position',[0.82,0.12,0.12,0.82]);
hold(ax_main,'on');
hold(ax_kde,'on');

左侧主图 先画散点图。

Matlab 复制代码
scatter(ax_main, x, y, 22, 'k','filled','MarkerFaceAlpha',0.8);

然后是拟合。

Matlab 复制代码
tbl = table(x,y,'VariableNames',{'x','y'});
mdl = fitlm(tbl,'y~x');
x_fit = linspace(min(x),max(x),200)';
[y_pred,ci] = predict(mdl,table(x_fit,'VariableNames',{'x'}));

接着是置信区间。

Matlab 复制代码
patch(ax_main,[x_fit;flipud(x_fit)],[ci(:,1);flipud(ci(:,2))],...
    [0.7 0.7 0.7],'FaceAlpha',0.4,'EdgeColor','none');

再加上一条拟合中线,即黑色直线,表示变化趋势。

Matlab 复制代码
plot(ax_main, x_fit, y_pred, 'k-','LineWidth',1.4);

最后再放一个零点虚线,左侧主图完成!

Matlab 复制代码
yline(ax_main,0,'k--','LineWidth',0.8);

右侧KDE密度图,需要调用函数 ksdensity计算。

Matlab 复制代码
y_mhw = y(mhw_flag==1);
y_no  = y(mhw_flag==0);
[f_mhw,yi_mhw] = ksdensity(y_mhw);
[f_no,yi_no]   = ksdensity(y_no);

然后就是填充曲线,填充之前做了一点缩放。

Matlab 复制代码
% 缩放密度宽度
scale_kde = 12;
% 红色:MHW
fill(ax_kde, f_mhw*scale_kde, yi_mhw, [0.75,0.2,0.3],'linestyle','none','FaceAlpha',0.6,'Marker','none');
plot(ax_kde, f_mhw*scale_kde, yi_mhw, 'r-','LineWidth',1.2);
% 蓝色:无MHW
fill(ax_kde, f_no*scale_kde, yi_no, [0.2,0.4,0.75],'linestyle','none','FaceAlpha',0.4,'Marker','none');
plot(ax_kde, f_no*scale_kde, yi_no, 'b-','LineWidth',1.2);

最后美化坐标轴。

Matlab 复制代码
xlabel(ax_main,'MHW cumulative intensity (°C-days)');
ylabel(ax_main,'Biomass log ratio');
box(ax_main,'on');
xlim(ax_main,[0,80]);
set(ax_main,'linewidth',1.5,'fontsize',14,'fontname','Times New Roman');
xlim(ax_kde,[0,max([f_mhw,f_no])*scale_kde]);
ylim(ax_kde, ylim(ax_main));
set(ax_kde,'XColor','none','YColor','none','YTickLabel','');

复刻结果

Tada,搞定!

完整版代码

Matlab 复制代码
clear; clc; close all;
rng(42); %固定随机种子

% ==========  模拟数据   ==========
n_total = 369;
n_mhw = 139;    %有MHW
n_no = 230;     %无MHW
x = rand(n_total,1)*80;    %MHW累积强度
y = randn(n_total,1)*0.4;  %biomass log ratio
mhw_flag = [ones(n_mhw,1);zeros(n_no,1)]; %1=有MHW,0=无MHW

%% ==========  作图  ==========
fig = figure('Position',[100,100,1200,600],'Color','w');
ax_main = axes('Position',[0.06,0.12,0.75,0.82]);
ax_kde  = axes('Position',[0.82,0.12,0.12,0.82]);

hold(ax_main,'on');
hold(ax_kde,'on');

% ----  左侧主图 ----
scatter(ax_main, x, y, 22, 'k','filled','MarkerFaceAlpha',0.8);
% ----  线性拟合 + 95%置信区间 ----
tbl = table(x,y,'VariableNames',{'x','y'});
mdl = fitlm(tbl,'y~x');
x_fit = linspace(min(x),max(x),200)';
[y_pred,ci] = predict(mdl,table(x_fit,'VariableNames',{'x'}));
% 置信区间
patch(ax_main,[x_fit;flipud(x_fit)],[ci(:,1);flipud(ci(:,2))],...
    [0.7 0.7 0.7],'FaceAlpha',0.4,'EdgeColor','none');
% 拟合中线
plot(ax_main, x_fit, y_pred, 'k-','LineWidth',1.4);
% y=0虚线
yline(ax_main,0,'k--','LineWidth',0.8);

% ----  右侧KDE密度图 ----
y_mhw = y(mhw_flag==1);
y_no  = y(mhw_flag==0);
[f_mhw,yi_mhw] = ksdensity(y_mhw);
[f_no,yi_no]   = ksdensity(y_no);
% 缩放密度宽度
scale_kde = 12;
% 红色:MHW
fill(ax_kde, f_mhw*scale_kde, yi_mhw, [0.75,0.2,0.3],'linestyle','none','FaceAlpha',0.6,'Marker','none');
plot(ax_kde, f_mhw*scale_kde, yi_mhw, 'r-','LineWidth',1.2);
% 蓝色:无MHW
fill(ax_kde, f_no*scale_kde, yi_no, [0.2,0.4,0.75],'linestyle','none','FaceAlpha',0.4,'Marker','none');
plot(ax_kde, f_no*scale_kde, yi_no, 'b-','LineWidth',1.2);
hold on

% ---- 坐标轴设置 ----
xlabel(ax_main,'MHW cumulative intensity (°C-days)');
ylabel(ax_main,'Biomass log ratio');
box(ax_main,'on');
xlim(ax_main,[0,80]);
set(ax_main,'linewidth',1.5,'fontsize',14,'fontname','Times New Roman');
xlim(ax_kde,[0,max([f_mhw,f_no])*scale_kde]);
ylim(ax_kde, ylim(ax_main));
set(ax_kde,'XColor','none','YColor','none','YTickLabel','');
相关推荐
严肃小白兔5 天前
MATLAB 绘图与科研论文插图制作:图形设计、统计表达与矢量导出
开发语言·matlab·科研绘图
余丁,微生信1 个月前
《Nature Genetics》树图实操:五步把基因和功能分类缩进一张图
信息可视化·论文插图·生信分析·科研绘图·科学科普·nature genetics·树图
沐风老师1 个月前
科研绘图ChemicalStructures插件:3DMAX一键生成分子结构科研绘图模型
3dmax插件·科研绘图·3dmax华学结构·3dmax分子建模
imbackneverdie2 个月前
论文中的机制图、原理图用什么软件画?AI生成可编辑矢量图的方法分享
人工智能·深度学习·计算机视觉·aigc·科研·ai绘图·科研绘图
实用科研工具箱3 个月前
生物医学矢量绘图工具|四款主流工具剖析
科研绘图·科研绘图工具·科研绘图网站
青春不败 177-3266-05203 个月前
R语言数据统计分析与ggplot2高级绘图
r语言·生态学·科研绘图·统计学·ggplot2·环境科学
实用科研工具箱4 个月前
生物医学科研绘图工具推荐:6个工具实测横评
科研绘图·科研绘图工具·科研绘图网站
imbackneverdie6 个月前
论文/课题/组会PPT技术路线图绘制完整教程
人工智能·信息可视化·aigc·科研·论文写作·科研绘图·ai工具
实用科研工具箱6 个月前
科研绘图工具全对比:BioGDP、BioRender、GraphPad Prism、Origin、Adobe Illustrator 哪个更适合你?
科研绘图·科研绘图工具·科研绘图网站