您当前的位置: 首页 >  matlab

暂无认证

  • 21浏览

    0关注

    93895博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

MATLAB | 全网唯一! 又双叒叕一种弦图绘制

发布时间:2022-10-06 11:49:20 ,浏览量:21

前几天有粉丝问我这种图能不能画: 大体看了一下就是有联系的两个元素之间连线,同时将不同类用不同颜色划分,于是又双叒叕了一个工具函数:

绘制效果

教程部分 基础使用

输入数据要求一个nxn大小的0-1矩阵,代表各个元素之间有没有连线,同时还需要一个nx1大小的Class列表代表每个元素属于哪一类,举个简单的例子:

% 生成随机200x200对称0-1矩阵 Data=rand(200,200)>.992; Data=(Data+Data')>0; % 生成200x1随机分类编号 Class=randi([1,5],[200,1]); CC=circosChart(Data,Class); CC=CC.draw(); 

修改颜色

以下两种写法等价:

colorList=[78 101 155; 138 140 191; 184 168 207; 231 188 198; 253 207 158]./255; CC=circosChart(Data,Class,'ColorOrder',colorList); CC=CC.draw(); 
CC=circosChart(Data,Class); CC=CC.draw(); colorList=[78 101 155; 138 140 191; 184 168 207; 231 188 198; 253 207 158]./255; CC.setColor(1:5,colorList) 

除颜色外其他线属性设置

使用setLine修饰其他属性,'Line’对象具有的属性均可以修饰,例如改变粗细:

CC.setLine('LineWidth',5) 

添加和修改标签

设置

  • partNameList
  • classNameList

俩属性设置标签:

% 生成随机200x200对称0-1矩阵 Data=rand(200,200)>.992; Data=(Data+Data')>0; % 生成200x1随机分类编号 Class=randi([1,5],[200,1]); for i=1:200 partName{i}=[num2str(Class(i)),'-',num2str(i)]; end
className={'AAAAA','BBBBB','CCCCC','DDDDD','EEEEE'}; CC=circosChart(Data,Class,'PartName',partName,'ClassName',className); CC=CC.draw(); 

修饰标签

使用:

  • setPartLabel
  • setClassLabel

俩函数修饰文本标签,例如:

CC.setPartLabel('Color',[0,0,.8],'FontName','Cambria') CC.setClassLabel('Color',[.8,0,0],'FontName','Cambria','FontSize',25) 

一个实例

展示 π \pi π小数点后500和1000位数字前后连接情况:500个点的时候我们发现7出现次数似乎格外的少,本来以为写错了,结果算了一下就只出现了36次,确实是出现的次数比较少:

% demo 1 pi小数点后1000个数值前后连接状况
piStr=['1415926535897932384626433832795028841971693993751058209749445923078',... '1640628620899862803482534211706798214808651328230664709384460955058',... '2231725359408128481117450284102701938521105559644622948954930381964',... '4288109756659334461284756482337867831652712019091456485669234603486',... '1045432664821339360726024914127372458700660631558817488152092096282',... '9254091715364367892590360011330530548820466521384146951941511609433',... '0572703657595919530921861173819326117931051185480744623799627495673',... '5188575272489122793818301194912983367336244065664308602139494639522',... '4737190702179860943702770539217176293176752384674818467669405132000',... '5681271452635608277857713427577896091736371787214684409012249534301',... '4654958537105079227968925892354201995611212902196086403441815981362',... '9774771309960518707211349999998372978049951059731732816096318595024',... '4594553469083026425223082533446850352619311881710100031378387528865',... '8753320838142061717766914730359825349042875546873115956286388235378',... '75937519577818577805321712268066130019278766111959092164201999']; Class=abs(piStr(1:1000))-47; % 类要求从1开始而非0因此这里减去47 Data=diag(ones(1,999),-1); className={'0','1','2','3','4','5','6','7','8','9'}; colorOrder=[239,65,75;230,115,48;229,158,57;232,136,85;239,199,97; 144,180,116;78,166,136;81,140,136;90,118,142;43,121,159]./255; CC=circosChart(Data,Class,'ClassName',className,'ColorOrder',colorOrder); CC=CC.draw(); ax=gca; ax.Color=[0,0,0]; CC.setClassLabel('Color',[1,1,1],'FontSize',25,'FontName','Cambria') CC.setLine('LineWidth',.7) 

工具函数完整代码
classdef circosChart % @author : slandarer % gzh : slandarer随笔 


    properties
        ax,arginList={'ColorOrder','ClassName','PartName'} ColorOrder=[80,118,169;226,144,50;127,167,58;242,86,54;126,109,167; 196,98,37;74,148,189;255,182,46;161,86,144;134,138,33; 240,73,53;90,123,207;254,147,44;186,79,115;35,170,102]./255; ClassName,PartName Data,Class,indexInClass,colorSet={[]} classSet,classNum,classSize,classRatio,classTheta
        lineHdl,partLabelHdl,classLabelHdl,scatterHdl
    end

    methods
        function obj=circosChart(Data,Class,varargin) obj.Data=Data; obj.Class=Class(:); obj.classSet=unique(Class); obj.classNum=length(obj.classSet); obj.indexInClass=zeros(length(obj.Class),1); % 计算比例 for i=1:obj.classNum
                tClassBool=obj.classSet(i)==obj.Class; tCumsumBool=cumsum(tClassBool); obj.classSize(i)=sum(tClassBool); obj.indexInClass(tClassBool)=tCumsumBool(tClassBool); end
            obj.classRatio=obj.classSize./sum(obj.classSize); disp(char([64 97 117 116 104 111 114 32 58 32 115 108 97 110 100 97 114 101 114])) obj.ColorOrder=[obj.ColorOrder;rand([obj.classNum,3])]; for i=1:size(obj.Data,1) obj.PartName{i}=''; end for i=1:obj.classNum obj.ClassName{i}=['Class ',num2str(i)]; end % 获取其他数据 for i=1:2:(length(varargin)-1) tid=ismember(obj.arginList,varargin{i}); if any(tid) obj.(obj.arginList{tid})=varargin{i+1}; end
            end
        end

        function obj=draw(obj) obj.ax=gca;hold on obj.ax.XLim=[-1.2,1.2]; obj.ax.YLim=[-1.2,1.2]; obj.ax.XTick=[]; obj.ax.YTick=[]; obj.ax.XColor='none'; obj.ax.YColor='none'; obj.ax.PlotBoxAspectRatio=[1,1,1]; % 调整初始界面大小
            fig=obj.ax.Parent; if max(fig.Position(3:4))<600 fig.Position(3:4)=1.8.*fig.Position(3:4); fig.Position(1:2)=fig.Position(1:2)./3; end

            sepTheta=2/30/obj.classNum; cumTheta=[0,28/30*cumsum(obj.classRatio)]; if isempty(obj.PartName{1})&&isempty(obj.PartName{2}) tdis=1.1; else tdis=1.22; end % 计算每一类中每一个元素的角度 for i=1:obj.classNum
                obj.classTheta(i).T=linspace(sepTheta*i+cumTheta(i),sepTheta*i+cumTheta(i+1),obj.classSize(i)).*2.*pi; obj.scatterHdl(i)=scatter(cos(obj.classTheta(i).T),sin(obj.classTheta(i).T),30,'filled','CData',obj.ColorOrder(i,:),'MarkerEdgeColor','none'); CTi=mean(obj.classTheta(i).T); rotation=CTi/pi*180; if rotation>0&&rotation<180 obj.classLabelHdl(i)=text(cos(CTi).*tdis,sin(CTi).*tdis,obj.ClassName{i},'FontSize',14,'FontName','Arial',... 'HorizontalAlignment','center','Rotation',-(.5*pi-CTi)./pi.*180); else obj.classLabelHdl(i)=text(cos(CTi).*tdis,sin(CTi).*tdis,obj.ClassName{i},'FontSize',14,... 'HorizontalAlignment','center','Rotation',-(1.5*pi-CTi)./pi.*180); end
            end % 绘制文字 for i=1:size(obj.Data,1) Ci=obj.Class(i);Pi=obj.indexInClass(i); Ti=obj.classTheta(Ci).T(Pi); rotation=Ti/pi*180; if rotation>90&&rotation<270 rotation=rotation+180; obj.partLabelHdl(i)=text(cos(Ti).*1.03,sin(Ti).*1.03,obj.PartName{i},'Rotation',rotation,'HorizontalAlignment','right','FontSize',8); else obj.partLabelHdl(i)=text(cos(Ti).*1.03,sin(Ti).*1.03,obj.PartName{i},'Rotation',rotation,'FontSize',8); end
            end % 计算类与类之间的渐变色
            t2=linspace(0,1,200);t1=1-t2; for i=1:obj.classNum for j=1:obj.classNum
                    C1=obj.ColorOrder(i,:); C2=obj.ColorOrder(j,:); obj.colorSet{i,j}=uint8([t1.*C1(1)+t2.*C2(1); t1.*C1(2)+t2.*C2(2); t1.*C1(3)+t2.*C2(3) ones(1,200).*.6].*255); end
            end % 画线并赋予颜色 for i=1:size(obj.Data,1) for j=1:(i-1) if obj.Data(i,j)>0 Ci=obj.Class(i);Pi=obj.indexInClass(i); Cj=obj.Class(j);Pj=obj.indexInClass(j); Ti=obj.classTheta(Ci).T(Pi); Tj=obj.classTheta(Cj).T(Pj); Xij=[cos(Ti),0,cos(Tj)]'; Yij=[sin(Ti),0,sin(Tj)]'; XYb=bezierCurve([Xij,Yij],200); obj.lineHdl(i,j)=plot(XYb(:,1),XYb(:,2),'-','LineWidth',1); end
                end
            end pause(1e-16) for i=1:size(obj.Data,1) for j=1:(i-1) if obj.Data(i,j)>0 Ci=obj.Class(i); Cj=obj.Class(j); set(get(obj.lineHdl(i,j),'Edge'),'ColorBinding','interpolated','ColorData',obj.colorSet{Ci,Cj}) end
                end
            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
        end % 设置线除了颜色的其他属性
        function setLine(obj,varargin) for i=1:size(obj.Data,1) for j=1:(i-1) if obj.Data(i,j)>0 set(obj.lineHdl(i,j),varargin{:}) end
                end
             end
        end % 设置线颜色
        function setColor(obj,N,color) obj.ColorOrder(N,:)=color; t2=linspace(0,1,200);t1=1-t2; for i=1:obj.classNum set(obj.scatterHdl(i),'CData',obj.ColorOrder(i,:)) for j=1:obj.classNum
                    C1=obj.ColorOrder(i,:); C2=obj.ColorOrder(j,:); obj.colorSet{i,j}=uint8([t1.*C1(1)+t2.*C2(1); t1.*C1(2)+t2.*C2(2); t1.*C1(3)+t2.*C2(3) ones(1,200).*.6].*255); end
            end for i=1:size(obj.Data,1) for j=1:(i-1) if obj.Data(i,j)>0 Ci=obj.Class(i); Cj=obj.Class(j); set(get(obj.lineHdl(i,j),'Edge'),'ColorBinding','interpolated','ColorData',obj.colorSet{Ci,Cj}) end
                end
            end
        end % 设置标签
        function setPartLabel(obj,varargin) for i=1:size(obj.Data,1) set(obj.partLabelHdl(i),varargin{:}); end
        end

        function setClassLabel(obj,varargin) for i=1:obj.classNum set(obj.classLabelHdl(i),varargin{:}); end
        end
    end % @author : slandarer % gzh : slandarer随笔 % Zhaoxu Liu (2022). circos plot 弦图 % (https://www.mathworks.com/matlabcentral/fileexchange/118655-circos-plot), % MATLAB Central File Exchange. 检索来源 2022/10/6. end

MATLAB弦图绘制能画成这样属实不易,如果有用请留个赞叭~

未经允许本代码请勿作商业用途,引用的话可以引用我file exchange上的链接,可使用如下格式:

Zhaoxu Liu (2022). circos plot 弦图 (https://www.mathworks.com/matlabcentral/fileexchange/118655-circos-plot), MATLAB Central File Exchange. 检索来源 2022/10/6.

若转载请保留以上file exchange链接及本文链接!!!

全部m文件及数据获取:

【链接】:https://pan.baidu.com/s/1pQoh8cE5G4oeTLoXgFoRGw?pwd=slan 【提取码】:slan

关注
打赏
1655516835
查看更多评论
立即登录/注册

微信扫码登录

2.7888s