iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
1
AI & Data

D3.js資料視覺化的浪漫突進系列 第 21

Day21 D3js d3.tree 樹狀資料結構視覺化

  • 分享至 

  • xImage
  •  

d3.tree 樹狀資料結構視覺化

用途

建立一個網路拓撲的結構圖,可視覺化呈現階層分類的資料。

d3.tree

範例:

const tree = data => {
  const root = d3.hierarchy(data);
  root.dx = 10;
  root.dy = 200;
  return d3.tree().nodeSize([root.dx, root.dy])(root);
}
const root = tree(data);

d3.hierarchy(data)就是之前提到過,d3會協助遍歷結構型的資料,可產出相關深度等等資料。

root.dx = 10;
root.dy = 200;

dx如果設定為100,每一個資料水平階層會相當的寬。

dy如果設定為20,每一個資料垂直階層會相當的窄。

以上就是針對圖階層的長度寬度。

descendants

範例

const node = g.append("g")
  .attr("stroke-linejoin", "round")
  .attr("stroke-width", 3)
.selectAll("g")
.data(root.descendants())
.join("g")
.attr("transform", d => `translate(${d.y},${d.x})`)

root.descendants可協助將資料轉成具有x, y定位的拓撲圖,這時候其實已經完成八成,因為位置已經有了,只差繪製。

完整範例

下半部開始閱讀。

範例:

console.clear();
const width = 800;
const height = 600;

const treeData = {
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "value": 3938},
      {"name": "CommunityStructure", "value": 3812},
      {"name": "HierarchicalCluster", "value": 6714},
      {"name": "MergeEdge", "value": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "value": 3534},
      {"name": "LinkDistance", "value": 5731},
      {"name": "MaxFlowMinCut", "value": 7840},
      {"name": "ShortestPaths", "value": 5914},
      {"name": "SpanningTree", "value": 3416}
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker", "value": 7074}
     ]
    }
   ]
  },
  {
   "name": "animate",
   "children": [
    {"name": "Easing", "value": 17010},
    {"name": "FunctionSequence", "value": 5842},
    {
     "name": "interpolate",
     "children": [
      {"name": "ArrayInterpolator", "value": 1983},
      {"name": "ColorInterpolator", "value": 2047},
      {"name": "DateInterpolator", "value": 1375},
      {"name": "Interpolator", "value": 8746},
      {"name": "MatrixInterpolator", "value": 2202},
      {"name": "NumberInterpolator", "value": 1382},
      {"name": "ObjectInterpolator", "value": 1629},
      {"name": "PointInterpolator", "value": 1675},
      {"name": "RectangleInterpolator", "value": 2042}
     ]
    },
    {"name": "ISchedulable", "value": 1041},
    {"name": "Parallel", "value": 5176},
    {"name": "Pause", "value": 449},
    {"name": "Scheduler", "value": 5593},
    {"name": "Sequence", "value": 5534},
    {"name": "Transition", "value": 9201},
    {"name": "Transitioner", "value": 19975},
    {"name": "TransitionEvent", "value": 1116},
    {"name": "Tween", "value": 6006}
   ]
  },
  {
   "name": "data",
   "children": [
    {
     "name": "converters",
     "children": [
      {"name": "Converters", "value": 721},
      {"name": "DelimitedTextConverter", "value": 4294},
      {"name": "GraphMLConverter", "value": 9800},
      {"name": "IDataConverter", "value": 1314},
      {"name": "JSONConverter", "value": 2220}
     ]
    },
    {"name": "DataField", "value": 1759},
    {"name": "DataSchema", "value": 2165},
    {"name": "DataSet", "value": 586},
    {"name": "DataSource", "value": 3331},
    {"name": "DataTable", "value": 772},
    {"name": "DataUtil", "value": 3322}
   ]
  },
  {
   "name": "display",
   "children": [
    {"name": "DirtySprite", "value": 8833},
    {"name": "LineSprite", "value": 1732},
    {"name": "RectSprite", "value": 3623},
    {"name": "TextSprite", "value": 10066}
   ]
  },
  {
   "name": "flex",
   "children": [
    {"name": "FlareVis", "value": 4116}
   ]
  }
 ]
}

// 此部分才是重點
const tree = data => {
  const root = d3.hierarchy(data);
  root.dx = 10;
  root.dy = 20;
  return d3.tree().nodeSize([root.dx, root.dy])(root);
}
// 將資料轉為tree的格式
const root = tree(treeData);

const svg = d3.select('svg').attr('width', width).attr('height', height);

const g = svg.append("g")
      .attr("font-family", "sans-serif")
      .attr("font-size", 10)
      .attr("transform", `translate(50, 250)`);

// link是點跟點連線的灰色線條
const link = g.append("g")
    .attr("fill", "none")
    .attr("stroke", "#555")
    .attr("stroke-opacity", 0.4)
    .attr("stroke-width", 1.5)
  .selectAll("path")
    .data(root.links())
    .join("path")
      .attr("d", d3.linkHorizontal()
          .x(d => d.y)
          .y(d => d.x));
           
 // 這部分是畫上圓圈的部分,透過`descendants`推測出目前資料的`x, y`位置。
 const node = g.append("g")
      .attr("stroke-linejoin", "round")
      .attr("stroke-width", 3)
    .selectAll("g")
    .data(root.descendants())
    .join("g")
 .attr("transform", d => `translate(${d.y},${d.x})`)
 .each(data => console.log('data', data))

  node.append("circle")
      .attr("fill", d => d.children ? "#555" : "#999")
      .attr("r", 2.5);

  node.append("text")
      .attr("dy", "0.31em")
      .attr("x", d => d.children ? -6 : 6)
      .attr("text-anchor", d => d.children ? "end" : "start")
      .text(d => d.data.name)
    .clone(true).lower()
      .attr("stroke", "white");

結論

這種圖目前我還沒有實際使用上,但可能對大量資料蒐集分析需要快速縱觀全局的時候,可能可以派得上用場。

Codepen範例

參考

d3-hierarchy


上一篇
Day20 d3.force密集恐懼症的引力圓圈圖
下一篇
Day22 D3js d3與canvas
系列文
D3.js資料視覺化的浪漫突進30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言