利用Matlab繪制好看的弦圖
弦圖在python中以及R中非常常見,但是MATLAB中卻始終沒有相關函數,file exchange中也沒有工作做的較為完備的弦圖繪制函數(不過現在有瞭,我已經往上面也傳瞭一份hiahiahia)
僅工具函數主體部分約300行,字符數約8000,能畫出與R語言同等質量的弦圖實屬不易,希望能有個`點贊“!!!
由於工具函數過長,將被放在最後展示,以下將先展示函數用法
封面圖
使用教程
1.數據格式
數據要求為全部數值大於等於0的數值矩陣,或者table
數組,或者數值矩陣+行列名元胞數組,首先舉個數值矩陣的例子:
數值矩陣
dataMat=randi([0,5],[5,4]); % 繪圖 CC=chordChart(dataMat); CC=CC.draw();
這樣由於沒對各個對象命名,因此會自動命名為Rn
和Cn
數值矩陣+行列名元胞數組
這是最推薦的一種格式:
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
要和矩陣的列相同大小
對於本列子來說第2行第3列數值是1,就說明有一份能量從S2
流向G3
,也就在這倆之間需要畫單位寬度的弦。
table 數組
需要使用如下格式的table數組:
當然,如果各個行沒有命名的話依舊會自動命名的。
2.修飾弦
弦的批量修飾
弦的批量修飾可以使用setChordProp
函數,一切Patch對象所具有的屬性均可以被修飾,舉個例子(修飾一下弦的顏色,邊緣顏色,邊緣線形狀等):
CC.setChordProp('EdgeColor',[.3,.3,.3],'LineStyle','--',... 'LineWidth',.1,'FaceColor',[.3,.3,.3])
弦的單獨修飾
弦的單獨修飾可以使用setChordMN
函數,其中m,n值是和原始數值矩陣的行列完全對應的,舉個例子(把S2
流向G4
的弦顏色更改為紅色):
CC.setChordMN(2,4,'FaceColor',[1,0,0])
弦的顏色映射
使用setChordColorByMap
函數進行顏色映射,
matlab 自帶的colormap
均可用:
或者也可自行放入一個n×3大小的顏色列表,程序會自動對其進行插值:舉個例子:
CC.setChordColorByMap(copper(100))
3.圓弧狀方塊修飾
圓弧狀方塊批量修飾
使用
setSquareT_Prop
setSquareF_Prop
分別修飾上方方塊和下方方塊,一切Patch對象所具有的屬性均可以被修飾,舉個例子,上方方塊批量修飾(改為黑色):
CC.setSquareT_Prop('FaceColor',[0,0,0])
圓弧狀方塊單獨修飾
使用
setSquareT_N
setSquareF_N
分別修飾上方方塊和下方方塊,舉個例子,上方第二個方塊單獨修飾(改為紅色):
CC.setSquareT_N(2,'FaceColor',[.8,0,0])
4.字體調整
使用setFont
函數對字體進行調整,所有text對象具有的屬性均可以修飾,舉個例子(更改文本的字號、字體和顏色):
CC.setFont('FontSize',25,'FontName','Cambria','Color',[0,0,.8])
5.顯示和隱藏刻度
用法:
CC.tickState('on') % CC.tickState('off')
工具函數完整代碼
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數組 dataMat % 數值矩陣 colName={}; % 列名稱 rowName={}; % 行名稱 thetaSetF thetaSetT % ----------------------------------------------------------- squareFHdl % 繪制下方方塊的圖形對象矩陣 squareTHdl % 繪制下上方方塊的圖形對象矩陣 nameFHdl % 繪制下方文本的圖形對象矩陣 nameTHdl % 繪制上方文本的圖形對象矩陣 chordMatHdl % 繪制弦的圖形對象矩陣 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 % 獲取其他數據 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 % 創建table數組 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]; % 計算繪圖所用數值 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)]; % 貝塞爾曲線斷點計算 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; % 計算曲線 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 % 貝塞爾函數 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 % 漸變色句柄生成函數 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 % ================================================================= % 批量弦屬性設置 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 % 單獨弦屬性設置 function setChordMN(obj,m,n,varargin) set(obj.chordMatHdl(m,n),varargin{:}); end % 根據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 % 漸變色句柄生成函數 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 % ----------------------------------------------------------------- % 批量上方方塊屬性設置 function setSquareT_Prop(obj,varargin) tDMat=obj.chordTable.Variables; for j=1:size(tDMat,2) set(obj.squareTHdl(j),varargin{:}); end end % 單獨上方方塊屬性設置 function setSquareT_N(obj,n,varargin) set(obj.squareTHdl(n),varargin{:}); end % 批量下方方塊屬性設置 function setSquareF_Prop(obj,varargin) tDMat=obj.chordTable.Variables; for i=1:size(tDMat,1) set(obj.squareFHdl(i),varargin{:}); end end % 單獨上方方塊屬性設置 function setSquareF_N(obj,n,varargin) set(obj.squareFHdl(n),varargin{:}); end % ----------------------------------------------------------------- % 字體設置 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 % ----------------------------------------------------------------- % 刻度開關 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(); % 弦屬性設置 =============================================================== % 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)) % 方塊屬性設置 ============================================================= 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]) % 字體設置 ================================================================= CC.setFont('FontSize',17,'FontName','Cambria','Color',[0,0,.8]) % 刻度開關設置 ============================================================= CC.tickState('on')
以上就是利用Matlab繪制好看的弦圖的詳細內容,更多關於Matlab弦圖的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Matlab實現極坐標堆疊柱狀圖的繪制
- Matlab繪制散點密度圖的教程詳解
- python機器學習MATLAB最小二乘法的兩種解讀
- 詳解Matlab如何繪制桑基圖
- 詳解Matlab繪制3D玫瑰花的方法(內附旋轉版本)