MATLAB | 绘图复刻(十八) | K-means 聚类分组热图

文摘   2024-10-21 09:00   英国  
请尊重原创劳动成果
转载请注明本文链接
及文章作者:slandarer

嘿,又双叒叕又双叒叕好久不见了,这期来个后台问的分组的热图,实际上就是绘制热图然后根据分组画一些线,但是matlab自带的热图heatmap不支持hold on操作,因此我们直接用pcolor来画,原图和复刻效果如下:

直接看步骤:

步骤解读

0 数据准备

这边我随机生成了一些数据,大家可以换成自己的,CName是分类后每个类的名字,大家可以增加一些识别每个类是什么种类的步骤,来将其换成自己的类名:

% 随便生成一些随机数据
rng(5)
Data = rand(50,10).*((1:10) + rand(1,10)) + randi([1,8],[50,1]);
Data = Data(:); Data = Data([end,1:end-1]); Data = reshape(Data, 50, []);

% 可以直接将上面部分删掉,然后
% Data = []% 自己的数据

K = 8% kmeans 分组数
CName = compose('Class-%d'1:K);

% 将相同组数据放在一起,并计算相关矩阵
[Class, Ind] = sort(kmeans(Data, K));
HMat = corr(Data(Ind,:).');

1 创建图窗并修饰

主要是设置坐标区域比例,增添X/Y轴刻度标签,增加标题,改改字体等:

%  坐标区域修饰
figure('Units','normalized''Position',[.1,.1,.6,.8])
ax = gca;
ax.NextPlot = 'add';
ax.Box = 'on';
ax.PlotBoxAspectRatio = [1,1,1];
ax.FontName = 'Times New Roman';
ax.FontSize = 14;
ax.YDir = 'reverse';
TickPos = find(diff([0;Class;K+1]) == 1);
ax.XTick = (TickPos(1:end-1) + TickPos(2:end) - 1)./2 - .5;
ax.YTick = ax.XTick;
ax.XTickLabel = CName;
ax.YTickLabel = CName;
ax.XTickLabelRotation = 30;
% 修改标题
ax.Title.String = 'XXXXXX K-means Centroid';
ax.Title.FontSize = 24;
ax.Title.VerticalAlignment = 'bottom';

2 绘制热图

由于pcolor每个格子的颜色是由上下左右四个格点的数值决定(比如左上角数值),因此直接用矩阵话最后一行最后一列的数值就不会被使用,导致画出来的热图少了一行一列,因此使用pcolor函数前需要先给矩阵增加一行一列NaN。

这部分代码最后一行的如果把注释符号去掉的话,能够隐藏边缘线。

% 绘制热图
N = size(Data, 1);
X = 0:N;
HMat(end+1, :) = nan;
HMat(:, end+1) = nan;
PHdl = pcolor(X, X, HMat);
PHdl.EdgeColor = [.3,.3,.3]; 
% PHdl.EdgeColor = 'none'; 

3 添加分组线

% 绘制分组线
for i = 2:K
    plot(ax, TickPos([i,i]) - 1, [0,N], 'Color','k''LineWidth',2)
    plot(ax, [0,N], TickPos([i,i]) - 1'Color','k''LineWidth',2)
end

4 绘制colorbar并调整颜色图

colorbar()
colormap(flipud(turbo))
clim([-1,1])


% colormap(slanCM(134))

大家可以尝试一下以下工具来获得更多种类的colormap:

  • https://www.mathworks.com/matlabcentral/fileexchange/120088-200-colormap

比如其中136号配色:

134号配色:

114号配色:


完整代码

% Grouped heatmap

% 随便生成一些随机数据
rng(5)
Data = rand(50,10).*((1:10) + rand(1,10)) + randi([1,8],[50,1]);
Data = Data(:); Data = Data([end,1:end-1]); Data = reshape(Data, 50, []);

% 可以直接将上面部分删掉,然后
% Data = []% 自己的数据

K = 8% kmeans 分组数
CName = compose('Class-%d'1:K);

% 将相同组数据放在一起,并计算相关矩阵
[Class, Ind] = sort(kmeans(Data, K));
HMat = corr(Data(Ind,:).');

%% 绘图部分
%  坐标区域修饰
figure('Units','normalized''Position',[.1,.1,.6,.8])
ax = gca;
ax.NextPlot = 'add';
ax.Box = 'on';
ax.PlotBoxAspectRatio = [1,1,1];
ax.FontName = 'Times New Roman';
ax.FontSize = 14;
ax.YDir = 'reverse';
TickPos = find(diff([0;Class;K+1]) == 1);
ax.XTick = (TickPos(1:end-1) + TickPos(2:end) - 1)./2 - .5;
ax.YTick = ax.XTick;
ax.XTickLabel = CName;
ax.YTickLabel = CName;
ax.XTickLabelRotation = 30;
% 修改标题
ax.Title.String = 'XXXXXX K-means Centroid';
ax.Title.FontSize = 24;
ax.Title.VerticalAlignment = 'bottom';

% 绘制热图
N = size(Data, 1);
X = 0:N;
HMat(end+1, :) = nan;
HMat(:, end+1) = nan;
PHdl = pcolor(X, X, HMat);
PHdl.EdgeColor = [.3,.3,.3]; 
% PHdl.EdgeColor = 'none'; 

% 绘制分组线
for i = 2:K
    plot(ax, TickPos([i,i]) - 1, [0,N], 'Color','k''LineWidth',2)
    plot(ax, [0,N], TickPos([i,i]) - 1'Color','k''LineWidth',2)
end

% 绘制colorbar并调整颜色图
colorbar()
colormap(flipud(turbo))
clim([-1,1])


% colormap(slanCM(134))

以上已经是完整代码,如果懒得复制可以去以下gitee仓库获取:

  • https://gitee.com/slandarer/PLTreprint/


slandarer随笔
slandarer个人公众号,目前主要更新MATLAB相关内容。
 最新文章