简体   繁体   中英

transition between two datasets, from a single line chart to a multiline chart, in d3

I'm trying to build a chart that goes from 1 line to many lines. I have built the two charts separately, but am having trouble combining them. The idea is that I want to show the total of all fruit sold per year, and then show how much of each fruit is sold per year.

This is the template I'm working from: http://bl.ocks.org/d3noob/a048edddbf83bff03a34

In my code, the single line shows up fine. When I click update, the axes update as they should, but the data doesn't. Any help would be greatly appreciated.

My code is in a plunker, here: https://plnkr.co/edit/dgwsGLIRbZ2qm7faEvSw?p=preview

The code is also below.

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>
    body { font: 12px Arial;}
    path {
        stroke: #333;
        stroke-width: 2;
        fill: none;
    }
    .axis path,
    .axis line {
        fill: none;
        stroke: grey;
        stroke-width: 1;
        shape-rendering: crispEdges;
    }
    </style>
    <body>
    <div id="option">
      <input name="updateButton" id="updateData" type="button" value="Update" />
        <input name="revertButton" type="button" value="Revert" onclick="revertData()" />
    </div>

    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="//code.jquery.com/jquery-1.10.2.js"></script>

    <script>

    var margin = {top: 30, right: 20, bottom: 30, left: 50},
        width = 800 - margin.left - margin.right,
        height = 470 - margin.top - margin.bottom;

    var x = d3.scaleLinear().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    var xAxis = d3.axisBottom().scale(x)
        .ticks(7)
        .tickFormat(d3.format("d"))

    var yAxis = d3.axisLeft().scale(y)
        .ticks(5);

    var valueline = d3.line()
        .x(function(d) { return x(d.Year); })
        .y(function(d) { return y(d.Count); });

    var svg = d3.select("body")
        .append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
        .append("g")
            .attr("transform",
                  "translate(" + margin.left + "," + margin.top + ")");

    d3.csv("datab.csv", function(error, data2) {
      d3.csv("dataa.csv", function(error, data) {
        data.forEach(function(d) {
            d.Year = +d.Year;
            d.Count = +d.Count;
        });

        x.domain(d3.extent(data, function(d) { return d.Year; }));
        y.domain([0, d3.max(data, function(d) { return d.Count; })]);

        dataNest1 = d3.nest()
                .key(function(d) {return d.Type;})
                .entries(data);

        var result1 = dataNest1.filter(function(val,idx, arr){
              return $("." + val.key)
            })

      var calls = d3.select("svg").selectAll(".line")
        .data(result1, function(d){return d.key})

        var color1 = d3.scaleOrdinal().range(["#333",  "none", "none", "none", "none", "none"]);

      calls.enter().append("path")
          .attr("class", "line")
        .attr("stroke","#333")
        .attr("d", function(d){
          return valueline(d.values)
        })
        .attr("transform",
              "translate(" + margin.left + "," + margin.top + ")");

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

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

            d3.select('#updateData').on('click',function(){
              updateData(data2)
            })
     });
    });

    function updateData(data2) {

            data2.forEach(function(d) {
                d.Year = +d.Year;
                d.Count = +d.Count;
            });

          dataNest = d3.nest()
                  .key(function(d) {return d.Descriptor;})
                  .entries(data2);

            var result = dataNest.filter(function(val,idx, arr){
                      return $("." + val.key)
                    })

            x.domain(d3.extent(data2, function(d) { return d.Year; }));
            y.domain([0, d3.max(data2, function(d) { return d.Count; })]);

        var svg = d3.select("body").transition();
        svg.selectAll('.circle').duration(0).remove()

        d3.select("svg").selectAll(".line")
        .data(result, function(d){return d.key})

        d3.select("svg").selectAll("path.line")
            .transition()
            .duration(700)
          .style("stroke", "#333")
                .attr("d", function(d){
                    return valueline(d.values)
                });

            // svg.select(".line")   // change the line
            //     .duration(750)
            //     .attr("d", valueline(rats));

            svg.select(".x.axis")
                .transition()
                .duration(750)
                .call(xAxis);
            svg.select(".y.axis")
                .duration(750)
                .call(yAxis);

    }

    function revertData() {

        // Get the data again
        d3.csv("totalsbyyear.csv", function(error, data) {
            data.forEach(function(d) {
                d.Year = +d.Year;
                d.Count = +d.Count;
            });

            // Scale the range of the data again
            x.domain(d3.extent(data, function(d) { return d.Year; }));
            y.domain([0, d3.max(data, function(d) { return d.Count; })]);

        // Select the section we want to apply our changes to
        var svg = d3.select("body").transition();

        // Make the changes
            svg.select(".line")   // change the line
                .duration(750)
                .attr("d", valueline(data));
            svg.select(".x.axis") // change the x axis
                .duration(750)
                .call(xAxis);
            svg.select(".y.axis") // change the y axis
                .duration(750)
                .call(yAxis);

        });
    }

    </script>
    </body>

There are a few problems here. The first one being that your datasets are very different and I don't see anywhere in the code to compensate for there being multiple different fruit in the same year. This is something you will need to address either by modifying your csv file or in your updateData function to extract just a single fruit.

I have made some changes to your plunker that will allow the updateFunction to work but without fixing the input data it won't really matter.

https://plnkr.co/edit/DSg09NWPrBADLLbcL5cx?p=preview

The main thing that needed to be fixed was

d3.select("svg").selectAll("path.line")
  .data(result, function(d){return d.key})
  .transition()
  .duration(700)
  .style("stroke", "#337")
     .attr("d", function(d){
     return valueline(result)
   });

And putting the d3.csv on datab.csv call in the updateData function instead of wrapping it around the main table creation function.

I was probably being unclear in my question asking. I figured out what I needed to do to make it work as intended. Code here:

https://plnkr.co/edit/YrABkbc8l9oeT1ywMspy?p=preview

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>
    body { font: 12px Arial;}
    path {
        stroke: #333;
        stroke-width: 2;
        fill: none;
    }
    .axis path,
    .axis line {
        fill: none;
        stroke: grey;
        stroke-width: 1;
        shape-rendering: crispEdges;
    }
    </style>
    <body>

    <div id="option">
      <input name="updateButton" id="updateData" type="button" value="Update" />
        <input name="revertButton" type="button" value="Revert" onclick="revertData()" />
    </div>

    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="//code.jquery.com/jquery-1.10.2.js"></script>

    <script>

    var margin = {top: 30, right: 200, bottom: 30, left: 50},
        width = 850 - margin.left - margin.right,
        height = 470 - margin.top - margin.bottom;

    var x = d3.scaleLinear().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    var xAxis = d3.axisBottom().scale(x)
        .ticks(7)
        .tickFormat(d3.format("d"))

    var yAxis = d3.axisLeft().scale(y)
        .ticks(5);

    var valueline = d3.line()
        .x(function(d) { return x(d.Year); })
        .y(function(d) { return y(d.Count); });

    var svg = d3.select("body")
        .append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
        .append("g")
            .attr("transform",
                  "translate(" + margin.left + "," + margin.top + ")");

    d3.csv("datab.csv", function(error, data2) {
      d3.csv("dataa.csv", function(error, data) {
        data.forEach(function(d) {
            d.Year = +d.Year;
            d.Count = +d.Count;
        });

        x.domain(d3.extent(data, function(d) { return d.Year; }));
        y.domain([0, d3.max(data, function(d) { return d.Count; })]);

        svg.append("path")
            .attr("class", "line")
            .attr("d", valueline(data));

        svg.append("text")
            .attr("transform", function(d) { return "translate(" + x(2017) + "," + y(35074) + ")"; })
            .attr("x", 3)
            .attr("dy", "0.35em")
            .attr('class','toplinetext')
            .style("font", "10px sans-serif")
            .text(function(d) { return "All"; });

        circles = svg.selectAll("circle")
              .data(data)
              .enter()
              .append("circle")
              .attr('class','circle')
              .attr('cx',function(d){ return x(d.Year)})
              .attr('cy',function(d){ return y(d.Count)})
              .attr('r',3)

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

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

          svg.exit().remove();

            d3.select('#updateData').on('click',function(){
              updateData(data2)
            })
     });
    });

    function updateData(data2) {

          data2.forEach(function(d) {
                d.Year = +d.Year;
                d.Count = +d.Count;
            });

          var notapples = data2.filter(function(d){return d.Descriptor == "Peach" || d.Descriptor == "Pear" || d.Descriptor == "Plum" || d.Descriptor == "Banana"})

          dataNest = d3.nest()
                  .key(function(d) {return d.Descriptor;})
                  .entries(notapples);

            var result = dataNest.filter(function(val,idx, arr){
                      return $("." + val.key)
                    })

         $('.toplinetext').text('Apples');


            x.domain(d3.extent(data2, function(d) { return d.Year; }));
            y.domain([0, d3.max(data2, function(d) { return d.Count; })]);

        var svg = d3.select("body").transition();
        svg.selectAll('.circle').duration(0).remove()

        var typeOfCall = d3.select("svg").selectAll(".dline")
          .data(result, function(d){return d.key})
          .enter().append("g")
          .attr("class", function(d){return "type " + d.key})
          .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

          var color2 = d3.scaleOrdinal().range(["#ff0000",  "#333", "#333", "#333", "#333", "#333"]);

        typeOfCall.append("path")
          .attr("height", 0)
            .transition()
            .duration(700)
            .attr("class", "line")
          .style("stroke", function(d,i) { return color2(d.key); })
                .attr("d", function(d){
                    return valueline(d.values)
                });

          typeOfCall.append("text")
             .datum(function(d) { return {id: d.Descriptor, value: d.values[d.values.length - 1]}; })
              .attr("transform", function(d) { return "translate(" + x(d.value.Year) + "," + y(d.value.Count) + ")"; })
              .attr("x", 3)
              .attr("dy", "0.35em")
              .style("font", "10px sans-serif")
              .text(function(d) { return d.value.Descriptor; });

            typeOfCall.exit().remove();

            apples = data2.filter(function(d){return d.Descriptor == "Apple"})

            svg.select(".line")
                .duration(750)
                .attr("d", valueline(apples));

            svg.select(".x.axis")
                .transition()
                .duration(750)
                .call(xAxis);
            svg.select(".y.axis")
                .duration(750)
                .call(yAxis);
    }

    function revertData() {

        // Get the data again
        d3.csv("totalsbyyear.csv", function(error, data) {
            data.forEach(function(d) {
                d.Year = +d.Year;
                d.Count = +d.Count;
            });

          $('.toplinetext').text('All');
          $('.Peach,.Pear,.Banana,.Plum').remove();
            // Scale the range of the data again
            x.domain(d3.extent(data, function(d) { return d.Year; }));
            y.domain([0, d3.max(data, function(d) { return d.Count; })]);

        // Select the section we want to apply our changes to
        var svg = d3.select("body").transition();

        // Make the changes
            svg.select(".line")   // change the line
                .duration(750)
                .attr("d", valueline(data));
            svg.select(".x.axis") // change the x axis
                .duration(750)
                .call(xAxis);
            svg.select(".y.axis") // change the y axis
                .duration(750)
                .call(yAxis);

        });
    }

    </script>
    </body>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM