d3.js:链接相关项目

标签 d3.js relationship

我正在尝试使用 d3.js 创建一个图表,显示项目之间的关系或链接。

基本思想是这样的:
enter image description here

当我悬停或单击其中一个项目时,相关项目会突出显示

我看过 d3.layout.tree https://github.com/mbostock/d3/wiki/Tree-Layout但这似乎与我想做的不同。

我看到了这个 fiddle :http://jsfiddle.net/bmdhacks/qsEbd/5/
这似乎是朝着正确方向的开始

基于那个 fiddle ,我用我自己的数据集构建了这个 fiddle
http://jsfiddle.net/Ps4Fe/1/
起初看起来它会起作用。但后来我意识到我的圆圈覆盖在其他圆圈上,并且有多个副本……我明白为什么了。

我构建数据的方式可能有问题。那是可以改变的。

    var data = {
    "Product": [
        {
            "type": "product",
            "name": "Product 1",
            "links": [
                {
                    "name": "Industry 1",
                    "type": "industry",
                    "percent": 0.12,
                    "count": 149
                },
                {
                    "name": "Industry 2",
                    "type": "industry",
                    "percent": 0.18,
                    "count": 180
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.17,
                    "count": 152
                },
                {
                    "name": "Industry 4",
                    "type": "industry",
                    "percent": 0.16,
                    "count": 175
                },
                {
                    "name": "Industry 5",
                    "type": "industry",
                    "percent": 0.25,
                    "count": 21
                },
                {
                    "name": "Size A",
                    "type": "size",
                    "percent": 0.24,
                    "count": 21
                },
                {
                    "name": "Size B",
                    "type": "size",
                    "percent": 0.15,
                    "count": 49
                },
                {
                    "name": "Size C",
                    "type": "size",
                    "percent": 0.15,
                    "count": 83
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.17,
                    "count": 128
                },
                {
                    "name": "Size E",
                    "type": "size",
                    "percent": 0.13,
                    "count": 241
                },
                {
                    "name": "Size F",
                    "type": "size",
                    "percent": 0.08,
                    "count": 161
                }            ]
        },
        {
            "type": "product",
            "name": "Product 2",
            "links": [
                {
                    "name": "Industry 1",
                    "type": "industry",
                    "percent": 0.06,
                    "count": 15
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.21,
                    "count": 52
                },
                {
                    "name": "Industry 5",
                    "type": "industry",
                    "percent": 0.15,
                    "count": 39
                },
                {
                    "name": "Size C",
                    "type": "size",
                    "percent": 0.28,
                    "count": 78
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.13,
                    "count": 73
                }
            ]
        },
        {
            "type": "product",
            "name": "Product 3",
            "links": [
                {
                    "name": "Industry 4",
                    "type": "industry",
                    "percent": 0.18,
                    "count": 15
                },
                {
                    "name": "Industry 5",
                    "type": "industry",
                    "percent": 0.19,
                    "count": 52
                },
                {
                    "name": "Size A",
                    "type": "size",
                    "percent": 0.15,
                    "count": 3
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.18,
                    "count": 55
                },
                {
                    "name": "Size E",
                    "type": "size",
                    "percent": 0.14,
                    "count": 47
                },
                {
                    "name": "Size F",
                    "type": "size",
                    "percent": 0.13,
                    "count": 24
                }
            ]
        },
        {
            "type": "product",
            "name": "Product 4",
            "links": [
                {
                    "name": "Industry 2",
                    "type": "industry",
                    "percent": 0.1,
                    "count": null
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.01,
                    "count": null
                },
                {
                    "name": "Size A",
                    "type": "size",
                    "percent": 0.21,
                    "count": null
                },
                {
                    "name": "Size B",
                    "type": "size",
                    "percent": 0.11,
                    "count": null
                },
                {
                    "name": "Size C",
                    "type": "size",
                    "percent": 0.18,
                    "count": null
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.14,
                    "count": null
                }            
            ]
        },
        {
            "type": "product",
            "name": "Product 5",
            "links": [
                {
                    "name": "Industry 1",
                    "type": "industry",
                    "percent": 0.1,
                    "count": null
                },
                {
                    "name": "Industry 2",
                    "type": "industry",
                    "percent": 0.15,
                    "count": null
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.03,
                    "count": null
                },
                {
                    "name": "Industry 4",
                    "type": "industry",
                    "percent": 0.08,
                    "count": null
                },
                {
                    "name": "Size 2",
                    "type": "size",
                    "percent": 0.08,
                    "count": null
                },
                {
                    "name": "Size 3",
                    "type": "size",
                    "percent": 0.18,
                    "count": null
                },
                {
                    "name": "Size 5",
                    "type": "size",
                    "percent": 0.25,
                    "count": null
                }
            ]
        }
    ],
    "Industry": [
        {
            "type": "industry",
            "name": "Agriculture, Forestry & Fishery"
        },
        {
            "type": "industry",
            "name": "Arts & Entertainment"
        },
        {
            "type": "industry",
            "name": "Construction"
        },
        {
            "type": "industry",
            "name": "Educational Services"
        },
        {
            "type": "industry",
            "name": "Finance & Insurance"
        },
        {
            "type": "industry",
            "name": "Health Care & Social Assistance"
        },
        {
            "type": "industry",
            "name": "Manufacturing"
        },
        {
            "type": "industry",
            "name": "Mining"
        },
        {
            "type": "industry",
            "name": "Professional Services"
        },
        {
            "type": "industry",
            "name": "Public Administration"
        },
        {
            "type": "industry",
            "name": "Real Estate"
        },
        {
            "type": "industry",
            "name": "Retail Trade"
        },
        {
            "type": "industry",
            "name": "Services - Other"
        },
        {
            "type": "industry",
            "name": "Technology & Communication"
        },
        {
            "type": "industry",
            "name": "Transportation & Warehousing"
        },
        {
            "type": "industry",
            "name": "Utilities"
        },
        {
            "type": "industry",
            "name": "Wholesale Trade"
        }
    ],
    "Size": [
        {
            "type": "size",
            "name": "Size A"
        },
        {
            "type": "size",
            "name": "Size B"
        },
        {
            "type": "size",
            "name": "Size C"
        },
        {
            "type": "size",
            "name": "Size D"
        },
        {
            "type": "size",
            "name": "Size E"
        },
        {
            "type": "size",
            "name": "Size F"
        },
        {
            "type": "size",
            "name": "Size G"
        },
        {
            "type": "size",
            "name": "Size H"
        }
    ]
};

我的想法是我可以将每个产品类型下的“链接”与匹配的尺寸或行业类型相匹配。

我的 javascript 在这里:
var width = 600,
    height = 600,
    margin = {top: 16, right: 16, bottom: 16, left: 16},
    radius = 10, 
    gap = 24;

var dProduct = data.Product;

// test layout
var nodes = [];
var links = [];
dProduct.forEach(function(d, i) {
    d.x = width/2;
    d.y = margin.top + gap*i;
    nodes.push(d);
    d.links.forEach(function(c, i) {
        if(c.type === 'industry'){
            c.x = margin.left;
            c.y = margin.top + gap * (i+1) -2*radius;
        }else if (c.type === 'size'){
            c.x = width-margin.right-radius*2;
            c.y = margin.top + gap * (i+1) -2*radius;
        }
        nodes.push(c);

        var a = {x:c.y, y:c.x};
        var b = {x:d.y, y:d.x};
        links.push({source: b, target: a});
    });
});

var color = d3.scale.category20();

var svg = d3.select("#chart").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g");
var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });

var link = svg.selectAll(".link")
        .data(links)
        .enter().append("path")
        .attr("class", "link")
        .attr("d", diagonal);

var circle = svg.selectAll(".circle")
        .data(nodes)
        .enter()
        .append("g")
        .attr("class", "circle");

var el = circle.append("circle")
        .attr("cx", function(d) {return d.x})
        .attr("cy", function(d) {return d.y})
        .attr("r", radius)
        .style("fill", function(d) {return color(d.name)})
        .append("title").text(function(d) {return d.name});

我认为主要的问题是我基本上是从链接创建 Size 和 Industry 节点,而不是创建完整的节点集然后链接它们。

如何布局 3 种类型(行业、产品、尺寸),然后在产品和其他两种类型之间创建链接?或者更准确地说,如何在布局 3 种类型后创建链接?

谢谢!

最佳答案

如果我理解正确并且您说您的问题是您获得了多个节点副本,那么这应该可以通过确保仅将节点添加到 nodes 来轻松解决。阵列一次。确保唯一性的一种方法是使用关联数组,如 d3.map :

var nodeMap = d3.map();
var links = [];
dProduct.forEach(function(d, i) {
    d.x = width/2;
    d.y = margin.top + gap*i;
    nodeMap.set(d.name, d);
    d.links.forEach(function(c, i) {
        if(c.type === 'industry'){
            c.x = margin.left;
            c.y = margin.top + gap * (i+1) -2*radius;
        }else if (c.type === 'size'){
            c.x = width-margin.right-radius*2;
            c.y = margin.top + gap * (i+1) -2*radius;
        }
        nodeMap.set(c.name, c);

        var a = {x:c.y, y:c.x};
        var b = {x:d.y, y:d.x};
        links.push({source: b, target: a});
    });
});

var nodes = nodeMap.values();

请注意,此代码的唯一更改是使用了 nodeMap而不是 nodes在循环中,然后是 nodeMap.values()最后调用。

在此之后,nodes应该是一组独特的节点,您可以使用它来创建圆圈和 links应该仍然包含与以前相同的所有信息以链接所有内容。

关于d3.js:链接相关项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18391897/

相关文章:

javascript - 如何使用 JQuery 在 d3 中返回国家代码?

javascript - 为什么只有当字符串来自 d3.format 函数时,将负字符串转换为数字( +"-2.333")才会返回 NaN ?

powerbi - DAX 用户关系函数

mysql - 两个用户与同一条记录关联?

d3.js - 是否可以有一个滚动 div 来调整 dc.js 行图中的条数

d3.js - 分位数与四分位数

ruby-on-rails - rails : remove reference relationship

php - Laravel:将关系添加到数据透视模型

php - Laravel 关系递归

javascript - D3 Transform Rescale X向右跳转