Search code examples
javascriptgraphd3.jsmultiline

d3 Multiline Graph Update


I have a multiline graph that displays 10 series of data, I am trying to get the lines to update with new data but for some reason I can't get that happening. The transition with the new data is working for the points on the lines so I assume I am not selecting the right elements but for the life of me I can't figure out where my mistake is. At one point I had one line changing which indicated it was only updating from the first index of the data array. Any insight would be appreciated:

Initial Series creation-

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

series.append("path")
        .attr("id", function (d) {
            return d.name;
        })
        .attr("stay", "false")
        .attr("class", "line")

        .attr("d", function (d) {
            d.line = this;
            return line(d.values);
        })
        .attr("opacity", ".2")
        .on("click", function () {
            fadeOuts(this);
        })
        .style("stroke", function (d) {
            return strokeCol;
        })
        .style("stroke-width", "4px")
        .style("fill", "none");

Update function: This is where I am stuck, the points respond to the new data but the paths do not.

    series.data(newseriesData);
    series.selectAll("path")
            .attr("id", function (d) {
                return d.name;
            })
            .attr("d", function (d) {
                d.line = this;
                return line(d.values);
            })
            .attr("opacity", ".2")
            .on("click", function () {
                fadeOuts(this);
            })
            .style("stroke", function (d) {
                return strokeCol;
            })
            .style("stroke-width", "4px")
            .style("fill", "none");
    series.selectAll(".point")
            .data(function (d) {
                return d.values;
            })
            .transition()
            .attr("cx", function (d) {
                return x(d.label) + x.rangeBand() / 2;
            })
            .attr("cy", function (d) {
                return y(d.value);
            })
            .style("fill", function (d) {
                return color(d.name);
            })
            .style("stroke", "grey")
            .style("stroke-width", "2px")
            .on("mouseover", function (d) {
                showPopover.call(this, d);
            })
            .on("mouseout", function (d) {
                removePopovers();
            })

Yes this is a university project, this is the last piece of work in a solid 50+ hour effort on this and I'd just like to get it knocked out.


Solution

  • The short answer is that instead of series.selectAll("path") you should use series.select("path"). Remember that series is already a selection, and the subselection is done for each element in it. You've appended exactly one element to each of the selection, so .select() is fine and no .selectAll() is required.

    The main difference this makes is that .select() inherits the data from the parent selection, while .selectAll() doesn't -- when doing .selectAll() the data is simply not updated and therefore no change occurs.