D3图表无法更新-选择的输入和退出属性均为空 [英] D3 chart can't update -- enter and exit property of selection both empty

查看:108
本文介绍了D3图表无法更新-选择的输入和退出属性均为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用.json文件制作散点图.它将允许用户选择要显示的json文件中的数据组.所以我正在尝试使用更新模式.

I'm trying to make a scatter plot using a .json file. It will let the user to select which group of data in the json file to be displayed. So I'm trying to use the update pattern.

以下代码将绘制第一个图形,但是每次调用selectGroup()时(该代码在html文件中),都没有更新.每次都会在console.log(selection)中返回一个新数组,但是该选择的enter和exit属性始终为空. 谁能帮我看看吗?非常感谢!

The following code will make the first drawing, but every time selectGroup() is called(the code is in the html file), nothing got updated. The console.log(selection) did come back with a new array each time, but the enter and exit property of that selection is always empty. Can anyone help me take a look? Thanks a lot!

var margin = {
    top: 30,
    right: 40,
    bottom: 30,
    left: 40
}
var width = 640 - margin.right - margin.left,
    height = 360 - margin.top - margin.bottom;
var dataGroup;
var groupNumDefault = "I";
var maxX, maxY;
var svg, xAxis, xScale, yAxis, yScale;



//select and read data by group
function init() {
    d3.json("data.json", function (d) {
        maxX = d3.max(d, function (d) {
            return d.x;
        });
        maxY = d3.max(d, function (d) {
            return d.y;
        });
        console.log(maxY);

        svg = d3.select("svg")
            .attr("id", "scatter_plot")
            .attr("width", 960)
            .attr("height", 500)
            .append("g")
            .attr("id", "drawing_area")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        //x-axis 
        xScale = d3.scale.linear().range([0, width]).domain([0, maxX]);
        xAxis = d3.svg.axis()
            .scale(xScale).orient("bottom").ticks(6);

        //y-axis
        yScale = d3.scale.linear().range([0, height]).domain([maxY, 0]);
        yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(6);

        svg.append("g")
            .attr("class", "x_axis")
            .attr("transform", "translate(0," + (height) + ")")
            .call(xAxis);

        svg.append("g")
            .attr("class", "y_axis")
            .call(yAxis);

    });

    selectGroup(groupNumDefault);
}

//update data 
function selectGroup(groupNum) {
    d3.json("/data.json", function (d) {
        dataGroup = d.filter(function (el) {
            return el.group == groupNum;
        });
        console.log(dataGroup);
        drawChart(dataGroup);

    });
}


//drawing function
function drawChart(data) {
    var selection = d3.select("svg").selectAll("circle")
        .data(data);
    console.log(selection);

    selection.enter()
        .append("circle")
        .attr("class", "dots")
        .attr("cx", function (d) {
            console.log("updating!");
            return xScale(d.x);
        })
        .attr("cy", function (d) {
            return yScale(d.y);
        })
        .attr("r", function (d) {
            return 10;
        })
        .attr("fill", "red");

    selection.exit().remove();
}

init();

推荐答案

这里的问题有两个方面:

The problem here is on two fronts:

首先,您在data()调用中缺少关键功能,这意味着默认情况下数据与索引(数据数组中的位置)匹配,这意味着如果将旧数据集和当前数据集发送到大小相同.相反,当d3按索引匹配时(旧数据集中的第一个基准=新数据集中的第一个基准,旧数据集中的第二个基准=第二个基准),当d3匹配时,大多数(也许全部)数据将被放入 update 选择中在新的数据集等中)

Firstly, your lack of a key function in your data() call means data is matched by index (position in data array) by default, which will mean no enter and exit selections if the old and current datasets sent to data() are of the same size. Instead, most (perhaps all) of the data will be put in the update selection when d3 matches by index (first datum in old dataset = first datum in new dataset, second datum in old dataset = second datum in new dataset etc etc)

var selection = d3.select("svg").selectAll("circle")
        .data(data);

请参阅: https://bl.ocks.org/mbostock/3808221

基本上,您需要将数据调用调整为类似的方式(如果您的数据具有.id属性或可以唯一标识每个数据的其他任何内容)

Basically, you need your data call adjusted to something like this (if your data has an .id property or anything else that can uniquely identify each datum)

var selection = d3.select("svg").selectAll("circle")
            .data(data, function(d) { return d.id; });

这将根据数据的实际内容而不只是索引来生成enter()和exit()(并更新)选择.

This will generate enter() and exit() (and update) selections based on the data's actual contents rather than just their index.

第二,并非第二轮的所有保证都在输入或退出选择中.某些数据可能只是现有数据的更新,而不是这些选择中的任何一种(在您的情况下,每次都可能是全新的).但是,鉴于上述情况,几乎可以保证您的大部分数据都在更新选择中,其中一些是错误的.要显示更新,您需要像这样更改代码(我在这里假设d3 v3,显然对于v4稍有不同)

Secondly, not everything the second time round is guaranteed be in the enter or exit selections. Some data may be just an update of existing data and not in either of those selections (in your case it may be intended to be completely new each time). However, given the situation just described above it's pretty much guaranteed most of your data will be in the update selection, some of it by mistake. To show updates you will need to alter the code like this (I'm assuming d3 v3 here, apparently it's slightly different for v4)

selection.enter()
        .append("circle")
        .attr("class", "dots")
        .attr("r", function (d) {
            return 10;
        })
        .attr("fill", "red");

// this new bit is the update selection (which includes the just added enter selection
// now, the syntax is different in v4)
selection // v3 version
// .merge(selection)  // v4 version (remove semi-colon off preceding enter statement)
        .attr("cx", function (d) {
            console.log("updating!");
            return xScale(d.x);
        })
        .attr("cy", function (d) {
            return yScale(d.y);
        })

   selection.exit().remove();

这两个更改应该可以使您的可视化工作正常,除非问题当然出在第二次出现空白数据集之类的简单问题时:-)

Those two changes should see your visualisation working, unless of course the problem is something as simple as an empty set of data the second time around which would also explain things :-)

这篇关于D3图表无法更新-选择的输入和退出属性均为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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