本期教大家如何绘制带树状图的环状热图,要复刻的图片长这样:
复刻效果:
需要安装Statistics and Machine Learning Toolbox即统计与机器学习工具箱!!!
需要安装Statistics and Machine Learning Toolbox即统计与机器学习工具箱!!!
完整步骤
0 随机数据生成及变量定义
这里随便生成了一点数据:
% 随机生成数据
rng(5)
X=randn(100,80)+[(linspace(-1,2.5,100)').*ones(1,15),(linspace(.5,-.7,100)').*ones(1,15),...
(linspace(.1,-.7,100)').*ones(1,15),(linspace(.9,-.2,100)').*ones(1,15),...
(linspace(-.1,.7,100)').*ones(1,10),(linspace(-.9,-.2,100)').*ones(1,10)];
Y=randn(100,8)+[(linspace(-1,2.5,100)').*ones(1,2),(linspace(.5,-.7,100)').*ones(1,3),(linspace(-1,-2.5,100)').*ones(1,3)];
Data=corr(X,Y);
% 定义配色和颜色范围
CMap=parula();
%CMap=slanCM(136);
CLim=[-1,1];
% 随便定义变量名
XName{80}=[];
for i=1:80
XName{i}=['slan',num2str(i)];
end
YName{8}=[];
for i=1:8
YName{i}=['var',num2str(i)];
end
并定义了颜色和变量名,可以自行替换数据、配色和变量名。
1 图窗、坐标区域、基础数据定义
% 角度范围
theta1=pi/4;
theta2=-3*pi/2;
% 半径范围
R1=1;
R2=2;
% 角度及半径预处理 ==========================================================
theta3=(theta2-theta1)./size(Data,1);
theta4=theta1+theta3/2;
theta5=theta2-theta3/2;
theta6=2.7*pi/8;
R3=(R2-R1)./size(Data,2);
R4=R1+R3/2;
R5=R2-R3/2;
% 开始绘图 =================================================================
fig=figure('Units','normalized','Position',[0,0,1,1]);
fig.Color=[1,1,1];
ax=axes(fig);hold on
% ax.Position=[0,0,1,1];
ax.XLim=[-2,2];
ax.YLim=[-2,2];
ax.DataAspectRatio=[1,1,1];
ax.XColor='none';
ax.YColor='none';
这样会生成一个全屏空白窗口。
2 中心环形树状图生成
需要安装Statistics and Machine Learning Toolbox即统计与机器学习工具箱!!!
使用dendrogram
函数绘图后进行一个极坐标变换即可,同时为了图象连接处能对起来,需要进行弧形的插值:
% 中心极坐标树状图
fig1=figure();
tree1=linkage(Data,'average');
[treeHdl1,~,order1]=dendrogram(tree1,0,'Orientation','top');
LineSet1=fig1.Children.Children;
maxY1=0;
for i=1:length(LineSet1)
maxY1=max(max(LineSet1(i).YData),maxY1);
end
tS=linspace(0,1,50);
for i=1:length(LineSet1)
tX=LineSet1(i).XData;
tY=LineSet1(i).YData;
tR=(maxY1-tY)./maxY1;
tT=theta4+(theta5-theta4).*(tX-1)./(size(Data,1)-1);
tR=[tR(1),tR(2).*ones(1,50),tR(4)];
tT=[tT(1),tT(2)+tS.*(tT(3)-tT(2)),tT(4)];
plot(ax,tR.*cos(tT),tR.*sin(tT),'Color','k','LineWidth',.7)
end
close(fig1)
3 侧面树状图生成
还是几乎完全相同的操作,不过弧形插值变成了两次:
% 绘制侧面树状图
fig2=figure();
tree2=linkage(Data.','average');
[treeHdl2,~,order2]=dendrogram(tree2,0,'Orientation','top');
LineSet2=fig2.Children.Children;
maxY2=0;
for i=1:length(LineSet2)
maxY2=max(max(LineSet2(i).YData),maxY2);
end
tS=linspace(0,1,20);
for i=1:length(LineSet2)
tX=LineSet2(i).XData;
tY=LineSet2(i).YData;
tR=R4+(R5-R4).*(tX-1)./(size(Data,2)-1);
tT=theta6+(theta1-theta6).*(maxY2-tY)./maxY2;
tR=[tR(1).*ones(1,20),tR(4).*ones(1,20)];
tT=[tT(1)+(tT(2)-tT(1)).*tS,tT(3)+(tT(4)-tT(3)).*tS];
plot(ax,tR.*cos(tT),tR.*sin(tT),'Color','k','LineWidth',.7)
end
close(fig2)
4 绘制环形热力图
由于MATLAB本身并不自带极坐标填充函数,因此这里直接fill函数一个一个格子硬画:;
% 绘制环形热力图
x=linspace(CLim(1),CLim(2),size(CMap,1))';
y1=CMap(:,1);y2=CMap(:,2);y3=CMap(:,3);
colorFunc=@(X)[interp1(x,y1,X,'pchip'),interp1(x,y2,X,'pchip'),interp1(x,y3,X,'pchip')];
tS=linspace(0,1,50);
Data=Data(order1,:);
Data=Data(:,order2);
for i=1:size(Data,2)
for j=1:size(Data,1)
tX=[i-1,i]./size(Data,2);
tY=[j-1,j]./size(Data,1);
tX=tX+1;
tY=theta1+(theta2-theta1).*tY;
tR=[tX(1).*ones(1,50),tX(2).*ones(1,50)];
tT=[tY(1)+(tY(2)-tY(1)).*tS,tY(2)+(tY(1)-tY(2)).*tS];
fill(ax,tR.*cos(tT),tR.*sin(tT),colorFunc(Data(j,i)),'EdgeColor',[1,1,1],'LineWidth',.7)
end
end
5 绘制文本
要是中文字体乱码,请换成支持中文的字体,例如换成'FontName','宋体'
:
% 添加文本1
for i=1:length(order1)
tT=theta4+(theta5-theta4).*(i-1)./(size(Data,1)-1);
if tT>-pi/2
text(ax,(1/30+2).*cos(tT),(1/30+2).*sin(tT),XName{order1(i)},...
'FontSize',13,'FontName','Cambria','Rotation',tT./pi.*180);
else
text(ax,(1/30+2).*cos(tT),(1/30+2).*sin(tT),XName{order1(i)},...
'FontSize',13,'FontName','Cambria','Rotation',tT./pi.*180+180,'HorizontalAlignment','right');
end
end
% 添加文本2
for i=1:length(order2)
text(ax,1/30,R4+(R5-R4).*(i-1)./(size(Data,2)-1),YName{order2(i)},...
'FontSize',13,'FontName','Cambria');
end
6 添加colorbar
% 添加colorbar
colormap(CMap)
clim(CLim)
cb=colorbar();
cb.Position(2)=2/5;
cb.Position(4)=1/5;
cb.Position(1)=8/10;
cb.Position(3)=1/80;
cb.FontName='Cambria';
cb.FontSize=12;
7 更换配色
大家可能觉得颜色不好看,大家可以尝试下载文末所提到的压缩包,或者下载以下文章中提到的配色包,使用其中的配色让图象变得更好看一点:
https://slandarer.blog.csdn.net/article/details/127719784
比如将第0部分,随机数据生成及变量定义中定义配色的代码改为:
% 定义配色和颜色范围
CMap=slanCM(136);
CLim=[-1,1];
136号配色
141号配色
131号配色
111号配色
108号配色
105号配色
56号配色
175号配色
-1 完整代码
% @author : slandarer
% gzh : slandarer随笔
% 随机生成数据
rng(5)
X=randn(100,80)+[(linspace(-1,2.5,100)').*ones(1,15),(linspace(.5,-.7,100)').*ones(1,15),...
(linspace(.1,-.7,100)').*ones(1,15),(linspace(.9,-.2,100)').*ones(1,15),...
(linspace(-.1,.7,100)').*ones(1,10),(linspace(-.9,-.2,100)').*ones(1,10)];
Y=randn(100,8)+[(linspace(-1,2.5,100)').*ones(1,2),(linspace(.5,-.7,100)').*ones(1,3),(linspace(-1,-2.5,100)').*ones(1,3)];
Data=corr(X,Y);
% 定义配色和颜色范围
CMap=parula();
CMap=slanCM(136);
CLim=[-1,1];
% 随便定义变量名
XName{80}=[];
for i=1:80
XName{i}=['slan',num2str(i)];
end
YName{8}=[];
for i=1:8
YName{i}=['var',num2str(i)];
end
% 角度范围
theta1=pi/4;
theta2=-3*pi/2;
% 半径范围
R1=1;
R2=2;
% 角度及半径预处理 ==========================================================
theta3=(theta2-theta1)./size(Data,1);
theta4=theta1+theta3/2;
theta5=theta2-theta3/2;
theta6=2.7*pi/8;
R3=(R2-R1)./size(Data,2);
R4=R1+R3/2;
R5=R2-R3/2;
% 开始绘图 =================================================================
fig=figure('Units','normalized','Position',[0,0,1,1]);
fig.Color=[1,1,1];
ax=axes(fig);hold on
% ax.Position=[0,0,1,1];
ax.XLim=[-2,2];
ax.YLim=[-2,2];
ax.DataAspectRatio=[1,1,1];
ax.XColor='none';
ax.YColor='none';
% 中心极坐标树状图
fig1=figure();
tree1=linkage(Data,'average');
[treeHdl1,~,order1]=dendrogram(tree1,0,'Orientation','top');
LineSet1=fig1.Children.Children;
maxY1=0;
for i=1:length(LineSet1)
maxY1=max(max(LineSet1(i).YData),maxY1);
end
tS=linspace(0,1,50);
for i=1:length(LineSet1)
tX=LineSet1(i).XData;
tY=LineSet1(i).YData;
tR=(maxY1-tY)./maxY1;
tT=theta4+(theta5-theta4).*(tX-1)./(size(Data,1)-1);
tR=[tR(1),tR(2).*ones(1,50),tR(4)];
tT=[tT(1),tT(2)+tS.*(tT(3)-tT(2)),tT(4)];
plot(ax,tR.*cos(tT),tR.*sin(tT),'Color','k','LineWidth',.7)
end
close(fig1)
% 绘制侧面树状图
fig2=figure();
tree2=linkage(Data.','average');
[treeHdl2,~,order2]=dendrogram(tree2,0,'Orientation','top');
LineSet2=fig2.Children.Children;
maxY2=0;
for i=1:length(LineSet2)
maxY2=max(max(LineSet2(i).YData),maxY2);
end
tS=linspace(0,1,20);
for i=1:length(LineSet2)
tX=LineSet2(i).XData;
tY=LineSet2(i).YData;
tR=R4+(R5-R4).*(tX-1)./(size(Data,2)-1);
tT=theta6+(theta1-theta6).*(maxY2-tY)./maxY2;
tR=[tR(1).*ones(1,20),tR(4).*ones(1,20)];
tT=[tT(1)+(tT(2)-tT(1)).*tS,tT(3)+(tT(4)-tT(3)).*tS];
plot(ax,tR.*cos(tT),tR.*sin(tT),'Color','k','LineWidth',.7)
end
close(fig2)
% 绘制环形热力图
x=linspace(CLim(1),CLim(2),size(CMap,1))';
y1=CMap(:,1);y2=CMap(:,2);y3=CMap(:,3);
colorFunc=@(X)[interp1(x,y1,X,'pchip'),interp1(x,y2,X,'pchip'),interp1(x,y3,X,'pchip')];
tS=linspace(0,1,50);
Data=Data(order1,:);
Data=Data(:,order2);
for i=1:size(Data,2)
for j=1:size(Data,1)
tX=[i-1,i]./size(Data,2);
tY=[j-1,j]./size(Data,1);
tX=tX+1;
tY=theta1+(theta2-theta1).*tY;
tR=[tX(1).*ones(1,50),tX(2).*ones(1,50)];
tT=[tY(1)+(tY(2)-tY(1)).*tS,tY(2)+(tY(1)-tY(2)).*tS];
fill(ax,tR.*cos(tT),tR.*sin(tT),colorFunc(Data(j,i)),'EdgeColor',[1,1,1],'LineWidth',.7)
end
end
% 添加文本1
for i=1:length(order1)
tT=theta4+(theta5-theta4).*(i-1)./(size(Data,1)-1);
if tT>-pi/2
text(ax,(1/30+2).*cos(tT),(1/30+2).*sin(tT),XName{order1(i)},...
'FontSize',13,'FontName','Cambria','Rotation',tT./pi.*180);
else
text(ax,(1/30+2).*cos(tT),(1/30+2).*sin(tT),XName{order1(i)},...
'FontSize',13,'FontName','Cambria','Rotation',tT./pi.*180+180,'HorizontalAlignment','right');
end
end
% 添加文本2
for i=1:length(order2)
text(ax,1/30,R4+(R5-R4).*(i-1)./(size(Data,2)-1),YName{order2(i)},...
'FontSize',13,'FontName','Cambria');
end
% 添加colorbar
colormap(CMap)
clim(CLim)
cb=colorbar();
cb.Position(2)=2/5;
cb.Position(4)=1/5;
cb.Position(1)=8/10;
cb.Position(3)=1/80;
cb.FontName='Cambria';
cb.FontSize=12;
完
完整代码:
链接:
https://pan.baidu.com/s/1VVNozsMGzVKF45-ArZE_Dg?pwd=slan
提取码:slan