桑基图(sankey)的绘制

在线绘图|2分钟轻松搞定桑基图(Sankey diagrams) 桑基图(Sankey diagrams) 桑基图(Sankey diagrams),即桑基能量分流图,也叫桑基能量平衡图。用来展示数据的“流动”变化,分支的宽度表示流量的大小,应用于能源流向、收入支出、人员流动等数据的可视化。桑基图主要由边、流量和支点组成,其中边代表了流动的数据,流量代表了流动数据的具体数值,节点代表了不同分类。边的宽度与流量成比例的显示,边越宽,数值越大。 如何在线绘制桑基图(或物种分类关系图)? 小编和他的小伙伴们开发了一个在线的作图小网站——云图图(www.cloudtutu.co 阅读详情
转载自:http://blog.youkuaiyun.com/tianxuzhang/article/details/49624701

  • 注:本文未经作者允许严禁转载和演绎

1 什么是桑基图?

桑基图是流图 (flow diagram )的一种,用来描述能量,人口,经济等的流动情况。最早由爱尔兰人Matthew Henry Phineas Riall Sankey 提出。Sankey是一名船长也是工程师,1898年Sankey在土木工程师学会会报纪要的一篇关于蒸汽机能源效率的文章中首次推出了第一个能量流动图,后来被命名为Sankey图,中文音译为桑基图。

桑基图主要关注能量、物料或资本等在系统内部的流动和转移情况。起始流量和结束流量相同;在内部,不同的线条代表了不同的流量分流情况,它的宽度成比例地显示此分支占有的流量;节点不同的宽度代表了特定状态下的流量大小。

2 用D3绘制简单的Sankey图

D3提供一个Sankey插件,可以用来根据输入的节点-连接数据转换为桑基图布局所用的中间数据。这些中间数据可以很方便地结合SVG的矩形元素(rect)绘制节点,结合路径元素(path)就可以绘制链接。使得用D3绘制Sankey图很方便。图1展示了绘制效果。




 

图1 绘制简单的桑基图 

下面我们来详细介绍如果实现sankey图的绘制:

首先,绘制sankey图需要引入D3库以及Sankey插件库:

<code class="language-html hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"../d3.js"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">charset</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"utf-8"</span>></span><span class="javascript" style="box-sizing: border-box;"><<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/script >
<script src="../</span>sankey.js<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"></span></span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
然后,我们需要准备sankey图所需要的数据,这些数据按照一定的格式描述了网络中的节点-链接关系:
<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 节点和连接数据</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> data = {
  <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'nodes'</span>: [
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"0"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"1"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"2"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"3"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"4"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"5"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"6"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"7"</span>},
    {name: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"8"</span>}
  ],
  <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'links'</span>: [
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>},
    {source: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>, target: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>, value: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>}
  ]
};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>

这里的数据定义为JavaScript脚本中的变量,当然也可以由其他形式的数据转换,例如加载JSON数据文件等。但转换后的最终形式必须如上所示,即含有一个节点数组和一个一个链接数组。节点数组中每个元素是一个对象,含有一个name属性表示节点的名称;链接数组中每个对象都含有source、target和value三个属性,分别代表了来源节点的索引(从0开始),目标节点的索引,以及流量。 
接下来,我们可以配置sankey布局的属性值:

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 定义桑基布局</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> sankey = d3.sankey()
        .nodeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">80</span>) 
        .nodePadding(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">40</span>) 
        .size([width, height]) 
        .nodes(data.nodes)  
        .links(data.links)
        .layout(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

其中各个函数的解释如下:

  • nodeWidth表示节点水平宽度,这个属性可以用来设置矩形的宽度等;
  • nodePadding表示矩形的垂直方向的间距;
  • size表示整个sankey图占用的空间大小;
  • nodes加载如上所述的节点数组;
  • 同理links函数加载链接数组;
  • layout中的参数表示桑基布局用来优化流布局的时间。

定义完了sankey布局之后最重要的就可以得到一个链接路径生成器:

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 路径数据生成器</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> path = sankey.link();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
 

图2 由sankey布局转换后的节点和连接数据 

最后,就可以绑定数据绘制矩形节点和路径了:

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制连接数据</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> links = svg.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"g"</span>).selectAll(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"path"</span>)
            .data(data.links)
            .enter()

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绑定节点数据</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> nodes = svg.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"g"</span>).selectAll(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".node"</span>)
                .data(data.nodes)
                .enter();

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制连接线</span>
links.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"path"</span>)
    .attr({
    fill: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"none"</span>,   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//填充色</span>
            stroke: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d,i)</span>{</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> color(i); },  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//描边色</span>
        <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"stroke-opacity"</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>,  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//描边透明度</span>
          d: path,  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//路径数据</span>
          id: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d,i)</span>{</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'link'</span> +i }  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//ID</span>
     })
     .style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"stroke-width"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span>  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//连线的宽度</span>
          <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Math</span>.max(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, d.dy);
     });

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制圆形节点   </span>
nodes.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"circle"</span>)
    .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"transform"</span>,<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span>
          <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"translate("</span> + d.x + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">","</span> + d.y + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">")"</span>;
       })
        .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"r"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dy / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; })
        .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cx"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dx/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; })
        .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cy"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dy / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; })
        .style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"fill"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"tomato"</span>)
        .style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"stroke"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"gray"</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>

3 添加文字

为了方便理解sankey图的流量的流动情况,我们还可以为节点和链接添加文字提示, 
给节点添加文字很简单,直接给之前绑定了数据并添加了占位符的nodes对象添加text元素并设置文本内容和坐标即可:

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制节点文本</span>
  nodes.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"text"</span>)
        .attr({
            x: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.x+sankey.nodeWidth() / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; },
            y: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.y+d.dy / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; }
        })
        .text(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.name; }); </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

给链接添加文本稍微复杂一点,需要给text元素再添加textPath子元素,并用xlink:href属性和对应的链接路径关联起来,用startOffset属性可以设置文字相对于链接路径的位置,例如这里的50%表示居中显示。

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制连接文本</span>
  links.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'text'</span>)
        .append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'textPath'</span>)
        .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'xlink:href'</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d,i)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'#link'</span> + i; })
        .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'startOffset'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'50%'</span>)
        .text(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'流量:'</span> + d.value; })</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

添加完文字之后可以清晰地展现流量变化情况,如图3所示:




 

图3 为sankey图添加文字提示 

4 圆形节点

当然,也可以将sankey图中的矩形换成圆形。关键是在定义sankey布局的时候指定的节点宽度不能太大,例如本例指定为1像素:

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">.nodeWidth(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

然后,可以把圆平移到sankey布局计算得到的节点坐标处,并用节点的偏移量指定圆的圆心坐标和半径。

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制圆形节点   </span>
nodes.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"circle"</span>)
      .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"transform"</span>,<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"translate("</span> + d.x + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">","</span> + d.y + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">")"</span>;
      })
      .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"r"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dy / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; })
      .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cx"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dx / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; })
      .attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cy"</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dy / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; })
      .style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"fill"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"tomato"</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

还需要相应地调整下显示的尺寸,最后绘制效果如图4所示:




 

图4 绘制圆形节点的sankey图 

5 添加交互效果

有时候为了增加sankey图的易用性,可能需要给节点和连接线添加一些交互效果。下面介绍给连接线添加鼠标悬停事件,以及给节点添加拖动事件。

用CSS控制悬浮样式,让连接线在鼠标悬停的时候高亮显示:

<code class="language-HTML hljs xml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">style</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">type</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"text/css"</span>></span><span class="css" style="box-sizing: border-box;">
    <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">path</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:hover</span><span class="hljs-rules" style="box-sizing: border-box;">{
        <span class="hljs-rule" style="box-sizing: border-box;"><span class="hljs-attribute" style="box-sizing: border-box;">stroke-opacity</span>:<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 102, 102);"> <span class="hljs-number" style="box-sizing: border-box;">0.9</span></span></span>;
    <span class="hljs-rule" style="box-sizing: border-box;">}</span></span>
</span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">style</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

效果如图5所示: 




 

图5 连接线在鼠标悬停时高亮显示 




绘制节点时给节点添加拖动行为,并绑定拖动事件监听器。

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绘制矩形节点   </span>
nodes.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"rect"</span>)
          .attr({
                x: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.x; },
                y: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.y; },
                height: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d.dy; },
                width: sankey.nodeWidth(),
                fill: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"tomato"</span>
          })
          .call(d3.behavior.drag()
                    .origin(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d; })
                    .on(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"drag"</span>, dragmove)
);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

这里的.origin(function(d) { return d; })是为了防止拖动时出现跳动,相应的拖动事件监听器为:

<code class="language-javascript hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 拖动事件响应函数</span>
<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">dragmove</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(d)</span> {</span>
     d3.select(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>).attr({
        <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"x"</span>: (d.x = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Math</span>.max(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Math</span>.min(width - d.dx, d3.event.x))),
        <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"y"</span>: (d.y = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Math</span>.max(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Math</span>.min(height - d.dy, d3.event.y)))
     });

     sankey.relayout();
     paths.attr(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'d'</span>,path);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

也就是在拖动过程中重新计算矩形的坐标位置,并重新启动桑基布局,之后给路径元素绑定新的路径数据。这里拖动时文本如何移动就留给读者作为练习题,最后效果如图6所示: 




 

图6 可拖动的sankey图 

好了!桑基图就介绍到这了,感谢关注!

D3 二维图表的绘制系列(二十二)桑基图sankey 上一篇: 仪表盘图 https://blog.youkuaiyun.com/zjw_python/article/details/98492510 下一篇: 旭日图 https://blog.youkuaiyun.com/zjw_python/article/details/98201470 代码结构和初始化画布的Chart对象介绍,请先看 https://blog.youkuaiyun.com/zjw_python/article... 阅读详情

相关推荐

python绘制桑基图(sankey diagram)

## 背景 最近因为工作需要,需要画一些漏斗图、成交路径的图之类的,然后我就想到了桑基图(sankey diagram)。这个图现在绘制很简单,可以有以下几个方法: 1. 使用R语言画,比如R语言的networkD3、plotly包,可以画非常漂亮的sankey diagram图,使用起来也很方便,但是我不想用,因为我不想从python到R相互转化,变量之间的传递太麻烦了,虽然现在的jupyter notebook可以配置,让R和python共享变量。但是我个人感觉不够优雅。 参考链接有:[https:

yuanzhoulvpi的博客 1万+

【D3.js数据可视化实战】--(3)桑基图(sankey)的绘制

桑基图是流图(flow diagram)的一种,用来描述能量,人口,经济等的流动情况。 桑基图主要关注能量、物料或资本等在系统内部的流动和转移情况。起始流量和结束流量相同;在内部,不同的线条代表了不同的流量分流情况,它的宽度成比例地显示此分支占有的流量;节点不同的宽度代表了特定状态下的流量大小。

司机大傻 4万+

python pyecharts绘制桑基图(Sankey )

桑基图(Sankey diagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,图中延伸的分支的宽度对应数据流量的大小,通常应用于能源、材料成分、金融等数据的可视化分析。因1898年Matthew Henry Phineas Riall Sankey绘制的“蒸汽机的能源效率图”而闻名,此后便以其名字命名为“桑基图” 利用python的pyecharts绘制桑基图 1.node(所有节点) #形如 {'name': ' '} 2.link #形如 {'so...

hufei_neo的博客 9747

桑基图绘制的简易操作

简单桑基图绘制

weixin_41340728的博客 1万+

python pyecharts绘制桑基图Sankey

文章目录sankey_base sankey_base from pyecharts import options as opts from pyecharts.charts import Sankey nodes = [ {"name": "category1"}, {"name": "category2"}, {"name": "category3"}, {"name": "category4"}, {"name": "category5"}, {"na

Cachel Wood的博客 1931

d3-sankey-circular:d3-sankey库的一个fork,以允许循环链接

d3-sankey-circular d3-sankey库( )的分支,以允许循环链接(,循环图,如)。 该库包含来自Colin Fergus的bl.ock 的一部分代码,用于检测循环链接。 安装 如果使用NPM,则npm install d3-sankey-circular 。 否则,请使用已文件夹中的d3-sankey-circular.js文件。 用法 var sankey = d3.sankeyCircular(); API参考 该API遵循原始的d3-sankey库,并带有其他选项以允许布置和绘制圆形链接。 d3。 sankeyCircular () 使用默认设置构造一个新的Sankey生成器。 桑基(参数...) 计算给定参数的节点和链接位置,返回代表Sankey布局的图形。 返回的图具有以下属性: 图.nodes-数组 graph .links-数组

实现绘制Sankey桑基图(河流图、分流图)流程数据可视化

原文链接:http://tecdat.cn/?p=24996我一直在寻找一种直观的方法来绘制流程中状态之间的流程或连接。R软件恰好满足了我的需求。将数据设置为正确的格式是一个比较麻烦的过程。现在,本文仅说明如何构建多级图。构造数据此示例的计划是在六层中的每一层具有四个节点,并且层之间具有流。数据很好地说明了该过程,并且产生的结果与我所追求的最终图一致。我们必须为节点和边创建数据结构。从边开始,然...

拓端研究室TRL 641

d3.v4-sanKey.js

d3.v4-sanKey布局,非原创

python Dat Vis: Plotly绘制sankey diagram桑基图

点赞发Nature 关注中Science sankey图一般用于描绘agent间的物质、能量流动,在综合评估模型IAM、投入产出模型IO相关的论文中比较常见。以下是一个使用plotly程序包绘制能量流动的代码 import os import pandas as pd import plotly.express as px import plotly.graph_objects as go color_node_prod = px.colors.sequential.YlGn # define the c

Cmmmmm丶的博客 1292

sankey:D3带自循环的Sankey图生成器

用HTML5,CSS3和D3.js编写 可以在画布上自由移动节点 可以调整链接的不透明度和节点间距 自动调整为屏幕大小 适用于所有设备并呈现相同的效果 JSON / PNG格式的加载/保存功能 应用程序 尝试: : 文献资料 信用 丹尼斯·卡拉(DénesCsala),2014年

[学习笔记]Esp32 + 4G模块,随身wifi,ppp拨号上网

Esp32S3 + 4G模块制作随身WIFI教程

weixin_45595548的博客 7412

SAS软件绘制桑基图sankey

使用SAS软件绘制桑基图sankey

xinzaijiafang的博客 704

超详细YOLOv8实例分割全程概述:环境、训练、验证与预测详解

这篇博客提供了一个全面的指南,介绍了如何使用 Ultralytics YOLOv8-seg 系列模型进行对象检测和分割任务。内容从环境搭建、模型选择、训练、验证到预测的完整流程都有详细说明。为想要使用 YOLOv8-seg 系列模型的开发者提供了一站式的解决方案。它不仅涵盖了从环境配置到模型部署的详细步骤,还解释了如何解读和使用模型输出,使得用户能够根据自己的需求选择合适的模型,并能够有效地训练和评估它们。

CDBmax的博客 6万+

python 桑基图 地理坐标_python可视化动态图表: 关于pyecharts的sankey桑基图绘制

#数据架构 总领数据架构-品牌-车辆用途-importmatplotlib.pyplot as pltfrom pyecharts importPie,Bar,Page,Bar3D,Overlap,Line,Boxplot,Surface3D,Sankey,EffectScatterimportpandas as pdimportnumpy as npdf=pd.read_excel(r'C:\U...

weixin_39996750的博客 404

天池长期赛:二手车价格预测(422方案分享)

本次比赛是一次很好的锻炼数据挖掘能力的入门赛,从EDA-数据清洗-特征工程-模型调参-模型融合,能够完整的学习到大数据的分析和挖掘,值得历练。

weixin_46685991的博客 1万+

五、2K0300 久久派开发板的GPIO控制与Shell脚本自动化实战

本文详细介绍了基于龙芯2K0300处理器的久久派开发板的GPIO控制方法,通过sysfs文件系统实现LED控制和传感器读取。重点讲解了Shell脚本自动化实战,包括LED闪烁、流水灯效果和传感器数据采集,为物联网项目开发提供完整解决方案。

silver的专栏 686

基于Highcharts平台的桑基图(Sankey diagram)绘制

1.介绍①桑基图(Sankeydiagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,右图中延伸的分支的宽度对应数据流量的大小,通常应用于、材料成分、等数据的可视化分析。因1898年MatthewHenryPhineasRiallSankey绘制的“的效率图”而闻名,此后便以其名字命名为“桑基图”。(据百度百科)②桑基图特征始末端的分支宽度总和相等,也是桑基图的一大鲜明特色。③制作平台及工具Excel,RAWGraphs,Echarts,Tableau等。......

m0_57340659的博客 1510

CVAT自动标注避坑指南:从nuctl安装到YOLOv5模型部署的完整流程

本文详细介绍了在CVAT中部署YOLOv5自动标注功能的完整流程与避坑指南。重点解决了从nuctl工具安装、项目创建时因网络问题导致的镜像拉取失败,到最终模型函数部署与CVAT集成的关键步骤。针对国内网络环境,提供了实用的镜像替换方案,帮助用户顺利完成基于CPU的自动化标注环境搭建。

pytorch8learner的博客 229

Python绘制桑基图Sankey,Pyecharts不显示html页面,桑基图只显示标题,原因总结

Python绘制桑基图Sankey,Pyecharts不显示html页面,桑基图只显示标题,原因总结 说说使用上的三点注意: 1.nodes中的"name"不要重新命名,否则会不识别,导致没有图 2.links中source和target对应的值一定要在nodes的name对应的值中,否则图中会不显示(但是不会报错) 3.links中source和target对应的值不能相同,否则图不显示 主要参考: 桑基图官方文档 # official from pyecharts import options as o

你好啊靓仔 6773

Debian Buster 软件源失效问题

摘要:基于Debian Buster的ARM64设备因系统版本结束支持(EOL)导致apt update报错404。解决方案包括:1)改用Debian官方存档源(需禁用安全检查);2)升级至受支持的Debian 11/12版本(推荐);3)临时使用第三方镜像源(不推荐)。操作步骤涉及修改sources.list、处理NTP同步问题及清理残留配置。建议优先采用版本升级方案以获得持续安全更新,避免使用过时系统带来的安全隐患。文中提供了完整命令示例和操作记录供参考。

yy_xzz的博客 2179

DeepSeek网页版和DeepSeek Harness

DeepSeek网页版是开箱即用的对话工具,适合快速问答与日常任务;而DeepSeekHarness(dsh)是基于Node.js的开源智能体框架,支持文件操作、命令执行、多工具协同,实现“对话即执行”。二者定位不同:网页版为“大脑”,Harness为“躯体”。前者封闭易用,后者开放可扩展,具备可追溯的执行日志与插件化架构。未来,网页版将聚焦轻量化普及,Harness则致力于构建生态平台。对开发者而言,应将AI作为执行层,守住决策层,深耕垂直领域,并掌握AI工作流设计能力,以构建不可替代的技术优势。

几十年资深高级架构师,技术专家的技术笔记。专注C、Java、Python、微服务、云原生、AI工程化及高并发系统分布式架构实战,分享源码剖析、性能调优与架构治理经验。 866

Stata绘图:绘制桑基图-sankey_plot

全文阅读:Stata绘图:绘制桑基图-sankey_plot| 连享会主页 目录 1. 什么是桑基图 2. sankey_plot 命令介绍 3. 实例演示 3.1 大陆间移民 3.2 就业市场流动 3.3 宠物、婚姻和幸福 4. 相关推文     1. 什么是桑基图 根据百度百科的定义,桑基图 (Sankey diagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,图中延伸的分支的宽度对应数据流量的大小,通常应用于能源、材料成分、金融等数据的

Stata连享会 1049

X书关键词协议搜索

【代码】X书关键词协议搜索。

Codeooo 博客 6377

Python pyecharts Sankey 多节点桑基图绘制

【代码】python pyecharts 多节点桑基图

xcxcxc_的博客 1909

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

MATLAB | 如何使用MATLAB绘制高度自定义的桑基图(sankey)

~

slandarer的博客 6250

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

上一篇: java8新的时间日期库及使用示例
下一篇: 程序员必须知道的十大基础实用算法及其讲解
Tracyclock
博客等级 码龄10年 14粉丝 41原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值