转载请注明本文链接
及文章作者:slandarer
Hey,最近刷到公众号CNSplot
复刻Nature弦图,于是想拿自己开发的工具试一下,同时为工具查漏补缺,增填了一些新功能,本篇文章先讲解如何复刻,再讲解一些新属性该怎么使用。
本人工具复刻图:
与Nature原图对比:
本文绘图需要调用我自己写的弦图绘制工具函数,该函数可在fileexchange或者gitee仓库下载,里面有弦图函数基本使用例子:
gitee链接
弦图+有向弦图 https://gitee.com/slandarer/matlab-chord-chart
fileexchange链接
chord chart 弦图 https://www.mathworks.com/matlabcentral/fileexchange/116550-chord-chart Digraph chord chart 有向弦图https://www.mathworks.com/matlabcentral/fileexchange/121043-digraph-chord-chart
同时我发现,我在MATLAB官网fileexchange平台发布的文件2024年下载总量排到了官网前10,喜提小徽章:
https://www.mathworks.com/matlabcentral/profile/badges/157
Nature弦图复刻
数据准备及导入
Nature文章网站:
https://www.nature.com/articles/s41586-023-05769-3#MOESM9
下载数据:
导入数据并调整格式:
% Data source :
% Lake, B.B., Menon, R., Winfree, S. et al.
% An atlas of healthy and injured cell states and niches in the human kidney.
% Nature 619, 585–594 (2023). https://doi.org/10.1038/s41586-023-05769-3
% https://www.nature.com/articles/s41586-023-05769-3
% 41586_2023_5769_MOESM9_ESM.xlsx | sheet : panel_d_chordplot
Data = readtable("41586_2023_5769_MOESM9_ESM.xlsx");
dataMat = rot90(Data.Variables, 2);
dataMat = triu(dataMat, 1);
nameList = fliplr(Data.Properties.VariableNames);
nameList = cellfun(@(s)strrep(s, '_', '-'), nameList, 'UniformOutput',false);
CList = [203,122,165; 208,112,85; 214,95,1; 106,103,90; 0,114,178; 121,171,123;
240,228,65; 123,199,94; 0,160,117; 46,164,165; 85,182,231; 159,171,110; 230,157,5]./255;
基础绘制
有下面三个新参数:
Rotation
整个弦图旋转角度OSqRatio
弧形块外圈宽度,范围[0,1]SSqRatio
弧形块内圈宽度,范围[-0.5,1]
figure('Units','normalized', 'Position',[.02,.05,.6,.85])
BCC=biChordChart(dataMat, 'Label',nameList, 'Rotation',pi/1.62,...
'CData',CList, 'SSqRatio', -30/100, 'OSqRatio', 80/100, 'LRadius',1.21);
BCC=BCC.draw();
调整文字旋转角度
把所有标签旋转至水平:
% 旋转标签(Rotate labels)
textHdl = findobj(gca, 'Tag','BiChordLabel');
for i = 1:length(textHdl)
set(textHdl(i), 'Rotation',0, 'FontSize',17)
if textHdl(i).Position(1) < -.1
set(textHdl(i), 'HorizontalAlignment','right')
elseif textHdl(i).Position(1) > .1
set(textHdl(i), 'HorizontalAlignment','left')
end
end
修改弦透明度
% 调整弦透明度(Adjust the chords opacity)
for i = 1:size(dataMat, 1)
for j = 1:size(dataMat, 2)
BCC.setChordMN(i,j, 'FaceAlpha', .5)
end
end
添加X轴标签
ax=gca;
ax.XLabel.String = {'Pairwise connections in neighbourhoods'; '(1,240,569 neighbourhoods)'};
ax.XLabel.Color = 'k';
ax.XLabel.FontSize = 15;
完整代码
% Data source :
% Lake, B.B., Menon, R., Winfree, S. et al.
% An atlas of healthy and injured cell states and niches in the human kidney.
% Nature 619, 585–594 (2023). https://doi.org/10.1038/s41586-023-05769-3
% https://www.nature.com/articles/s41586-023-05769-3
% 41586_2023_5769_MOESM9_ESM.xlsx | sheet : panel_d_chordplot
Data = readtable("41586_2023_5769_MOESM9_ESM.xlsx");
dataMat = rot90(Data.Variables, 2);
dataMat = triu(dataMat, 1);
nameList = fliplr(Data.Properties.VariableNames);
nameList = cellfun(@(s)strrep(s, '_', '-'), nameList, 'UniformOutput',false);
CList = [203,122,165; 208,112,85; 214,95,1; 106,103,90; 0,114,178; 121,171,123;
240,228,65; 123,199,94; 0,160,117; 46,164,165; 85,182,231; 159,171,110; 230,157,5]./255;
figure('Units','normalized', 'Position',[.02,.05,.6,.85])
BCC=biChordChart(dataMat, 'Label',nameList, 'Rotation',pi/1.62,...
'CData',CList, 'SSqRatio', -30/100, 'OSqRatio', 80/100, 'LRadius',1.21);
BCC=BCC.draw();
% 旋转标签(Rotate labels)
textHdl = findobj(gca, 'Tag','BiChordLabel');
for i = 1:length(textHdl)
set(textHdl(i), 'Rotation',0, 'FontSize',17)
if textHdl(i).Position(1) < -.1
set(textHdl(i), 'HorizontalAlignment','right')
elseif textHdl(i).Position(1) > .1
set(textHdl(i), 'HorizontalAlignment','left')
end
end
% 调整弦透明度(Adjust the chords opacity)
for i = 1:size(dataMat, 1)
for j = 1:size(dataMat, 2)
BCC.setChordMN(i,j, 'FaceAlpha', .5)
end
end
ax=gca;
ax.XLabel.String = {'Pairwise connections in neighbourhoods'; '(1,240,569 neighbourhoods)'};
ax.XLabel.Color = 'k';
ax.XLabel.FontSize = 15;
内外圈宽度
无向弦图
这个在无向弦图工具更新的比较早,但是因为颜色区分度一般没那么大,所以颜色需要手动设置,可通过
OSqRatio
设置弧形块外圈宽度,范围[0,1]SSqRatio
设置弧形块内圈宽度,范围[-0.5,1]obj.setEachSquareF_Prop(i,j,...)
设置从节点i流向节点j的弦对应的下方内圈弧形块颜色等属性obj.setEachSquareT_Prop(i,j,...)
设置从节点i流向节点j的弦对应的上方内圈弧形块颜色等属性
dataMat = rand([11,4]);
dataMat = round(10.*dataMat.*((11:-1:1).'+1))./10;
colName = {'A','B','C','D'};
rowName = {'Acidobacteriota', 'Actinobacteriota', 'Proteobacteria', ...
'Chloroflexi', 'Bacteroidota', 'Firmicutes', 'Gemmatimonadota', ...
'Verrucomicrobiota', 'Patescibacteria', 'Planctomyetota', 'Others'};
figure('Units','normalized', 'Position',[.02,.05,.8,.85])
% CC = chordChart(dataMat, 'colName',colName, 'Sep',1/80, 'SSqRatio',30/100);
% SSqRatio Range : [-50/100, 100/100]; OSqRatio Range : [0, 100/100]
CC = chordChart(dataMat, 'colName',colName, 'Sep',1/80, 'SSqRatio',-30/100, 'OSqRatio',80/100);
CC = CC.draw();
% 修改上方方块颜色(Modify the color of the blocks above)
CListT = [0.93,0.60,0.62; 0.55,0.80,0.99; 0.95,0.82,0.18; 1.00,0.81,0.91];
for i = 1:size(dataMat, 2)
CC.setSquareT_N(i, 'FaceColor',CListT(i,:))
end
% 修改下方方块颜色(Modify the color of the blocks below)
CListF = [0.75,0.73,0.86; 0.56,0.83,0.78; 0.00,0.60,0.20; 1.00,0.49,0.02
0.78,0.77,0.95; 0.59,0.24,0.36; 0.98,0.51,0.45; 0.96,0.55,0.75
0.47,0.71,0.84; 0.65,0.35,0.16; 0.40,0.00,0.64];
for i = 1:size(dataMat, 1)
CC.setSquareF_N(i, 'FaceColor',CListF(i,:))
end
% 修改弦颜色(Modify chord color)
for i = 1:size(dataMat, 1)
for j = 1:size(dataMat, 2)
% CC.setChordMN(i,j, 'FaceColor',CListF(i,:), 'FaceAlpha',.4)
CC.setChordMN(i,j, 'FaceColor',CListT(j,:), 'FaceAlpha',.4)
end
end
% 单独设置每一个弦末端方块(Set individual end blocks for each chord)
% Use obj.setEachSquareF_Prop
% or obj.setEachSquareT_Prop
% F means from (blocks below)
% T means to (blocks above)
for i = 1:size(dataMat, 1)
for j = 1:size(dataMat, 2)
CC.setEachSquareT_Prop(i,j, 'FaceColor', CListF(i,:))
CC.setEachSquareF_Prop(i,j, 'FaceColor', CListT(j,:))
end
end
% 添加刻度
CC.tickState('on')
% 修改字体,字号及颜色
CC.setFont('FontName','Cambria', 'FontSize',17)
有向弦图
这个会自动设置颜色,会方便一些:
dataMat=randi([0,5],[8,8]);
CList=[75,146,241;252,180,65;224,64,10;5,100,146;191,191,191;
26,59,105;255,227,130;18,156,221;202,107,75;0,92,219;
243,210,136;80,99,129;241,185,168;224,131,10;120,147,190]./255;
figure('Units','normalized','Position',[.02,.05,.6,.85])
BCC=biChordChart(dataMat,'Arrow','on','CData',CList,...
'TickMode','auto','SSqRatio',-30/100, 'OSqRatio',80/100);
BCC=BCC.draw();
% 添加刻度
BCC.tickState('on')
BCC.tickLabelState('on')
整体旋转
无向弦图
一个Rotation
属性的基础使用例子:
dataMat=[2 0 1 2 5 1 2;
3 5 1 4 2 0 1;
4 0 5 5 2 4 3];
colName={'G1','G2','G3','G4','G5','G6','G7'};
rowName={'S1','S2','S3'};
CC=chordChart(dataMat,'rowName',rowName,'colName',colName,'Rotation',pi/3);
CC=CC.draw();
CC.setFont('FontSize',17,'FontName','Cambria')
CC.tickState('on')
一个更复杂的例子:
clc;clear
rng(2)
dataMat = rand([14,5]) > .3;
colName = {'phosphorylation', 'vasculature development', 'blood vessel development', ...
'cell adhesion', 'plasma membrane'};
rowName = {'THY1', 'FGF2', 'MAP2K1', 'CDH2', 'HBEGF', 'CXCR4', 'ECSCR',...
'ACVRL1', 'RECK', 'PNPLA6', 'CDH5', 'AMOT', 'EFNB2', 'CAV1'};
figure('Units','normalized', 'Position',[.02,.05,.9,.85])
CC = chordChart(dataMat, 'colName',colName, 'rowName',rowName, 'Sep',1/80, 'LRadius',1.2, 'Rotation',3*pi/2);
CC = CC.draw();
% 修改上方方块颜色(Modify the color of the blocks above)
CListT = [0.47 0.58 0.75; 0.48 0.54 0.58; 0.65 0.72 0.65; 0.94 0.92 0.90; 0.98 0.76 0.68];
for i = 1:size(dataMat, 2)
CC.setSquareT_N(i, 'FaceColor',CListT(i,:), 'EdgeColor',[0,0,0])
end
% 修改弦颜色(Modify chord color)
for i = 1:size(dataMat, 1)
for j = 1:size(dataMat, 2)
CC.setChordMN(i,j, 'FaceColor',CListT(j,:), 'FaceAlpha',.9, 'EdgeColor',[0,0,0])
end
end
% 修改下方方块颜色(Modify the color of the blocks below)
logFC = sort(rand(1,14))*6 - 3;
for i = 1:size(dataMat, 1)
CC.setSquareF_N(i, 'CData',logFC(i), 'FaceColor','flat', 'EdgeColor',[0,0,0])
end
% 一个红白蓝配色 colorbar
CMap = interp1([0,.5,1].', [0,0,1;1,1,1;1,0,0], linspace(0,1,50).');
colormap(CMap);
try clim([-3,3]),catch,end
try caxis([-3,3]),catch,end
CBHdl = colorbar();
CBHdl.Position = [0.74,0.25,0.02,0.2];
% Draw legend
text(1.25,-.15, 'LogFC', 'FontSize',16)
text(1.25,1, 'Terms', 'FontSize',16)
patchHdl = [];
for i = 1:size(dataMat, 2)
patchHdl(i) = fill([10,11,12],[10,13,13], CListT(i,:), 'EdgeColor',[0,0,0]);
end
lgdHdl = legend(patchHdl, colName, 'Location','best', 'FontSize',14, 'Box','off');
lgdHdl.Position = [.735,.53,.167,.27];
lgdHdl.ItemTokenSize = [18,8];
有向弦图
也是一样的用法:
dataMat=randi([0,8],[6,6]);
BCC=biChordChart(dataMat,'Arrow','on', 'Rotation',pi/3);
BCC=BCC.draw();
% 添加刻度
BCC.tickState('on')
% 修改字体,字号及颜色
BCC.setFont('FontName','Cambria','FontSize',17)
有区别的是,对于有向弦图,我写了个在测试的功能,就是能够设置每个弧形块的位置,这个功能要求Rotation
是每个弧形块的角度构成的向量而不是角度数值:
这是应对弧形块有东南西北等实际方位信息,不过感觉用到的机会比较少,此外为了让弧形块不重叠,要把Sep
属性设置的大一些:
links = {'N','NE',252.4; 'NW','N',44.7; 'NW','W',11.4; 'NW','SW',7.9
'W','NW',43.1; 'SW','NW',35; 'SW','W',37.4; 'SW','S',10.6
'S','N',20.3; 'S','SW',88.5; 'SE','SW',89.7; 'SE','S',40.3
'E','SE',69.6; 'NE','N',27.4; 'NE','NW',6.9; 'NE','SE',14.1; 'NE','E',93.4};
% Change links into adjacency matrix and name list
[adjMat, nodeList]=links2AdjMat(links);
Theta=linspace(pi/2,2*pi+pi/2,9);
figure('Units','normalized','Position',[.02,.05,.6,.85])
BCC=biChordChart(adjMat,'Label',nodeList,'Arrow','on','TickMode','auto','Sep',1/2.2,'Rotation',Theta);
BCC=BCC.draw();
% 调节标签半径
% Adjustable Label radius
BCC.setLabelRadius(1.4);
% 显示刻度和数值
% Displays scales and numeric values
BCC.tickState('on')
BCC.tickLabelState('on')
BCC.labelRotate('on')
txtHdl=findobj(gca,'Tag','BiChordLabel');
for i=1:length(txtHdl)
if abs(txtHdl(i).Position(2))>1
set(txtHdl(i),'Rotation',0,'HorizontalAlignment','center');
end
end
% 修改字体,字号及颜色
BCC.setFont('FontName','Cambria','FontSize',25,'Color',[0,0,.8])
% An assistant function to change links into adjacency matrix and name list
function [adjMat, nodeList] = links2AdjMat(links)
nodeList=unique([links(:,1), links(:,2)], 'stable');
BN = length(nodeList);
adjMat=zeros(BN, BN);
for i=1:size(links,1)
sourceInd=strcmp(links{i,1},nodeList);
targetInd=strcmp(links{i,2},nodeList);
adjMat(sourceInd,targetInd)=links{i,3};
end
end
结语
gitee链接
弦图+有向弦图 https://gitee.com/slandarer/matlab-chord-chart
fileexchange链接
Zhaoxu Liu / slandarer (2025). chord chart 弦图 (https://www.mathworks.com/matlabcentral/fileexchange/116550-chord-chart), MATLAB Central File Exchange. Retrieved January 9, 2025. Zhaoxu Liu / slandarer (2025). Digraph chord chart 有向弦图 (https://www.mathworks.com/matlabcentral/fileexchange/121043-digraph-chord-chart), MATLAB Central File Exchange. Retrieved January 9, 2025.
本文代码免费分享,禁止用做任何盈利用途,若在论文中使用本代码,可引用上述fileexchange链接,代码编写不易,留个点赞或者再看叭~~~~