将平面 json 对象转换为分层 d3 对象结构
transform flat json object to hierarchical d3 object structure
我想将 json 数据如 packageJson
转换为适合树形图的分层格式
使用d3.hierarchy
转换对象
据我了解
每个 属性 包含嵌套数据
需要使用 like
内部的辅助函数进行转换
const test = d3.hierarchy(packageJson, d => d.scripts);
是通过查找每个具有嵌套对象的 属性 来转换 packageJson
的唯一方法
或者是我不知道的任何 d3 辅助函数来完成这种任务?
const fam = d3.hierarchy({
name: "root",
children: [
{name: "child #1"},
{
name: "child #2",
children: [
{name: "grandchild #1"},
{name: "grandchild #2"},
{name: "grandchild #3"}
]
}
]
})
// transform json
const packageJson = {
"name": "visualize-data",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"d3-color": "^3.0.1",
"d3-hierarchy": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-shape": "^3.0.1",
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
const test = d3.hierarchy(packageJson, d => d.scripts);
console.log(test)
#limit {
max-width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="limit">
</div>
最简单的方法是创建一个包含所有子属性的数组作为 d3.hierarchy:
使用的子数组
let root = d3.hierarchy(packageJson, function(d) {
if(typeof d == "object")
return Object.keys(d).map(k=>{ return d[k]; });
})
我们需要检查 属性 是否是对象(/数组)而不是文本,否则我们将提取标记叶节点的字符串的键。
这不是最令人满意的结果:没有节点有名称。我们可以通过根据父节点给它们的 属性 名称给节点命名来解决这个问题(根仍然是无名的,但这很容易纠正):
let root = d3.hierarchy(packageJson, function(d) {
if(typeof d == "object")
return Object.keys(d).filter(d=>d!="$name").map(k=>{
if(typeof d[k] == "object") d[k].$name = k;
else d[k] = k + " : " + d[k];
return d[k];
});
})
$name 属性 跟踪非叶节点的名称(因为这些是我们可以添加 属性 的对象),它被子数组生成器过滤掉。由于叶节点是字符串,我只是修改它们以反映 属性 名称和值:它们的值位于 d.data 而非叶节点的名称位于 d.data .$名字.
根据您想要的结果,您可能喜欢也可能不喜欢上述方法。但为了演示,如下所示:
这是一个演示:
const packageJson = {
"name": "visualize-data",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"d3-color": "^3.0.1",
"d3-hierarchy": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-shape": "^3.0.1",
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
let root = d3.hierarchy(packageJson, function(d) {
if(typeof d == "object")
return Object.keys(d).filter(d=>d!="$name").map(k=>{
if(typeof d[k] == "object") d[k].$name = k;
else d[k] = k + " : " + d[k];
return d[k];
});
})
var width = 600;
var height = 300;
margin = {left: 10, top: 10, right: 50, bottom: 50}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');
var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.text(function(d) { return d.data.$name || d.data; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
我想将 json 数据如 packageJson
转换为适合树形图的分层格式
使用d3.hierarchy
转换对象
据我了解
每个 属性 包含嵌套数据
需要使用 like
const test = d3.hierarchy(packageJson, d => d.scripts);
是通过查找每个具有嵌套对象的 属性 来转换 packageJson
的唯一方法
或者是我不知道的任何 d3 辅助函数来完成这种任务?
const fam = d3.hierarchy({
name: "root",
children: [
{name: "child #1"},
{
name: "child #2",
children: [
{name: "grandchild #1"},
{name: "grandchild #2"},
{name: "grandchild #3"}
]
}
]
})
// transform json
const packageJson = {
"name": "visualize-data",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"d3-color": "^3.0.1",
"d3-hierarchy": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-shape": "^3.0.1",
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
const test = d3.hierarchy(packageJson, d => d.scripts);
console.log(test)
#limit {
max-width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="limit">
</div>
最简单的方法是创建一个包含所有子属性的数组作为 d3.hierarchy:
使用的子数组let root = d3.hierarchy(packageJson, function(d) {
if(typeof d == "object")
return Object.keys(d).map(k=>{ return d[k]; });
})
我们需要检查 属性 是否是对象(/数组)而不是文本,否则我们将提取标记叶节点的字符串的键。
这不是最令人满意的结果:没有节点有名称。我们可以通过根据父节点给它们的 属性 名称给节点命名来解决这个问题(根仍然是无名的,但这很容易纠正):
let root = d3.hierarchy(packageJson, function(d) {
if(typeof d == "object")
return Object.keys(d).filter(d=>d!="$name").map(k=>{
if(typeof d[k] == "object") d[k].$name = k;
else d[k] = k + " : " + d[k];
return d[k];
});
})
$name 属性 跟踪非叶节点的名称(因为这些是我们可以添加 属性 的对象),它被子数组生成器过滤掉。由于叶节点是字符串,我只是修改它们以反映 属性 名称和值:它们的值位于 d.data 而非叶节点的名称位于 d.data .$名字.
根据您想要的结果,您可能喜欢也可能不喜欢上述方法。但为了演示,如下所示:
这是一个演示:
const packageJson = {
"name": "visualize-data",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"d3-color": "^3.0.1",
"d3-hierarchy": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-shape": "^3.0.1",
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
let root = d3.hierarchy(packageJson, function(d) {
if(typeof d == "object")
return Object.keys(d).filter(d=>d!="$name").map(k=>{
if(typeof d[k] == "object") d[k].$name = k;
else d[k] = k + " : " + d[k];
return d[k];
});
})
var width = 600;
var height = 300;
margin = {left: 10, top: 10, right: 50, bottom: 50}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');
var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.text(function(d) { return d.data.$name || d.data; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>