使用流式数据更新嵌套d3气泡图 [英] Updating nested d3 bubble chart with streaming data

查看:243
本文介绍了使用流式数据更新嵌套d3气泡图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图为我的项目实现一个嵌套的气泡图,我必须显示网络中不​​同客户端发生的情况。我使用的示例显示在:
https://bl.ocks.org/mbostock/7607535

I have been trying to implemented a nested bubble chart for a project of mine where I have to display what happens in different clients in a network. I used the example showed at: https://bl.ocks.org/mbostock/7607535

这里是我使用的代码:

    /// <reference path="../bower_components/dt-d3/d3.d.ts" />
    var margin = 20, diameter = 960;
    var color = d3.scale.linear()
        .domain([-1, 4])
        .range(["#ff8080", "#b30000"])
        .interpolate(d3.interpolateHcl);
    var pack = d3.layout.pack()
        .padding(2)
        .size([diameter - margin, diameter - margin])
        .value(function (d) { return d.size; });
    var svg = d3.select("body").select("#parent").select("#svg1").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
  .append("g")
    .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
    var svg2 = d3.select("body").select("#parent").select("#svg2").append("svg")
        .attr("width", 100)
        .attr("height", 100)
        .append("g")
        .attr("transform", "translate(" + margin + "," + margin + ")");
    function draw(fileToRead){
        console.log(fileToRead);
        d3.json(fileToRead, function (error, root) {
            if (error)
                throw error;
        var focus = root, nodes = pack.nodes(root), view;
        var circle = svg.selectAll("circle").data(nodes);
        circle.attr("class","update");
        circle.enter().append("circle")
            .attr("class", function (d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })        .style("fill", function (d) { return d.children ? d.children.length > 3 ? color(d.depth) : "white" : d.size > 0.02 ? "#660000" : "#003366"; })
            .style("fill", function (d) { return d.children ? "white" : d.size > 0.02 ? "#660000" : "#003366"; })
            .on("click", function (d) { if (focus !== d)
            zoom(d), d3.event.stopPropagation(); });
        circle.exit().remove();
        var text = svg.selectAll("text").data(nodes);
        text.attr("class","update");
        text.enter().append("text")
            .attr("class", "label")
            .style("fill-opacity", function (d) { return d.parent === root ? 1 : 0; })
            .style("display", function (d) { return d.parent === root ? "inline" : "none"; })
            .style("fill", "black")
            .text(function (d) { return d.name; });
        text.exit().remove();
        var node = svg.selectAll("circle,text");
        d3.select("body")
            .style("background", color(-1))
            .on("click", function () { zoom(root); });
        zoomTo([root.x, root.y, root.r * 2 + margin]);
        function zoom(d) {
            var focus0 = focus;
            focus = d;
            if (focus.depth == 2) {
                circle2.style("fill", "white");
            } else {
                circle2.style("fill", "black");
            }
            var transition = d3.transition()
                .duration(d3.event.altKey ? 7500 : 750)
                .tween("zoom", function (d) {
                var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
                return function (t) { zoomTo(i(t)); };
            });
            transition.selectAll("text")
                .filter(function (d) { return d.parent === focus || this.style.display === "inline"; })
                .style("fill-opacity", function (d) { return d.parent === focus ? 1 : 0; })
                .each("start", function (d) { if (d.parent === focus)
                this.style.display = "inline"; })
                .each("end", function (d) { if (d.parent !== focus)
                this.style.display = "none"; });
        }
        function zoomTo(v) {
            var k = diameter / v[2];
            view = v;
            node.attr("transform", function (d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
            circle.attr("r", function (d) { return d.r * k; });
        }
        });
    }
    d3.select(self.frameElement).style("height", diameter + "px");

我遇到的问题是当我不断地将新数据流入UI。每次我调用绘制一个完整的json文件与我在数据库中的所有数据。我已经阅读enter(),exit(),remove()负责更新DOM元素,但它似乎我错过了一些东西。当draw()函数被调用时,它似乎在现有的上面绘制气泡,像圆形边框颜色或文本边框颜色的东西消失。
我想知道我是否以正确的方式使用enter()和exit()命令。我想让draw()函数接收json文件,只更新气泡图中的信息是新的,没有DOM元素存在,但它似乎只是重新创建所有的DOM元素。

The problem I am encountering is when I continuously stream new data to the UI. Everytime I call up "Draw" with a full json file with all the data I have in the database. I have read that the enter(), exit(), remove() are responsible for updating the DOM elements, but it seems I am missing something. When the draw() function is called it seems to draw bubbles above existing ones and stuff like circle border color or text border color disappears. I am wondering if I am using the enter() and exit() commands in the right way. I would like to have the draw() function recieve the json file and only update info in the bubble graph that is new and no DOM elements exist for it, but it seems it just recreates all the DOM elements again.

提前谢谢,
Georgi

Thank you in advance, Georgi

PS:我有两个svg,因为我试图拆分屏幕两个用气泡图占据左边,右边用内部气泡放大时显示额外信息

PS: I have two svg's becase I am trying to split the screen in two with the left side being occupied by the bubble graph and the right side with extra information shown when we zoom it at an internal bubble

EDIT1:这里是一个data传递给draw()函数:

Here is a sample of the data I pass to the draw() function:

{"name": "", 
    "children": 
        [{"name": "10.0.0.64", "children": 
            [{"name": "unidentified", "children": 
                [{"name": "datasource", "size": 0.002551020408163265}, {"name": "datasource", "size": 0.0031746031746031746}, {"name": "datasource", "size": 0.0017123779389460522}, {"name": "average", "size": 0.008550406895439414}, {"name": "datasource", "size": 0.019020266320109332}]}, 
            {"name": "www.quefaire.be", "children":                 
                [{"name": "average", "size": 0.002270490544565449}, {"name": "datasource", "size": 0.023243328100470965}]}, {"name": "tnsinternet.be", "children": [{"name": "average", "size": 0.002199967070440535}, {"name": "datasource", "size": 0.022009167303284966}]}, 
            {"name": "hy.sachinese.com", "children":                    
                [{"name": "average", "size": 0.0022121416372369493}, {"name": "datasource", "size": 0.022222222222222223}]}, {"name": "pagesdor.be", "children": [{"name": "average", "size": 0.0030411250824668935}, {"name": "datasource", "size": 0.03672943251374624}]}, 
            {"name": "r.254a.com", "children": 
                [{"name": "average", "size": 0.0018942905665264935}, {"name": "datasource", "size": 0.015873015873015872}]}, 
            {"name": "i.ctnsnet.com", "children": 
                [{"name": "average", "size": 0.0018942905665264935}, {"name": "datasource", "size": 0.015873015873015872}]}, 
            {"name": "link.carrefour.eu", "children": 
                [{"name": "average", "size": 0.0019793245801319357}, {"name": "datasource", "size": 0.017857142857142856}]}, 
            {"name": "goudengids.be", "children": 
                [{"name": "average", "size": 0.00457041828122788}, {"name": "datasource", "size": 0.06349206349206349}]}, {"name": "www.inmemoriam.be", "children": [{"name": "average", "size": 0.0018443560093702978}, {"name": "datasource", "size": 0.014707876206037973}]}, 
            {"name": "www1.gfk-wi.com", "children": 
                [{"name": "datasource", "size": 0.011986645572622365}, {"name": "average", "size": 0.0017277318393667718}]}, {"name": "bootstrapcdn.com", "children": [{"name": "average", "size": 0.008550406895439414}, {"name": "datasource", "size": 0.13314186424076532}]}, 
            {"name": "maxcdn.bootstrapcdn.com", "children": 
                [{"name": "datasource", "size": 0.031746031746031744}, {"name": "average", "size": 0.0027563593243117796}]}]}]}

这里也是我的CSS:

.svg-container {
    display: flex;
    position: relative;
    width: 100%;
    padding-bottom: 100%; /* aspect ratio */
    vertical-align: top;
    overflow: hidden;
}

.svg-content-responsive {
    display: inline-block;
    position: absolute;
    top: 10px;
    left: 0;
}

.container {
  float: left;
}

.node {
    cursor: pointer;
    stroke: darkgrey;
}

.node:hover {
    stroke: #000;
    stroke-width: 1.5px;
}

.node--leaf {
    fill: white;
}

.label {
    font: 11px "Helvetica Neue", Helvetica, Arial, sans-serif;
    text-anchor: middle;
    text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
}

.label,
.node--root,
.node--leaf {
    pointer-events: none;
}


推荐答案

节点具有唯一的名称或必须具有一些id以唯一地定义节点。
使用如下所示的唯一键唯一标识数据。
在你的数据集我的解决方案不工作原因是很少的节点有非唯一的名称,如数据集等。

First of all ensure that all the nodes have unique names or must have some id to uniquely define a node. Use that unique key as shown below to identify the data uniquely. In you dataset my solution will not work reason is that few nodes have non unique names like dataset etc.

以下解决方案将工作,只有有

The below solution will work only if there is a unique name.

而不是

var circle = svg.selectAll ).data(nodes);

执行此操作

var circle = svg.selectAll("circle").data(nodes, function(d){return d.name});

而不是

var text = svg.selectAll("text").data(nodes);

执行此操作

var text = svg.selectAll("text").data(nodes, function(d){return d.name});

exit()

阅读关键功能 here

这篇关于使用流式数据更新嵌套d3气泡图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆