服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 详解Matlab如何绘制桑基图

详解Matlab如何绘制桑基图

2022-10-11 15:14slandarer C/C++

桑基图是一种特定类型的流程图,图中延伸的分支的宽度对应数据流量的大小,通常应用于能源、材料成分、金融等数据的可视化分析。本文将用Matlab绘制好看的桑基图,需要的可以参考一下

这次主要是分享自己写的一个函数,用来绘制桑基图,效果大概是下面这样子:

详解Matlab如何绘制桑基图

详解Matlab如何绘制桑基图

详解Matlab如何绘制桑基图

先说明函数(sankey2)怎么用,函数完整代码放在博客最后

 

详细用法

1 使用示例

新建一个m文件,运行如下代码

List={'a1',1,'A';
    'a2',1,'A';
    'a3',1,'A';
    'a3',0.5,'C';
    'b1',1,'B';
    'b2',1,'B';
    'b3',1,'B';
    'c1',1,'C';
    'c2',1,'C';
    'c3',1,'C';
    'A',2,'AA';
    'A',1,'BB';
    'B',1.5,'BB';
    'B',1.5,'AA';
    'C',3.5,'BB';
    };
axis([0,2,0,1])
sankeyHdl=sankey2([],'XLim',[0,2],'YLim',[0,1],'PieceWidth',0.15,'List',List,'Color',[0.3,0.3,0.7])

详解Matlab如何绘制桑基图

2 输入参数

2.1 必要输入参数

必要参数一共有四个,第一个就是流量表(‘List’),可以从excel里导入,也可以像下图这样直接写在cell数组里:

List={'a1',1,'A';
    'a2',1,'A';
    'a3',1,'A';
    'a3',0.5,'C';
    'b1',1,'B';
    'b2',1,'B';
    'b3',1,'B';
    'c1',1,'C';
    'c2',1,'C';
    'c3',1,'C';
    'A',2,'AA';
    'A',1,'BB';
    'B',1.5,'BB';
    'B',1.5,'AA';
    'C',3.5,'BB';
    };

另外三个参数为,x轴范围(‘xLim’),y轴范围(‘YLim’),以及函数第一个参数,要绘制图像的axes,要画在当前窗口可以将第一个参数写作[]或者gca

2.2 修饰参数

主要有以下几个,不写时用省缺值替换

  • Color 方块颜色
  • EdgeColor 方块边缘颜色
  • FontSize 字号
  • FontColor 字体颜色
  • PieceWidth 方块宽度
  • Margin 桑基图距离边缘距离
  • Sep 纵向空白占方块总长度比例

其中Color可以是个nx3大小的矩阵,矩阵中数值范围为[0,1],例如:

List={'a1',1,'A';
    'a2',1,'A';
    'a3',1,'A';
    'a3',0.5,'C';
    'b1',1,'B';
    'b2',1,'B';
    'b3',1,'B';
    'c1',1,'C';
    'c2',1,'C';
    'c3',1,'C';
    'A',2,'AA';
    'A',1,'BB';
    'B',1.5,'BB';
    'B',1.5,'AA';
    'C',3.5,'BB';
    };
axis([0,2,0,1])
colorList=[0.4600    0.5400    0.4600
  0.5400    0.6800    0.4600
  0.4100    0.4900    0.3600
  0.3800    0.5300    0.8400
  0.4400    0.5900    0.8700
  0.5800    0.7900    0.9300
  0.6500    0.6400    0.8400
  0.6300    0.6300    0.8000
  0.5600    0.5300    0.6700
  0.7600    0.8100    0.4300
  0.5600    0.8600    0.9700
  0.7800    0.5900    0.6500
  0.8900    0.9100    0.5300
  0.9300    0.5600    0.2500];
sankeyHdl=sankey2([],'XLim',[0,2],'YLim',[0,1],'PieceWidth',0.15,'List',List,'Color',colorList)

详解Matlab如何绘制桑基图

3 输出

函数的输出如下:

详解Matlab如何绘制桑基图

nameList就是每一个元素的名称,block是每一个方块的图形对象,connect是每一个连接的图形对象,txt是每一个标签的文本对象,我们可以做出以下操作:

图形对象和文本对象原本自带的属性依旧可以用(颜色,位置,透明度,边缘粗细等等)
假设我们编写了如下代码的基础上,我们尝试对对象进行操作:

List={'a1',1,'A';
    'a2',1,'A';
    'a3',1,'A';
    'a3',0.5,'C';
    'b1',1,'B';
    'b2',1,'B';
    'b3',1,'B';
    'c1',1,'C';
    'c2',1,'C';
    'c3',1,'C';
    'A',2,'AA';
    'A',1,'BB';
    'B',1.5,'BB';
    'B',1.5,'AA';
    'C',3.5,'BB';
    };
axis([0,2,0,1])
sankeyHdl=sankey2([],'XLim',[0,2],'YLim',[0,1],'PieceWidth',0.15,'List',List,'Color',colorList)

详解Matlab如何绘制桑基图

操作1 把第四个方块颜色变为红色

sankeyHdl.block(4).FaceColor=[0.8,0.3,0.3];

详解Matlab如何绘制桑基图

操作2 把第10个方块的第一个连接变为红色

sankeyHdl.connect(10,1).FaceColor=[0.8,0.3,0.3];

详解Matlab如何绘制桑基图

操作3 把第11个标签文本放大

sankeyHdl.txt(11).FontSize=40;

详解Matlab如何绘制桑基图

 

函数完整代码

function sankeyHdl=sankey2(varargin)
if strcmp(get(varargin{1},'type'),'axes' )
  ax=varargin{1};
else
  ax=gca;
end
hold(ax,'on')

%若未设置,则图像的初始值==================================================
prop.Color=[0,0,0];
prop.FontSize=10;
prop.FontColor=[0,0,0];
prop.Xlim=[0,1];
prop.YLim=[0,1];
prop.PieceWidth=0.15;
prop.List=[];
prop.Margin=0.05;
prop.Sep=1/8;
prop.EdgeColor=[0 0 0];

%从可变长度变量中提取有用信息==============================================
for i=1:length(varargin)
  tempVar=varargin{i};
  if ischar(tempVar)&&length(tempVar)>1
      prop.(tempVar)=varargin{i+1};
  end
end

%流量矩阵构建==============================================================
nameList=unique([prop.List(:,1);prop.List(:,3)],'stable');
blockMat=zeros(length(nameList));
for i=1:size(prop.List,1)
  s=strcmp(nameList,prop.List(i,1));
  e=strcmp(nameList,prop.List(i,3));
  blockMat(s,e)=prop.List{i,2};
end
totalFlow=max([sum(blockMat,1);sum(blockMat,2)'],[],1);


%划分桑基图层次============================================================
List_L=prop.List(:,1);
List_R=prop.List(:,3);
prop.layer=[];layerRoot=[];n=1;
for i=length(List_R):-1:1
  if ~any(strcmp(List_L,List_R{i}))
      layerRoot=[layerRoot;find(strcmp(nameList,List_R{i}))];
  end
end
layerRoot=unique(layerRoot,'stable');
while ~isempty(List_L)
  layer_n=[];
  for i=length(List_L):-1:1
      if ~any(strcmp(List_R,List_L{i}))
          layer_n=[layer_n;find(strcmp(nameList,List_L{i}))];
          List_L(i)=[];
          List_R(i)=[];
      end
  end
  layer_n=unique(layer_n,'stable');
  prop.layer(length(layer_n),n)=0;
  prop.layer(1:length(layer_n),n)=layer_n;
  n=n+1;
end
prop.layer(length(layerRoot),n)=0;
prop.layer(1:length(layerRoot),n)=layerRoot;
prop.layerNum=size(prop.layer,2);




%绘制方块==================================================================
baseBlockX=[0,1,1,0];
baseBlockY=[0,0,1,1];
bnul=max(sum(prop.layer~=0,1));   %block number upper limit
baseLenY=(diff(prop.YLim)-2*prop.Margin)/(bnul+(bnul-1)*prop.Sep)*bnul;
baseLenX=(diff(prop.XLim)-2*prop.Margin)/(prop.layerNum-0.5);
colorIndex=1;
for i=1:prop.layerNum
  tempY=prop.Margin;
  elemSet=prop.layer(prop.layer(:,i)~=0,i);
  flowSet=totalFlow(elemSet);
  offSet=(diff(prop.YLim)-2*prop.Margin-baseLenY/length(elemSet)*((length(elemSet)+(length(elemSet)-1)*prop.Sep)))/2;
  for j=1:length(elemSet)
      tempLenY=baseLenY./sum(flowSet).*flowSet(j);
      
      sankeyHdl.block(prop.layer(j,i))=...
      fill(baseBlockX.*prop.PieceWidth+prop.Margin+(i-1)*baseLenX,...
          baseBlockY.*tempLenY+tempY+offSet,...
          prop.Color(colorIndex,:),'EdgeColor',prop.EdgeColor);
      
      tempY=tempY+tempLenY+baseLenY/length(elemSet)*prop.Sep;
      colorIndex=mod(colorIndex,size(prop.Color,1))+1;
  end
end

%绘制连接
layerList=prop.layer(:);
for i=1:length(nameList)
  for j=i:length(nameList)
      if blockMat(i,j)~=0
          Hdl_L=sankeyHdl.block(i);
          Hdl_R=sankeyHdl.block(j);
          list_L=find(blockMat(i,:)~=0);
          list_R=find(blockMat(:,j)~=0);
          [~,pl,~]=intersect(layerList,list_L(:));
          [~,pr,~]=intersect(layerList,list_R(:));
          list_L=layerList(sort(pl));
          list_R=layerList(sort(pr));
          flow_L=blockMat(i,list_L);
          flow_R=blockMat(list_R,j);
          XData_L=Hdl_L.XData;YData_L=Hdl_L.YData;
          XData_R=Hdl_R.XData;YData_R=Hdl_R.YData;
          xx=[XData_L(1:2);XData_R(1:2)]';
          k_L=find(list_L==j);
          k_R=find(list_R==i);
          yy=[YData_L(1:2)+(YData_L(3:4)-YData_L(1:2))./sum(flow_L).*sum(flow_L(1:k_L-1));
              YData_R(1:2)+(YData_R(3:4)-YData_R(1:2))./sum(flow_R).*sum(flow_R(1:k_R-1))]';
          xxq=XData_L(2):0.01:XData_R(1);
          yyq=interp1(xx,yy,xxq,'pchip');
          tempColor=Hdl_L.FaceColor;
          width=(YData_R(3)-YData_R(1))./sum(flow_R).*flow_R(k_R);
           sankeyHdl.connect(i,k_L)=...
          fill([xxq,xxq(end:-1:1)],[yyq,yyq(end:-1:1)+width],tempColor,'EdgeColor','none','FaceAlpha',0.3);
      end    
  end
end

%绘制文本
for i=1:prop.layerNum
  tempY=prop.Margin;
  elemSet=prop.layer(prop.layer(:,i)~=0,i);
  flowSet=totalFlow(elemSet);
  offSet=(diff(prop.YLim)-2*prop.Margin-baseLenY/length(elemSet)*((length(elemSet)+(length(elemSet)-1)*prop.Sep)))/2;
  for j=1:length(elemSet)
      tempLenY=baseLenY./sum(flowSet).*flowSet(j);
      
      sankeyHdl.txt(prop.layer(j,i))=...
      text(prop.PieceWidth+prop.Margin+(i-1)*baseLenX,tempLenY/2+tempY+offSet,[' ',nameList{elemSet(j)}],...
          'FontSize',prop.FontSize,'Color',prop.FontColor);
      
      tempY=tempY+tempLenY+baseLenY/length(elemSet)*prop.Sep;
  end
end
sankeyHdl.nameList=nameList';
end

 

使用示例代码

List={'零食',300,'食品开销';
    '饮料',150,'食品开销';
    '水果',250,'食品开销';
    '食堂',600,'食品开销';
    '外卖',400,'食品开销';
    '水费',90,'住宿开销';
    '电费',90,'住宿开销';
    '网费',120,'住宿开销';
    '食品开销',1700,'开销';
    '住宿开销',300,'开销'};
axis([0,2,0,1])
sankeyHdl=sankey2([],'XLim',[0,2],'YLim',[0,1],'PieceWidth',0.15,'List',List,'Color',colorList)

sankeyHdl.block(4).FaceColor=[0.8,0.3,0.3];
sankeyHdl.txt(4).FontSize=40;

详解Matlab如何绘制桑基图

试试证明还是方块画细一点显得高级,修饰一下:

详解Matlab如何绘制桑基图

详解Matlab如何绘制桑基图

以上就是详解Matlab如何绘制桑基图的详细内容,更多关于Matlab桑基图的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/slandarer/article/details/118084972

延伸 · 阅读

精彩推荐
  • C/C++C语言字符串旋转问题的深入讲解

    C语言字符串旋转问题的深入讲解

    这篇文章主要给大家介绍了关于C语言字符串旋转问题的相关资料,文中给出了详细的实现方法,并对每种方法进行了分析和示例代码,需要的朋友可以参考下...

    小白多低调3762022-01-10
  • C/C++C语言编程中常见的五种错误及对应解决方案

    C语言编程中常见的五种错误及对应解决方案

    这篇文章主要给大家分享的是C语言编程中常见的五种错误及对应解决方案,详细内容就请跟小编一起进入下面的文章内容吧...

    LCTT unigeorge4422022-01-25
  • C/C++Easyx实现扫雷游戏

    Easyx实现扫雷游戏

    这篇文章主要为大家详细介绍了Easyx实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    shi_xiaobin3862022-08-27
  • C/C++C++生成和解析XML文件的讲解

    C++生成和解析XML文件的讲解

    今天小编就为大家分享一篇关于C++生成和解析XML文件的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    蜗牛20110252021-07-14
  • C/C++C++实现LeetCode(36.验证数独)

    C++实现LeetCode(36.验证数独)

    这篇文章主要介绍了C++实现LeetCode(36.验证数独),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    Grandyang9282021-11-26
  • C/C++VC基于ADO技术访问数据库的方法

    VC基于ADO技术访问数据库的方法

    这篇文章主要介绍了VC基于ADO技术访问数据库的方法,较为详细的分析了VC使用ADO操作数据库的相关实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    weiren20064992021-03-15
  • C/C++C语言音乐播放器实例代码

    C语言音乐播放器实例代码

    文章给大家分享了用C语言音乐播放器的实例代码,对此有需要的朋友参考学习下。...

    lemon1005215632021-06-27
  • C/C++详解C语言之单链表

    详解C语言之单链表

    这篇文章主要为大家介绍了C语言的单链表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助...

    ぃ咔哇依°ヽ11712022-02-25