转载请注明本文链接
及文章作者:slandarer
hey大家好久不见,本期带来一篇绘图复刻,居然已经出到第11篇了,不知道有朝一日有没有机会破百,本期绘制的是《PNAS》期刊中pnas.2200057120文章的figure03,文章题目为Intranasal delivery of full-length anti-Nogo-A antibody: A potential alternative route for therapeutic antibodies to central nervous system targets可在以下网址下载该文章pdf原文:
https://www.pnas.org/doi/epdf/10.1073/pnas.2200057120
本期要复刻的绘图长这样:
本人复刻的效果长这样:
虽然还是有些许不同但是大部分元素已经还原出来了,以下为教程部分:
请尽量使用新版本的MATLAB,比较旧版本的MATLAB无XJitter功能,本人目前较忙近期不会有空开发类似功能,因此在我未有空开发相关功能前,请尽量使用比较新的版本!!!!!!!!~
教程部分
0 数据准备
这里随便随机生成了一点数据,文章中的五个颜色都被我提取了出来,我们这次先取用前两个颜色:
figure('Units','normalized','Position',[.2,.3,.36,.45],'Color','w');
rng(24)
% 随机生成了两组数据
DataA = rand(7,1)*ones(1,5).*2+rand(7,5)./3.5;
DataB = rand(7,1)*ones(1,5)./2+rand(7,5)./3.5;
meanData = [mean(DataA,2), mean(DataB,2)];
% 文章图片中的颜色数据
CList = [188,188,240; 160,161,166; 237,187,128;
177,202,233; 245,185,192]./255;
CList = CList([1,2],:);
% CList = CList([4,5],:);
% 横坐标标签文本
NameList = {'Cortex';
'Hippocampus';
'Cerebellum';
'Brainstem';
'Cervical spinal cord';
'Thoracic spinal cord';
'Lumbar spinal cord'};
1 基础绘图
柱状图
hold on
% 绘制柱状图 ---------------------------------------------------------------
barHdl = bar(meanData,'EdgeColor','none','FaceAlpha',.5,'BarWidth',.7);
% 修改配色
barHdl(1).FaceColor = CList(1,:);
barHdl(2).FaceColor = CList(2,:);
散点图
% 绘制散点图 ---------------------------------------------------------------
XA = barHdl(1).XEndPoints.'*ones(1,size(DataA,2));
scatter(XA(:),DataA(:),55,'filled','o','MarkerEdgeColor','k','LineWidth',.8,...
'CData',CList(1,:),'XJitter','rand','XJitterWidth',0.15)
XB = barHdl(2).XEndPoints.'*ones(1,size(DataB,2));
scatter(XB(:),DataB(:),55,'filled','o','MarkerEdgeColor','k','LineWidth',.8,...
'CData',CList(2,:),'XJitter','rand','XJitterWidth',0.15)
误差棒
这里直接用的标准差:
% 绘制误差棒 ---------------------------------------------------------------
errorbar(barHdl(1).XEndPoints,meanData(:,1),std(DataA,0,2),'vertical',...
'LineStyle','none','LineWidth',1,'Color','k')
errorbar(barHdl(2).XEndPoints,meanData(:,2),std(DataB,0,2),'vertical',...
'LineStyle','none','LineWidth',1,'Color','k')
3 坐标区域简单修饰
主要是调整字体,并修改X轴刻度标签:
% 绘制误差棒 ---------------------------------------------------------------
errorbar(barHdl(1).XEndPoints,meanData(:,1),std(DataA,0,2),'vertical',...
'LineStyle','none','LineWidth',1,'Color','k')
errorbar(barHdl(2).XEndPoints,meanData(:,2),std(DataB,0,2),'vertical',...
'LineStyle','none','LineWidth',1,'Color','k')
4 截断坐标轴
这里用的我之前写的一个函数,为了怕大家找起来麻烦,放在了文末及文末的gitee仓库里。
以下是调用文末截断坐标轴函数实现的:
% 截断坐标轴
truncAxis('y',[1,1.4]);
5 坐标轴精修
包括隐藏baseline,添加Y轴标签,修改坐标轴粗细及刻度方向等:
fig = gcf;
ax1 = fig.Children(1);
ax2 = fig.Children(2);
% 隐藏基线
ax1.XColor = 'none';
ax1.Children(end).BaseLine.Color = 'none';
% 坐标轴修饰
ax1.LineWidth = 1.5;
ax2.LineWidth = 1.5;
ax1.TickDir = 'out';
ax2.TickDir = 'out';
% 增添Y轴标签
ax1.YLabel.String = 'ug of Ab/ g wet weight of tissue';
ax1.YLabel.Position = [0 1.4 -1];
ax1.YLabel.FontSize = 15;
6 添加显著性标注
就一个柱子一个柱子加吧,改改序号和字符就能得到比较符合想法的效果:
% 随便加点显著性标志
N = 2; % 第二个柱
S = '***';
% 要修改右侧柱请改成barHdl(2)及DataB(N,:)
X = barHdl(1).XEndPoints(N);
Y = max(DataA(N,:))+.1;
errorbar(X,Y,.2,'horizontal','LineStyle','none','LineWidth',1,'Color','k')
text(X,Y,S,'FontSize',15,'FontWeight','bold','FontName','Arial',...
'HorizontalAlignment','center','VerticalAlignment','baseline')
N = 3; % 第三个柱
S = '****';
% 要修改右侧柱请改成barHdl(2)及DataB(N,:)
X = barHdl(1).XEndPoints(N);
Y = max(DataA(N,:))+.1;
errorbar(X,Y,.2,'horizontal','LineStyle','none','LineWidth',1,'Color','k')
text(X,Y,S,'FontSize',15,'FontWeight','bold','FontName','Arial',...
'HorizontalAlignment','center','VerticalAlignment','baseline')
N = 6; % 第六个柱
S = '****';
% 要修改右侧柱请改成barHdl(2)及DataB(N,:)
X = barHdl(1).XEndPoints(N);
Y = max(DataA(N,:))+.1;
errorbar(X,Y,.2,'horizontal','LineStyle','none','LineWidth',1,'Color','k')
text(X,Y,S,'FontSize',15,'FontWeight','bold','FontName','Arial',...
'HorizontalAlignment','center','VerticalAlignment','baseline')
更多颜色展示
完整代码
教程完整代码
% code for pnas.2200057120fig03
% by slandarer
% bar chart with trunc-axis
figure('Units','normalized','Position',[.2,.3,.36,.45],'Color','w');
rng(24)
% 随机生成了两组数据
DataA = rand(7,1)*ones(1,5).*2+rand(7,5)./3.5;
DataB = rand(7,1)*ones(1,5)./2+rand(7,5)./3.5;
meanData = [mean(DataA,2), mean(DataB,2)];
% 文章图片中的颜色数据
CList = [188,188,240; 160,161,166; 237,187,128;
177,202,233; 245,185,192]./255;
CList = CList([1,2],:);
% CList = CList([4,5],:);
% 横坐标标签文本
NameList = {'Cortex';
'Hippocampus';
'Cerebellum';
'Brainstem';
'Cervical spinal cord';
'Thoracic spinal cord';
'Lumbar spinal cord'};
hold on
% 绘制柱状图 ---------------------------------------------------------------
barHdl = bar(meanData,'EdgeColor','none','FaceAlpha',.5,'BarWidth',.7);
% 修改配色
barHdl(1).FaceColor = CList(1,:);
barHdl(2).FaceColor = CList(2,:);
% 绘制散点图 ---------------------------------------------------------------
XA = barHdl(1).XEndPoints.'*ones(1,size(DataA,2));
scatter(XA(:),DataA(:),55,'filled','o','MarkerEdgeColor','k','LineWidth',.8,...
'CData',CList(1,:),'XJitter','rand','XJitterWidth',0.15)
XB = barHdl(2).XEndPoints.'*ones(1,size(DataB,2));
scatter(XB(:),DataB(:),55,'filled','o','MarkerEdgeColor','k','LineWidth',.8,...
'CData',CList(2,:),'XJitter','rand','XJitterWidth',0.15)
% 绘制误差棒 ---------------------------------------------------------------
errorbar(barHdl(1).XEndPoints,meanData(:,1),std(DataA,0,2),'vertical',...
'LineStyle','none','LineWidth',1,'Color','k')
errorbar(barHdl(2).XEndPoints,meanData(:,2),std(DataB,0,2),'vertical',...
'LineStyle','none','LineWidth',1,'Color','k')
% 坐标区域简单修饰
ax = gca;
ax.XTick = 1:length(barHdl(1).XEndPoints);
ax.XTickLabel = NameList(:);
ax.FontName = 'Arial';
ax.FontWeight = 'bold';
ax.FontSize = 11;
ax.XTickLabelRotation = 35;
% 截断坐标轴
truncAxis('y',[1,1.4]);
fig = gcf;
ax1 = fig.Children(1);
ax2 = fig.Children(2);
% 隐藏基线
ax1.XColor = 'none';
ax1.Children(end).BaseLine.Color = 'none';
% 坐标轴修饰
ax1.LineWidth = 1.5;
ax2.LineWidth = 1.5;
ax1.TickDir = 'out';
ax2.TickDir = 'out';
% 增添Y轴标签
ax1.YLabel.String = 'ug of Ab/ g wet weight of tissue';
ax1.YLabel.Position = [0 1.4 -1];
ax1.YLabel.FontSize = 15;
% -------------------------------------------------------------------------
% 随便加点显著性标志
N = 2; % 第二个柱
S = '***';
% 要修改右侧柱请改成barHdl(2)及DataB(N,:)
X = barHdl(1).XEndPoints(N);
Y = max(DataA(N,:))+.1;
errorbar(X,Y,.2,'horizontal','LineStyle','none','LineWidth',1,'Color','k')
text(X,Y,S,'FontSize',15,'FontWeight','bold','FontName','Arial',...
'HorizontalAlignment','center','VerticalAlignment','baseline')
N = 3; % 第三个柱
S = '****';
% 要修改右侧柱请改成barHdl(2)及DataB(N,:)
X = barHdl(1).XEndPoints(N);
Y = max(DataA(N,:))+.1;
errorbar(X,Y,.2,'horizontal','LineStyle','none','LineWidth',1,'Color','k')
text(X,Y,S,'FontSize',15,'FontWeight','bold','FontName','Arial',...
'HorizontalAlignment','center','VerticalAlignment','baseline')
N = 6; % 第六个柱
S = '****';
% 要修改右侧柱请改成barHdl(2)及DataB(N,:)
X = barHdl(1).XEndPoints(N);
Y = max(DataA(N,:))+.1;
errorbar(X,Y,.2,'horizontal','LineStyle','none','LineWidth',1,'Color','k')
text(X,Y,S,'FontSize',15,'FontWeight','bold','FontName','Arial',...
'HorizontalAlignment','center','VerticalAlignment','baseline')
截断坐标轴工具函数完整代码
function truncAxis(varargin)
% @author : slandarer
% 公众号 : slandarer随笔
% 知乎 : slandarer
% 获取参数
if isa(varargin{1},'matlab.graphics.axis.Axes')
ax=varargin{1};varargin(1)=[];
else
ax=gca;
end
hold(ax,'on');
% box(ax,'off')
ax.XAxisLocation='bottom';
ax.YAxisLocation='left';
axisPos=ax.Position;
axisXLim=ax.XLim;
axisYLim=ax.YLim;
axisXScale=diff(axisXLim);
axisYScale=diff(axisYLim);
truncRatio=1/20;
Xtrunc=[];Ytrunc=[];
for i=1:length(varargin)-1
switch true
case strcmpi('X',varargin{i}),Xtrunc=varargin{i+1};
case strcmpi('Y',varargin{i}),Ytrunc=varargin{i+1};
end
end
switch true
case isempty(Xtrunc)
% 复制坐标区域
ax2=copyAxes(ax);
% 修改轴基础属性
ax2.XTickLabels=[];
ax2.XColor='none';
% 修改坐标区域范围
ax.YLim=[axisYLim(1),Ytrunc(1)];
ax2.YLim=[Ytrunc(2),axisYLim(2)];
% 坐标区域重定位
ax.Position(4)=axisPos(4)*(1-truncRatio)/(axisYScale-diff(Ytrunc))*(Ytrunc(1)-axisYLim(1));
ax2.Position(2)=axisPos(2)+ax.Position(4)+axisPos(4)*truncRatio;
ax2.Position(4)=axisPos(4)*(1-truncRatio)/(axisYScale-diff(Ytrunc))*(axisYLim(2)-Ytrunc(2));
% 链接轴范围变动
linkaxes([ax,ax2],'x')
% 添加线和标识符
if strcmp(ax.Box,'on')
ax.Box='off';ax2.Box='off';
annotation('line',[1,1].*(ax.Position(1)+ax.Position(3)),[ax.Position(2),ax.Position(2)+ax.Position(4)],'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax.Position(1)+ax.Position(3)),[ax2.Position(2),ax2.Position(2)+ax2.Position(4)],'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax2.Position(2)+ax2.Position(4)),'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
else
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax.Position(2)+ax.Position(4)),'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax2.Position(2)),'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
end
createSlash([ax.Position(1)-.2,ax.Position(2)+ax.Position(4)-.2,.4,.4])
createSlash([ax.Position(1)-.2,ax2.Position(2)-.2,.4,.4])
createSlash([ax.Position(1)+ax.Position(3)-.2,ax.Position(2)+ax.Position(4)-.2,.4,.4])
createSlash([ax.Position(1)+ax.Position(3)-.2,ax2.Position(2)-.2,.4,.4])
case isempty(Ytrunc)
% 复制坐标区域
ax2=copyAxes(ax);
% 修改轴基础属性
ax2.YTickLabels=[];
ax2.YColor='none';
% 修改坐标区域范围
ax.XLim=[axisXLim(1),Xtrunc(1)];
ax2.XLim=[Xtrunc(2),axisXLim(2)];
% 坐标区域重定位
ax.Position(3)=axisPos(3)*(1-truncRatio)/(axisXScale-diff(Xtrunc))*(Xtrunc(1)-axisXLim(1));
ax2.Position(1)=axisPos(1)+ax.Position(3)+axisPos(3)*truncRatio;
ax2.Position(3)=axisPos(3)*(1-truncRatio)/(axisXScale-diff(Xtrunc))*(axisXLim(2)-Xtrunc(2));
% 链接轴范围变动
linkaxes([ax,ax2],'y')
% 添加线和标识符
if strcmp(ax.Box,'on')
ax.Box='off';ax2.Box='off';
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax.Position(2)+ax.Position(4)),'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax2.Position(1),ax2.Position(1)+ax2.Position(3)],[1,1].*(ax.Position(2)+ax.Position(4)),'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax2.Position(1)+ax2.Position(3)),[ax2.Position(2),ax2.Position(2)+ax2.Position(4)],'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
else
annotation('line',[1,1].*(ax.Position(1)+ax.Position(3)),[ax2.Position(2),ax2.Position(2)+ax2.Position(4)],'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax2.Position(1)),[ax2.Position(2),ax2.Position(2)+ax2.Position(4)],'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
end
createSlash([ax.Position(1)+ax.Position(3)-.2,ax.Position(2)-.2,.4,.4])
createSlash([ax2.Position(1)-.2,ax.Position(2)-.2,.4,.4])
createSlash([ax.Position(1)+ax.Position(3)-.2,ax.Position(2)+ax.Position(4)-.2,.4,.4])
createSlash([ax2.Position(1)-.2,ax.Position(2)+ax.Position(4)-.2,.4,.4])
case (~isempty(Ytrunc))&(~isempty(Ytrunc))
% 复制坐标区域
ax2=copyAxes(ax);
ax3=copyAxes(ax);
ax4=copyAxes(ax);
% 修改轴基础属性
ax2.XTickLabels=[];
ax2.XColor='none';
ax3.XTickLabels=[];
ax3.XColor='none';
ax3.YTickLabels=[];
ax3.YColor='none';
ax4.YTickLabels=[];
ax4.YColor='none';
% 修改坐标区域范围
ax.YLim=[axisYLim(1),Ytrunc(1)];
ax.XLim=[axisXLim(1),Xtrunc(1)];
ax2.XLim=[axisXLim(1),Xtrunc(1)];
ax2.YLim=[Ytrunc(2),axisYLim(2)];
ax3.XLim=[Xtrunc(2),axisXLim(2)];
ax3.YLim=[Ytrunc(2),axisYLim(2)];
ax4.XLim=[Xtrunc(2),axisXLim(2)];
ax4.YLim=[axisYLim(1),Ytrunc(1)];
% 坐标区域重定位
ax.Position(3)=axisPos(3)*(1-truncRatio)/(axisXScale-diff(Xtrunc))*(Xtrunc(1)-axisXLim(1));
ax.Position(4)=axisPos(4)*(1-truncRatio)/(axisYScale-diff(Ytrunc))*(Ytrunc(1)-axisYLim(1));
ax2.Position(2)=axisPos(2)+ax.Position(4)+axisPos(4)*truncRatio;
ax2.Position(3)=axisPos(3)*(1-truncRatio)/(axisXScale-diff(Xtrunc))*(Xtrunc(1)-axisXLim(1));
ax2.Position(4)=axisPos(4)*(1-truncRatio)/(axisYScale-diff(Ytrunc))*(axisYLim(2)-Ytrunc(2));
ax3.Position(1)=axisPos(1)+ax.Position(3)+axisPos(3)*truncRatio;
ax3.Position(2)=axisPos(2)+ax.Position(4)+axisPos(4)*truncRatio;
ax3.Position(3)=axisPos(3)*(1-truncRatio)/(axisXScale-diff(Xtrunc))*(axisXLim(2)-Xtrunc(2));
ax3.Position(4)=axisPos(4)*(1-truncRatio)/(axisYScale-diff(Ytrunc))*(axisYLim(2)-Ytrunc(2));
ax4.Position(1)=axisPos(1)+ax.Position(3)+axisPos(3)*truncRatio;
ax4.Position(3)=axisPos(3)*(1-truncRatio)/(axisXScale-diff(Xtrunc))*(axisXLim(2)-Xtrunc(2));
ax4.Position(4)=axisPos(4)*(1-truncRatio)/(axisYScale-diff(Ytrunc))*(Ytrunc(1)-axisYLim(1));
% 链接轴范围变动
linkaxes([ax3,ax2],'y')
linkaxes([ax4,ax3],'x')
linkaxes([ax,ax2],'x')
linkaxes([ax,ax4],'y')
% 添加线和标识符
if strcmp(ax.Box,'on')
ax.Box='off';ax2.Box='off';ax3.Box='off';ax4.Box='off';
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax2.Position(2)+ax2.Position(4)),'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax3.Position(1),ax3.Position(1)+ax3.Position(3)],[1,1].*(ax2.Position(2)+ax2.Position(4)),'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax4.Position(1)+ax4.Position(3)),[ax3.Position(2),ax3.Position(2)+ax3.Position(4)],'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax4.Position(1)+ax4.Position(3)),[ax4.Position(2),ax4.Position(2)+ax4.Position(4)],'LineStyle','-','LineWidth',ax.LineWidth,'Color',ax.XColor);
else
annotation('line',[1,1].*(ax.Position(1)+ax.Position(3)),[ax2.Position(2),ax2.Position(2)+ax2.Position(4)],'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax3.Position(1)),[ax2.Position(2),ax2.Position(2)+ax2.Position(4)],'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax.Position(1)+ax.Position(3)),[ax.Position(2),ax.Position(2)+ax.Position(4)],'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[1,1].*(ax3.Position(1)),[ax.Position(2),ax.Position(2)+ax.Position(4)],'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax.Position(2)+ax.Position(4)),'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax.Position(1),ax.Position(1)+ax.Position(3)],[1,1].*(ax2.Position(2)),'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax4.Position(1),ax4.Position(1)+ax4.Position(3)],[1,1].*(ax.Position(2)+ax.Position(4)),'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
annotation('line',[ax4.Position(1),ax4.Position(1)+ax4.Position(3)],[1,1].*(ax2.Position(2)),'LineStyle',':','LineWidth',ax.LineWidth,'Color',ax.XColor);
end
createSlash([ax.Position(1)-.2,ax.Position(2)+ax.Position(4)-.2,.4,.4])
createSlash([ax.Position(1)-.2,ax2.Position(2)-.2,.4,.4])
createSlash([ax4.Position(1)+ax4.Position(3)-.2,ax.Position(2)+ax.Position(4)-.2,.4,.4])
createSlash([ax4.Position(1)+ax4.Position(3)-.2,ax2.Position(2)-.2,.4,.4])
createSlash([ax.Position(1)+ax.Position(3)-.2,ax.Position(2)-.2,.4,.4])
createSlash([ax.Position(1)+ax.Position(3)-.2,ax2.Position(2)+ax2.Position(4)-.2,.4,.4])
createSlash([ax4.Position(1)-.2,ax.Position(2)-.2,.4,.4])
createSlash([ax4.Position(1)-.2,ax2.Position(2)+ax2.Position(4)-.2,.4,.4])
% 修改当前坐标区域,方便legend添加
set(gcf,'currentAxes',ax3)
end
% 复制原坐标区域全部可复制属性
function newAX=copyAxes(ax)
axStruct=get(ax);
fNames=fieldnames(axStruct);
newAX=axes('Parent',ax.Parent);
coeList={'CurrentPoint','XAxis','YAxis','ZAxis','BeingDeleted',...
'TightInset','NextSeriesIndex','Children','Type','Legend'};
for n=1:length(coeList)
coePos=strcmp(fNames,coeList{n});
fNames(coePos)=[];
end
for n=1:length(fNames)
newAX.(fNames{n})=ax.(fNames{n});
end
copyobj(ax.Children,newAX)
end
% 添加截断标识符函数
function createSlash(pos)
anno=annotation('textbox');
anno.String='/';
anno.LineStyle='none';
anno.FontSize=15;
anno.Position=pos;
anno.FitBoxToText='on';
anno.VerticalAlignment='middle';
anno.HorizontalAlignment='center';
end
end
完
以上已经是本文全部内容,若懒得复制代码,可以去以下gitee仓库获取全部代码:
https://gitee.com/slandarer/PLTreprint/