嘿,真的是好久不见,最近有点过于忙了,今天更一个好久之前粉丝问的半小提琴图的绘制方法,要复刻这张图:
绘制效果如下:
还是挺好看的,下面直接进入正题:
教程部分
0 数据准备
这里随机生成了两组数据DataL和DataR,分别是半小提琴图左侧小提琴的数据和右侧小提琴的数据,同时需要设置好各个位置标签变量名,类名,显著性结果等文本信息。
Name = {'AAA', 'BBB', 'CCC'};
ClassName = {'Ambient','WarNing'};
Condition = {'ns','*','**'};
% 随机生成数据
rng(2)
offset = repmat(rand(1, 3), [100,1]).*2;
DataL = rand(100, 3) + offset;
DataR = rand(100, 3) + offset;
1 其他参数
% 配色
CList = [153,153,253; 255,153,154]./255;
% 此参数用于调整小提琴图宽度
width = .36;
2 坐标区域修饰
生成一个空的坐标区域,并设置字体,X轴标签等信息:
% 坐标区域修饰
ax = gca;
ax.NextPlot = 'add';
ax.Box = 'on';
ax.XGrid = 'on';
ax.YGrid = 'on';
ax.XTick = 1:length(Name);
ax.XTickLabel = Name;
ax.FontName = 'Times New Roman';
ax.FontSize = 15;
ax.XTickLabelRotation = 30;
ax.XLim = [0, length(Name)] + .5;
3 绘制小提琴图
使用ksdensity
函数计算核密度,使用quantile
函数计算分位数,使用median
计算中位数,并循环绘图:
for i = 1:length(Name)
% 绘制核密度曲线
[fL, yiL] = ksdensity(DataL(:, i));
[fR, yiR] = ksdensity(DataR(:, i));
fill(ax, (i - fL.*width), yiL, CList(1,:), 'EdgeColor','none', 'FaceAlpha',.5)
fill(ax, (i + fR.*width), yiR, CList(2,:), 'EdgeColor','none', 'FaceAlpha',.5)
% 绘制四分位数线
qt25L = quantile(DataL(:, i), 0.25); qt75L = quantile(DataL(:, i), 0.75);
plot(ax, [-1, 1, nan, -1, 1, nan, 0, 0].*.05 + i - .08, [qt75L, qt75L, nan, qt25L, qt25L, nan, qt75L, qt25L], 'LineWidth',1, 'Color','k')
qt25R = quantile(DataR(:, i), 0.25); qt75R = quantile(DataR(:, i), 0.75);
plot(ax, [-1, 1, nan, -1, 1, nan, 0, 0].*.05 + i + .08, [qt75R, qt75R, nan, qt25R, qt25R, nan, qt75R, qt25R], 'LineWidth',1, 'Color','k')
% 绘制中位数点
medL = median(DataL(:, i));
scatter(i - .08, medL, 20, 'filled', 'CData',[0,0,0]);
medR = median(DataR(:, i));
scatter(i + .08, medR, 20, 'filled', 'CData',[0,0,0]);
% 绘制显著性标签
text(ax, i, max([yiL(:);yiR(:)]), Condition{i},...
'FontSize',16, 'FontName','Times New Roman',...
'HorizontalAlignment','center', 'VerticalAlignment','baseline')
end
4 绘制图例
在坐标区域外再画两个填充矩形用来当作图例的句柄:
% 绘制图例
fillHdl(1) = fill(ax, [-1,-2,-1], [0,0,1], CList(1,:), 'EdgeColor','none', 'FaceAlpha',.5);
fillHdl(2) = fill(ax, [-1,-2,-1], [0,0,1], CList(2,:), 'EdgeColor','none', 'FaceAlpha',.5);
lgdHdl = legend(fillHdl, ClassName, 'Location','best', 'Box','off');
lgdHdl.ItemTokenSize=[20,20];
完整代码
% half violin plot
Name = {'AAA', 'BBB', 'CCC'};
ClassName = {'Ambient','WarNing'};
Condition = {'ns','*','**'};
% 随机生成数据
rng(2)
offset = repmat(rand(1, 3), [100,1]).*2;
DataL = rand(100, 3) + offset;
DataR = rand(100, 3) + offset;
% 配色
CList = [153,153,253; 255,153,154]./255;
% CList = [0,64,115; 254,103,110]./255;
% 此参数用于调整小提琴图宽度
width = .36;
% 坐标区域修饰
ax = gca;
ax.NextPlot = 'add';
ax.Box = 'on';
ax.XGrid = 'on';
ax.YGrid = 'on';
ax.XTick = 1:length(Name);
ax.XTickLabel = Name;
ax.FontName = 'Times New Roman';
ax.FontSize = 15;
ax.XTickLabelRotation = 30;
ax.XLim = [0, length(Name)] + .5;
for i = 1:length(Name)
% 绘制核密度曲线
[fL, yiL] = ksdensity(DataL(:, i));
[fR, yiR] = ksdensity(DataR(:, i));
fill(ax, (i - fL.*width), yiL, CList(1,:), 'EdgeColor','none', 'FaceAlpha',.5)
fill(ax, (i + fR.*width), yiR, CList(2,:), 'EdgeColor','none', 'FaceAlpha',.5)
% 绘制四分位数线
qt25L = quantile(DataL(:, i), 0.25); qt75L = quantile(DataL(:, i), 0.75);
plot(ax, [-1, 1, nan, -1, 1, nan, 0, 0].*.05 + i - .08, [qt75L, qt75L, nan, qt25L, qt25L, nan, qt75L, qt25L], 'LineWidth',1, 'Color','k')
qt25R = quantile(DataR(:, i), 0.25); qt75R = quantile(DataR(:, i), 0.75);
plot(ax, [-1, 1, nan, -1, 1, nan, 0, 0].*.05 + i + .08, [qt75R, qt75R, nan, qt25R, qt25R, nan, qt75R, qt25R], 'LineWidth',1, 'Color','k')
% 绘制中位数点
medL = median(DataL(:, i));
scatter(i - .08, medL, 20, 'filled', 'CData',[0,0,0]);
medR = median(DataR(:, i));
scatter(i + .08, medR, 20, 'filled', 'CData',[0,0,0]);
% 绘制显著性标签
text(ax, i, max([yiL(:);yiR(:)]), Condition{i},...
'FontSize',16, 'FontName','Times New Roman',...
'HorizontalAlignment','center', 'VerticalAlignment','baseline')
end
% 绘制图例
fillHdl(1) = fill(ax, [-1,-2,-1], [0,0,1], CList(1,:), 'EdgeColor','none', 'FaceAlpha',.5);
fillHdl(2) = fill(ax, [-1,-2,-1], [0,0,1], CList(2,:), 'EdgeColor','none', 'FaceAlpha',.5);
lgdHdl = legend(fillHdl, ClassName, 'Location','best', 'Box','off');
lgdHdl.ItemTokenSize=[20,20];