全网唯一, MATLAB绘制好看的弦图

Posted slandarer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全网唯一, 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();

这样由于没对各个对象命名,因此会自动命名为RnCn

数值矩阵+行列名元胞数组

这是最推荐的一种格式:

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(varargin1,'matlab.graphics.axis.Axes')
                obj.ax=varargin1;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=varargin1;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.rowNamei=['R',num2str(i)];
                    end
                end
            else

            % 获取其他数据
            for i=1:(length(varargin)-1)
                tid=ismember(obj.arginList,varargini);
                if any(tid)
                obj.(obj.arginListtid)=varargini+1;
                end
            end
            tzerocell1,size(obj.dataMat,2)=zeros(size(obj.dataMat,1),1);
            for i=1:size(obj.dataMat,2)
                tzerocell1,i=zeros(size(obj.dataMat,1),1);
            end
            if isempty(obj.colName)
                for i=1:size(obj.dataMat,2)
                    obj.colNamei=['C',num2str(i)];
                end
            end
            if isempty(obj.rowName)
                for i=1:size(obj.dataMat,1)
                    obj.rowNamei=['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,tDFromi,'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,tDToj,'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以上是关于全网唯一, MATLAB绘制好看的弦图的主要内容,如果未能解决你的问题,请参考以下文章

MATLAB | 全网唯一 MATLAB双向弦图(有向弦图)绘制

MATLAB | 全网唯一 MATLAB双向弦图(有向弦图)绘制

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

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

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

MATLAB | 全网唯一,使用MATLAB绘制好看的韦恩图(venn)