D3图表无法更新——选择的进入和退出属性都为空

Yil*_*ang 2 javascript json d3.js

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

以下代码将进行第一次绘图,但每次调用 selectGroup() 时(代码在 html 文件中),没有任何更新。console.log(selection) 确实每次都返回一个新数组,但该选择的进入和退出属性始终为空。谁能帮我看看?非常感谢!

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();
Run Code Online (Sandbox Code Playgroud)

mgr*_*ham 5

这里的问题有两个方面:


首先,您的data()调用中缺少键函数意味着默认情况下数据按索引(数据数组中的位置)匹配,这意味着如果发送到的旧数据集和当前数据集data()大小相同,则没有进入和退出选择。相反,当 d3 按索引匹配时,大部分(可能全部)数据将被放入更新选择中(旧数据集中的第一个数据 = 新数据集中的第一个数据,旧数据集中的第二个数据 = 新数据集中的第二个数据等)

var selection = d3.select("svg").selectAll("circle")
        .data(data);
Run Code Online (Sandbox Code Playgroud)

参见:https : //bl.ocks.org/mbostock/3808221

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

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

这将根据数据的实际内容而不仅仅是它们的索引生成 enter() 和 exit() (和更新)选择。


其次,并非所有第二轮都保证在进入或退出选择中。某些数据可能只是现有数据的更新,而不是这些选择中的任何一个(在您的情况下,它可能每次都是全新的)。但是,鉴于上面刚刚描述的情况,几乎可以保证您的大部分数据都在更新选择中,其中一些是错误的。要显示更新,您需要像这样更改代码(我在这里假设 d3 v3,显然 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();
Run Code Online (Sandbox Code Playgroud)

这两个更改应该会看到您的可视化工作,除非问题当然像第二次空数据集一样简单,这也可以解释事情:-)