dlrandy / note-issues

2 stars 0 forks source link

D3 6--7 #56

Open dlrandy opened 6 years ago

dlrandy commented 6 years ago

复杂的数据可视化是由数据类型的编码定义的,而不是数值数据。

层级模式 层级数据是那些影射父亲和孩子关联的数据。

只显示数值模式,可以使用bar chart,line chart, 根据这两种图来作决定是有害的,有时候数据太多显示的图标太大,可以考虑换种别的模式的图标

d3.hierarchy layout是用来格式化数据的,它接收的是一个有层级的js对象,这个对象有一个设置关于孩子节点的访问方式以及分配给节点的数据值。

层级json或者对象指的就是带有values或者children属性的对象,当然根节点没有parent,叶子节点没有children。

dlrandy commented 6 years ago

Pack layout is amenable to 被接受 服从 层级数据为整个layouts接受

circle packing是每一个对象图表示的存放在层级的父亲元素里。

as with 与... 一样 和其他的layout一样,pack layout期待的数据可能和你使用的不一样。pack期待一个js对象数组,它的层级里的孩子元素们存储在children属性里。所以最好是调整accessor函数d3.hierarachy来匹配数据, 虽然有这个访问器函数,但是有时还是需要d3.nest函数的,特别是在外部的数据源的孩子节点是由另一个key指明的。

d3.hierarchy的sum方法里接受的方法会在当前的节点以及后续的节点执行。节点的value属性就是节点执行这个函数返回的值加上所有后代的value属性。这个函数被传递一个节点的data,返回一个非负的数值。 size设置的是layout的大小[width, height],默认是[1,1]

d3的hierarchy的descendants将会包含当前节点的

node的value可以设置pack的size,value主要取决于sum函数的回调函数 什么时候使用circle pack 在比较关注叶子节点的时候

dlrandy commented 6 years ago

SVG 元素的dx,dy指的是元素的位置上或者内容上的偏移 x,y是指用户坐标系统得坐标

d3的zoom是用来drag的

 var treeChart = d3.tree();
      treeChart.size([500, 500]);
      var root = d3.hierarchy(packableTweets, d => d.values);
      var treeData = treeChart(root).descendants();

treeZoom = d3.zoom();
treeZoom.on('zoom', zoomed)
d3.selectAll('svg').call(treeZoom)
function zoomed(){
d3.select('g#treeG').attr('transform', `translate(${d3.event.transform.x}, ${d3,event.transform.y})`)
}

坐标对换就可以旋转位置了

dlrandy commented 6 years ago

对于树的画法,不仅有从上到下,从左到右。因为如果我们把节点的位置邦定到一个角度,就可以以放射的方式绘画。

树的放射式的绘画,会使用size来决定最大的radius,而且从容器 零点开画。

// x y 坐标转换为radial坐标系统
 function project(x, y) {
          var angle = x / 90 * Math.PI;
          var radius = y;
          return [radius * Math.cos(angle), radius * Math.sin(angle)];
  }

d3.cluster和d3.tree的区别在于cluster强迫所有的叶子节点画在同一个级别上

和circle pack相反, 强调叶子节点,树图则是使用了同样的 符号但是是给所有节点。 dendrogram应该用在父子节点是同一类型的而且关注 路径的情况

dlrandy commented 6 years ago

d3.partition layout就是编码数值数据的,是用长度来编码父子节点的关系

在使用hierarchy chart的时候一般需要使用d3.nest和d3.hierarchy 来处理数值数据 。但是 partition使用sum函数来设置每一部分的大小来反映底层数据的值

放射式的partition size的width设置成2PI,height为整个图标的半径。 对于那些从0,0点开始绘画的方法,可以transform他的container,例如g

dlrandy commented 6 years ago

TreeMap他是 circle pack和partition的 组合,使用矩形描述节点,将矩形封闭在父亲节点的矩形里

dlrandy commented 6 years ago

Network 数据描述是多对多的关系 hierarchical数据是值得一个数据有一个父元素及多个子元素的关系

描述Network数据的四种常见形式:纯数据,邻接矩阵,弧线图,力导向的网络图。

邻接矩阵是使用grid来描述节点间的关系的,原则就是沿着x轴放置节点,然后y轴放置同样的节点,如果两个节点之间有联系,就fill对应的grid方格;否则留下空白。fill颜色的深浅可以表明联系的强弱。

D3里是用邻接矩阵的唯一个问题就是没有layout,需要自己手写

dlrandy commented 6 years ago

图形化描述网络的另一种形式就是使用弧线图,它是把nodes排列成一条线在节点的上面或者下面画一个弧线表示联系。

正向forward是顺时针方向

dlrandy commented 6 years ago

力导向布局Forced-directed layout word cloud和Sankey图,使用的是force()layout, 是动态的更新元素的位置来达到最佳的fit。而Directed-layout是实时的持续的各个内心位置而不是渲染前的预处理步骤。他的原理就是三种力的相互作用,这些力会把节点推开又把相关的节点吸引在一起,防止节点飞出视线之外。

力导向布局的三个力是指:吸引力/排斥力,重力和link 吸引力。其他的因素力还有层级packing和社区监测。这些力适合较大的网络改善性能

吸引力/排斥力。他的强度是基于节点的属性的,以致于更大的节点通过设置斥力可以占有更大的空间或者设置斥力更小作为一个卯点:d3.forceManyBody负责charge力;

重力。它是把节点 拉向布局中心防止力的相互作用把节点推出视野。负责的方法有d3.forceX(), d3.forceY(), d3.forceCenter().

link 吸引力。它是把节点拉近。越强越近,d3.forceCenter 负责。

一个力一般包括x, y, charge, collision 初始化一个力使用d3.forceSimulation, 它会计算力的效果以及画网络的起点

注册碰撞力使用d3.forceCollide,也就是.force('collision', d3.forceCollide(d => d.r))

dlrandy commented 6 years ago

forceSimulation里的links是带有link力注册的。forceManyBody的负值意味着节点被推远了,以致于相关的节点连接到相关的节点,创建出熟悉的网络

d3.forceLink()

svg marker

append('defs').append('marker').attr('id','111').append('path')

line.attr('marker-end', 'url(#111)')

dlrandy commented 6 years ago

svg的marker可以静态的定义在html里,也可以动态的定义在svg元素里

一个marker可以在path(line)的start, end, middle,有一些设置可以决定他们相对于父元素的方向 比如attr('marker-end/start/mid')

dlrandy commented 6 years ago

网络的衡量标准 Edge Weight(权重): 每一个link都有一个weight,代表着节点间的联系强度 Centrality(中心化): Network是系统的描述,我们需要知道系统里的那些节点比另一些节点重要。中心化的节点对网络有更重要的影响。中心化的标准有很多 Degree(degree centrality): 就是连接到某一个节点的link的数量。它是节点重要性的大致的衡量。也可以进一步区分in degree,out degree. CLUSTERING 和MODULARITY: 关于network一个重要的事情之一就是任何的community是否在这个网络以及它是一个什么样子的。这需要看特定的某些节点是否比网络里其他的彼此联系的多,这就是modularity。而节点是否相互联系则是clustering。clique小集团则是一组节点完全相互联系的术语。

\

dlrandy commented 6 years ago

更新d3.forceSimulation的时候 首先需要停掉simulation,然后修改force,然后再重启simulation

function sizeByDegree(){
simulation.stop();
simulation.force('charge', d3.forceManyBody().strength(d => -d.degreeCentrality * 20));
simulation.restart();
//设置元素的其他属性
}

Force Layout的设置 Charge: 它设置的是节点间推离或者吸引的比率。默认是-30。负数的charge表示的是斥力(推离);正数的时候表示的是吸引。 Gravity: 通用的gravity已经被x,y替换掉了。当然还有center。 LinkForce: 节点间吸引力是由link force的strength属性决定。d3.forceLink().strength(d => d.weight * .1)如果strength设置的太大的话会导致network翻折。可以把link的strength和edge的weight关联起来来设置距离。

ForceLayout是一种物理的模仿,意味着它使用的物理的隐喻来安排网络的最优的图形形状


   var simulation = d3.forceSimulation()
                .force('charge', d3.forceManyBody().strength(-500))
               // .force('center', d3.forceCenter().x(300).y(300))
//注意上下两者的区别
               .force('x', d3.forceX(250))
               .force('y', d3.forceY(250))
                .force('link', linkForce)
                .nodes(nodes)
                .on('tick', forceTick);

UPdate NetWork(更新网络) 创建network的时候,可能要提供添加或者移出网络的节点功能,或者拖拽功能。你也可能动态的调整不同的设置,而不是在初次创建的时候进行改变。

stop and restart network: force 布局最终停下来的,如果元素不再移向新的节点。也就是stop的。如果想再次看见动画,就需要restart。如果是更新force的设置或者增加移除network的一部分,就需要stop然后restart。

stop() 使用simulation.stop()关闭force交互,会停止运行simulation

restart() 使用simulation.restart(),来开始或者重启layout的动画

tick() 使用simulation.tick(), 移动layout到下一步Force Layout是比较耗费资源的,一般只会运行几秒钟而不是持续运行。如果不想要动画的话,可以预计算表格,例如simulation.tick(120)在排列之前预计算图表,。simulating 一个网络没有动画的情况下,图表渲染得会更快,可以使用D3的transition来动画节点到预计算的位置。

drag() 拖拽节点到新的位置

FIXED 节点的 位置 使用.fx,.fy进行设置。一般用在用户拖拽节点到某一个位置,然后固定起来的情况

dlrandy commented 6 years ago

移除和添加nodes和links 在使用network的时候,可能会过滤network或者添加删除节点。为了能够这么做 需要stop() network,移除不需要到的节点和links,重新邦定这些数组到force layout,然后restart布局

注意csv里的数据都是字符串

手动定位节点 力导向布局不会 移动元素。相反它会基于相关元素的x,y属性计算元素的位置。在每一次的tick中更新x,y属性。 手动移动元素的时候,首先需要停止simulation,防止tick覆盖掉元素的位置。然后更新line的位置,更新节点的x, y属性,还需要更新vx, vy属性。VX VY是上一次tick的velocity。如果不更新他们,force layout 会认为node有较高的velocity,会剧烈的移动到新位置。如果不更新这四个属性,下次启动force layout的时候,节点会立即回到移动前的位置。也就是说光使用transform是不够的,节点的数据也是要改变的

dlrandy commented 6 years ago

force layout相当耗费资源。这也是为什么设计上就是要它 慢慢的凉下来停止运行。

优化的第一个建议就是限制节点和边的数量。 一般节点不多于500,这个界限过去是100,但是随着浏览器性能的增加,可以变得越来越高,所以使用profiling来理解客户将要使用的浏览器的最小性能。

如果节点数量多于500,可以使用forceManyBody.chargeDistance()来设置一个最大的距离在noeds计算charge的时候。这个设置越小,force layout就越不结构化,但是运行的越快。

因为network的不同,必须测试chargeDistance不同的值来找到最合适的值。