利用Matlab繪制好看的弦圖
弦圖在python中以及R中非常常見(jiàn),但是MATLAB中卻始終沒(méi)有相關(guān)函數(shù),file exchange中也沒(méi)有工作做的較為完備的弦圖繪制函數(shù)(不過(guò)現(xiàn)在有了,我已經(jīng)往上面也傳了一份hiahiahia)
僅工具函數(shù)主體部分約300行,字符數(shù)約8000,能畫(huà)出與R語(yǔ)言同等質(zhì)量的弦圖實(shí)屬不易,希望能有個(gè)`點(diǎn)贊``!??!
由于工具函數(shù)過(guò)長(zhǎng),將被放在最后展示,以下將先展示函數(shù)用法
封面圖


使用教程
1.數(shù)據(jù)格式
數(shù)據(jù)要求為全部數(shù)值大于等于0的數(shù)值矩陣,或者table數(shù)組,或者數(shù)值矩陣+行列名元胞數(shù)組,首先舉個(gè)數(shù)值矩陣的例子:
數(shù)值矩陣
dataMat=randi([0,5],[5,4]); % 繪圖 CC=chordChart(dataMat); CC=CC.draw();

這樣由于沒(méi)對(duì)各個(gè)對(duì)象命名,因此會(huì)自動(dòng)命名為Rn和Cn
數(shù)值矩陣+行列名元胞數(shù)組
這是最推薦的一種格式:
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);
CC=CC.draw();

rowName要和矩陣的行相同大小
colName要和矩陣的列相同大小
對(duì)于本列子來(lái)說(shuō)第2行第3列數(shù)值是1,就說(shuō)明有一份能量從S2流向G3,也就在這倆之間需要畫(huà)單位寬度的弦。
table 數(shù)組
需要使用如下格式的table數(shù)組:

當(dāng)然,如果各個(gè)行沒(méi)有命名的話依舊會(huì)自動(dòng)命名的。
2.修飾弦
弦的批量修飾
弦的批量修飾可以使用setChordProp函數(shù),一切Patch對(duì)象所具有的屬性均可以被修飾,舉個(gè)例子(修飾一下弦的顏色,邊緣顏色,邊緣線形狀等):
CC.setChordProp('EdgeColor',[.3,.3,.3],'LineStyle','--',...
'LineWidth',.1,'FaceColor',[.3,.3,.3])

弦的單獨(dú)修飾
弦的單獨(dú)修飾可以使用setChordMN函數(shù),其中m,n值是和原始數(shù)值矩陣的行列完全對(duì)應(yīng)的,舉個(gè)例子(把S2流向G4的弦顏色更改為紅色):
CC.setChordMN(2,4,'FaceColor',[1,0,0])

弦的顏色映射
使用setChordColorByMap函數(shù)進(jìn)行顏色映射,
matlab 自帶的colormap均可用:

或者也可自行放入一個(gè)n×3大小的顏色列表,程序會(huì)自動(dòng)對(duì)其進(jìn)行插值:舉個(gè)例子:
CC.setChordColorByMap(copper(100))

3.圓弧狀方塊修飾
圓弧狀方塊批量修飾
使用
setSquareT_Prop
setSquareF_Prop
分別修飾上方方塊和下方方塊,一切Patch對(duì)象所具有的屬性均可以被修飾,舉個(gè)例子,上方方塊批量修飾(改為黑色):
CC.setSquareT_Prop('FaceColor',[0,0,0])

圓弧狀方塊單獨(dú)修飾
使用
setSquareT_N
setSquareF_N
分別修飾上方方塊和下方方塊,舉個(gè)例子,上方第二個(gè)方塊單獨(dú)修飾(改為紅色):
CC.setSquareT_N(2,'FaceColor',[.8,0,0])

4.字體調(diào)整
使用setFont函數(shù)對(duì)字體進(jìn)行調(diào)整,所有text對(duì)象具有的屬性均可以修飾,舉個(gè)例子(更改文本的字號(hào)、字體和顏色):
CC.setFont('FontSize',25,'FontName','Cambria','Color',[0,0,.8])

5.顯示和隱藏刻度
用法:
CC.tickState('on')
% CC.tickState('off')

工具函數(shù)完整代碼
classdef chordChart
% @author : slandarer
% gzh : slandarer隨筆
% 使用示例:
% =========================================================================
% 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);
% CC=CC.draw()
properties
ax
arginList={'colName','rowName'}
verMatlab % MATLAB 版本: R2021a顯示為2021,R2021b顯示為2021.5
chordTable % table數(shù)組
dataMat % 數(shù)值矩陣
colName={}; % 列名稱
rowName={}; % 行名稱
thetaSetF
thetaSetT
% -----------------------------------------------------------
squareFHdl % 繪制下方方塊的圖形對(duì)象矩陣
squareTHdl % 繪制下上方方塊的圖形對(duì)象矩陣
nameFHdl % 繪制下方文本的圖形對(duì)象矩陣
nameTHdl % 繪制上方文本的圖形對(duì)象矩陣
chordMatHdl % 繪制弦的圖形對(duì)象矩陣
thetaTickFHdl % 刻度句柄
thetaTickTHdl % 刻度句柄
RTickFHdl % 軸線句柄
RTickTHdl % 軸線句柄
end
methods
function obj=chordChart(varargin)
if isa(varargin{1},'matlab.graphics.axis.Axes')
obj.ax=varargin{1};varargin(1)=[];
else
obj.ax=gca;
end
% 獲取版本信息
tver=version('-release');
obj.verMatlab=str2double(tver(1:4))+(abs(tver(5))-abs('a'))/2;
if obj.verMatlab<2017
hold on
else
hold(obj.ax,'on')
end
obj.dataMat=varargin{1};varargin(1)=[];
if isa(obj.dataMat,'table')
obj.chordTable=obj.dataMat;
if isempty(obj.chordTable.Properties.RowNames)
for i=1:size(obj.chordTable.Variables,1)
obj.rowName{i}=['R',num2str(i)];
end
end
else
% 獲取其他數(shù)據(jù)
for i=1:(length(varargin)-1)
tid=ismember(obj.arginList,varargin{i});
if any(tid)
obj.(obj.arginList{tid})=varargin{i+1};
end
end
tzerocell{1,size(obj.dataMat,2)}=zeros(size(obj.dataMat,1),1);
for i=1:size(obj.dataMat,2)
tzerocell{1,i}=zeros(size(obj.dataMat,1),1);
end
if isempty(obj.colName)
for i=1:size(obj.dataMat,2)
obj.colName{i}=['C',num2str(i)];
end
end
if isempty(obj.rowName)
for i=1:size(obj.dataMat,1)
obj.rowName{i}=['R',num2str(i)];
end
end
% 創(chuàng)建table數(shù)組
obj.chordTable=table(tzerocell{:});
obj.chordTable.Variables=obj.dataMat;
obj.chordTable.Properties.VariableNames=obj.colName;
obj.chordTable.Properties.RowNames=obj.rowName;
help chordChart
end
end
function obj=draw(obj)
obj.ax.XLim=[-1.38,1.38];
obj.ax.YLim=[-1.38,1.38];
obj.ax.XTick=[];
obj.ax.YTick=[];
obj.ax.XColor='none';
obj.ax.YColor='none';
obj.ax.PlotBoxAspectRatio=[1,1,1];
% 計(jì)算繪圖所用數(shù)值
tDMat=obj.chordTable.Variables;
tDFrom=obj.chordTable.Properties.RowNames;
tDTo=obj.chordTable.Properties.VariableNames;
tDMatUni=tDMat-min(min(tDMat));
tDMatUni=tDMatUni./max(max(tDMatUni));
sep1=1/20;
sep2=1/40;
ratioF=sum(tDMat,2)./sum(tDMat,[1,2]);
ratioF=[0,ratioF'];
ratioT=[0,sum(tDMat,1)./sum(tDMat,[1,2])];
sepNumF=size(tDMat,1);
sepNumT=size(tDMat,2);
sepLen=pi*(1-2*sep1)*sep2;
baseLenF=(pi*(1-sep2)-(sepNumF-1)*sepLen);
baseLenT=(pi*(1-sep2)-(sepNumT-1)*sepLen);
tColor=[61 96 137;76 103 86]./255;
% 繪制下方方塊
for i=1:sepNumF
theta1=2*pi-pi*sep1/2-sum(ratioF(1:i))*baseLenF-(i-1)*sepLen;
theta2=2*pi-pi*sep1/2-sum(ratioF(1:i+1))*baseLenF-(i-1)*sepLen;
theta=linspace(theta1,theta2,100);
X=cos(theta);Y=sin(theta);
obj.squareFHdl(i)=fill([1.05.*X,1.15.*X(end:-1:1)],[1.05.*Y,1.15.*Y(end:-1:1)],...
tColor(1,:),'EdgeColor','none');
theta3=(theta1+theta2)/2;
obj.nameFHdl(i)=text(cos(theta3).*1.28,sin(theta3).*1.28,tDFrom{i},'FontSize',12,'FontName','Arial',...
'HorizontalAlignment','center','Rotation',-(1.5*pi-theta3)./pi.*180);
obj.RTickFHdl(i)=plot(cos(theta).*1.17,sin(theta).*1.17,'Color',[0,0,0],'LineWidth',.8,'Visible','off');
end
% 繪制上方放塊
for j=1:sepNumT
theta1=pi-pi*sep1/2-sum(ratioT(1:j))*baseLenT-(j-1)*sepLen;
theta2=pi-pi*sep1/2-sum(ratioT(1:j+1))*baseLenT-(j-1)*sepLen;
theta=linspace(theta1,theta2,100);
X=cos(theta);Y=sin(theta);
obj.squareTHdl(j)=fill([1.05.*X,1.15.*X(end:-1:1)],[1.05.*Y,1.15.*Y(end:-1:1)],...
tColor(2,:),'EdgeColor','none');
theta3=(theta1+theta2)/2;
obj.nameTHdl(j)=text(cos(theta3).*1.28,sin(theta3).*1.28,tDTo{j},'FontSize',12,'FontName','Arial',...
'HorizontalAlignment','center','Rotation',-(.5*pi-theta3)./pi.*180);
obj.RTickTHdl(j)=plot(cos(theta).*1.17,sin(theta).*1.17,'Color',[0,0,0],'LineWidth',.8,'Visible','off');
end
colorFunc=colorFuncFactory(flipud(summer(50)));
% 繪制弦
for i=1:sepNumF
for j=sepNumT:-1:1
theta1=2*pi-pi*sep1/2-sum(ratioF(1:i))*baseLenF-(i-1)*sepLen;
theta2=2*pi-pi*sep1/2-sum(ratioF(1:i+1))*baseLenF-(i-1)*sepLen;
theta3=pi-pi*sep1/2-sum(ratioT(1:j))*baseLenT-(j-1)*sepLen;
theta4=pi-pi*sep1/2-sum(ratioT(1:j+1))*baseLenT-(j-1)*sepLen;
tRowV=tDMat(i,:);tRowV=[0,tRowV(end:-1:1)./sum(tRowV)];
tColV=tDMat(:,j)';tColV=[0,tColV./sum(tColV)];
% 貝塞爾曲線斷點(diǎn)計(jì)算
theta5=(theta2-theta1).*sum(tRowV(1:(sepNumT+1-j)))+theta1;
theta6=(theta2-theta1).*sum(tRowV(1:(sepNumT+2-j)))+theta1;
theta7=(theta3-theta4).*sum(tColV(1:i))+theta4;
theta8=(theta3-theta4).*sum(tColV(1:i+1))+theta4;
tPnt1=[cos(theta5),sin(theta5)];
tPnt2=[cos(theta6),sin(theta6)];
tPnt3=[cos(theta7),sin(theta7)];
tPnt4=[cos(theta8),sin(theta8)];
if j==sepNumT,obj.thetaSetF(i,1)=theta5;end
obj.thetaSetF(i,j+1)=theta6;
if i==1,obj.thetaSetT(1,j)=theta7;end
obj.thetaSetT(i+1,j)=theta8;
% 計(jì)算曲線
tLine1=bezierCurve([tPnt1;0,0;tPnt3],200);
tLine2=bezierCurve([tPnt2;0,0;tPnt4],200);
tline3=[cos(linspace(theta6,theta5,100))',sin(linspace(theta6,theta5,100))'];
tline4=[cos(linspace(theta7,theta8,100))',sin(linspace(theta7,theta8,100))'];
obj.chordMatHdl(i,j)=fill([tLine1(:,1);tline4(:,1);tLine2(end:-1:1,1);tline3(:,1)],...
[tLine1(:,2);tline4(:,2);tLine2(end:-1:1,2);tline3(:,2)],...
colorFunc(tDMatUni(i,j)),'FaceAlpha',.3,'EdgeColor','none');
if tDMat(i,j)==0
set(obj.chordMatHdl(i,j),'Visible','off')
end
end
% 繪制刻度線
tX=[cos(obj.thetaSetF(i,:)).*1.17;cos(obj.thetaSetF(i,:)).*1.19;nan.*ones(1,sepNumT+1)];
tY=[sin(obj.thetaSetF(i,:)).*1.17;sin(obj.thetaSetF(i,:)).*1.19;nan.*ones(1,sepNumT+1)];
obj.thetaTickFHdl(i)=plot(tX(:),tY(:),'Color',[0,0,0],'LineWidth',.8,'Visible','off');
end
for j=1:sepNumT
tX=[cos(obj.thetaSetT(:,j)').*1.17;cos(obj.thetaSetT(:,j)').*1.19;nan.*ones(1,sepNumF+1)];
tY=[sin(obj.thetaSetT(:,j)').*1.17;sin(obj.thetaSetT(:,j)').*1.19;nan.*ones(1,sepNumF+1)];
obj.thetaTickTHdl(j)=plot(tX(:),tY(:),'Color',[0,0,0],'LineWidth',.8,'Visible','off');
end
% 貝塞爾函數(shù)
function pnts=bezierCurve(pnts,N)
t=linspace(0,1,N);
p=size(pnts,1)-1;
coe1=factorial(p)./factorial(0:p)./factorial(p:-1:0);
coe2=((t).^((0:p)')).*((1-t).^((p:-1:0)'));
pnts=(pnts'*(coe1'.*coe2))';
end
% 漸變色句柄生成函數(shù)
function colorFunc=colorFuncFactory(colorList)
x=(0:size(colorList,1)-1)./(size(colorList,1)-1);
y1=colorList(:,1);y2=colorList(:,2);y3=colorList(:,3);
colorFunc=@(X)[interp1(x,y1,X,'linear')',interp1(x,y2,X,'linear')',interp1(x,y3,X,'linear')'];
end
end
% =================================================================
% 批量弦屬性設(shè)置
function setChordProp(obj,varargin)
tDMat=obj.chordTable.Variables;
for i=1:size(tDMat,1)
for j=1:size(tDMat,2)
set(obj.chordMatHdl(i,j),varargin{:});
end
end
end
% 單獨(dú)弦屬性設(shè)置
function setChordMN(obj,m,n,varargin)
set(obj.chordMatHdl(m,n),varargin{:});
end
% 根據(jù)colormap映射顏色
function setChordColorByMap(obj,colorList)
tDMat=obj.chordTable.Variables;
tDMatUni=tDMat-min(min(tDMat));
tDMatUni=tDMatUni./max(max(tDMatUni));
colorFunc=colorFuncFactory(colorList);
for i=1:size(tDMat,1)
for j=1:size(tDMat,2)
set(obj.chordMatHdl(i,j),'FaceColor',colorFunc(tDMatUni(i,j)));
end
end
% 漸變色句柄生成函數(shù)
function colorFunc=colorFuncFactory(colorList)
x=(0:size(colorList,1)-1)./(size(colorList,1)-1);
y1=colorList(:,1);y2=colorList(:,2);y3=colorList(:,3);
colorFunc=@(X)[interp1(x,y1,X,'linear')',interp1(x,y2,X,'linear')',interp1(x,y3,X,'linear')'];
end
end
% -----------------------------------------------------------------
% 批量上方方塊屬性設(shè)置
function setSquareT_Prop(obj,varargin)
tDMat=obj.chordTable.Variables;
for j=1:size(tDMat,2)
set(obj.squareTHdl(j),varargin{:});
end
end
% 單獨(dú)上方方塊屬性設(shè)置
function setSquareT_N(obj,n,varargin)
set(obj.squareTHdl(n),varargin{:});
end
% 批量下方方塊屬性設(shè)置
function setSquareF_Prop(obj,varargin)
tDMat=obj.chordTable.Variables;
for i=1:size(tDMat,1)
set(obj.squareFHdl(i),varargin{:});
end
end
% 單獨(dú)上方方塊屬性設(shè)置
function setSquareF_N(obj,n,varargin)
set(obj.squareFHdl(n),varargin{:});
end
% -----------------------------------------------------------------
% 字體設(shè)置
function setFont(obj,varargin)
tDMat=obj.chordTable.Variables;
for i=1:size(tDMat,1)
set(obj.nameFHdl(i),varargin{:});
end
for j=1:size(tDMat,2)
set(obj.nameTHdl(j),varargin{:});
end
end
% -----------------------------------------------------------------
% 刻度開(kāi)關(guān)
function tickState(obj,state)
tDMat=obj.chordTable.Variables;
for i=1:size(tDMat,1)
set(obj.thetaTickFHdl(i),'Visible',state);
set(obj.RTickFHdl(i),'Visible',state);
end
for j=1:size(tDMat,2)
set(obj.thetaTickTHdl(j),'Visible',state);
set(obj.RTickTHdl(j),'Visible',state);
end
end
end
end
封面圖繪制代碼
封面一
% demo 1
% @author : slandarer
% gzh : slandarer隨筆
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);
CC=CC.draw();
CC.setFont('FontSize',17,'FontName','Cambria')
CC.tickState('on')

封面二
% demo 2
% @author : slandarer
% gzh : slandarer隨筆
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);
CC=CC.draw();
% 弦屬性設(shè)置 ===============================================================
% CC.setChordProp('EdgeColor',[.3,.3,.3],'LineStyle','--',...
% 'LineWidth',.1,'FaceColor',[.3,.3,.3])
% CC.setChordMN(2,4,'FaceColor',[1,0,0])
CC.setChordColorByMap(copper(100))
% 方塊屬性設(shè)置 =============================================================
CC.setSquareT_Prop('FaceColor',[0,0,0])
CC.setSquareT_N(2,'FaceColor',[.8,0,0])
% CC.setSquareF_Prop('FaceColor',[0,0,0])
% CC.setSquareF_N(2,'FaceColor',[.8,0,0])
% 字體設(shè)置 =================================================================
CC.setFont('FontSize',17,'FontName','Cambria','Color',[0,0,.8])
% 刻度開(kāi)關(guān)設(shè)置 =============================================================
CC.tickState('on')

以上就是利用Matlab繪制好看的弦圖的詳細(xì)內(nèi)容,更多關(guān)于Matlab弦圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的掃雷游戲操作
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的掃雷游戲操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
QT實(shí)戰(zhàn)之打開(kāi)最近圖片功能的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了如何利用Qt和QSettings實(shí)現(xiàn)打開(kāi)最近圖片功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)QT有一定的幫助,感興趣的可以了解一下2022-06-06
如何使用arm-none-eabi-gcc編譯器搭建STM32的Vscode開(kāi)發(fā)環(huán)境
這篇文章主要介紹了使用arm-none-eabi-gcc編譯器搭建STM32的Vscode開(kāi)發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
C++ OpenCV實(shí)現(xiàn)灰度圖蒙版GrayMask的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C++和OpenCV實(shí)現(xiàn)灰度圖蒙版GrayMask,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定參考價(jià)值,需要的可以參考一下2022-05-05
C++強(qiáng)制轉(zhuǎn)換與智能指針示例詳解
這篇文章主要介紹了C++強(qiáng)制轉(zhuǎn)換與智能指針示例,智能指針(Smart Pointer)是一種抽象的數(shù)據(jù)類型。在程序設(shè)計(jì)中,它通常是經(jīng)由類模板來(lái)實(shí)現(xiàn),借由模板來(lái)達(dá)成泛型,借由類別的析構(gòu)函數(shù)來(lái)達(dá)成自動(dòng)釋放指針?biāo)赶虻拇鎯?chǔ)器或?qū)ο?/div> 2022-11-11
C++實(shí)現(xiàn)打印1到最大的n位數(shù)
這篇文章主要介紹了C++實(shí)現(xiàn)打印1到最大的n位數(shù),并分析了實(shí)現(xiàn)代碼中語(yǔ)句的跳轉(zhuǎn)技巧,需要的朋友可以參考下2014-09-09最新評(píng)論

