如何在d3.js图中转换多行?

问题描述:

我一直在尝试改编Mike Bostock的chained transition script来处理多条线路,但我没有得到它的工作。第一次显示后,线条和标签飞出了阴谋,不再显示了所有事情都得到了更新(我可以看到在检查JavaScript控制台时,线条的值会发生变化)。我不明白我做错了什么。我将在下面发布(冗长的)代码(对长度表示歉意)。我将不胜感激任何帮助,谢谢!如何在d3.js图中转换多行?

<!DOCTYPE html> 
<head> 
<title>Modified Chained Transitions</title> 
<meta charset="utf-8"> 
<script src="https://d3js.org/d3.v3.min.js"></script> 
<style> 
body { 
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 
    margin: auto; 
    position: relative; 
    width: 960px; 
} 

text { 
    font: 10px sans-serif; 
} 

.axis path, 
.axis line { 
    fill: none; 
    stroke: #000; 
    shape-rendering: crispEdges; 
} 

.x.axis path { 
    display: none; 
} 

.line { 
    fill: none; 
    stroke: steelblue; 
    stroke-width: 1.5px; 
} 

form { 
    position: absolute; 
    right: 10px; 
    top: 10px; 
} 

</style> 
</head> 
<body> 
<br> 
    <button type="button"> Request data</button> 

    <div id='chart'> </div> 
</body> 
<script> 

var margin = {top: 20, right: 80, bottom: 30, left: 50}, 
    width = 750 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var parseDate = d3.time.format("%Y%m%d").parse; 

var xScale = d3.time.scale() 
    .range([0, width]); 

var yScale = d3.scale.linear() 
    .range([height, 0]); 

var color = d3.scale.category10(); 

var xAxis = d3.svg.axis() 
    .scale(xScale) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(yScale) 
    .orient("left"); 

var line = d3.svg.line() 
       .interpolate("basis") 
       .x(function(d) { return xScale(d.date); }) 
       .y(function(d) { return yScale(d.temperature); }); 

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 + ")"); 


var getNewData = function() { 
    var data = []; 
    var counter = 0; 
    function generate(){ 
     var startDate = new Date; 
     counter += 1; 
     var range = counter % 2 === 0 ? 10 : 100; 
     for (i = 0; i < 100; i++) { 
      data[i] = {"date": new Date(startDate - i), 
       "New York": Math.random() * (range - 1), 
       "San Francisco": Math.random() * (range - 1), 
       "Austin": Math.random() * (range - 10)}; 
     } 
     return data; 
    } 
    return { 
     new: function() {return generate()} 
    }; 
}; // function getNewData() 

var newData = getNewData(); 
data = newData.new(); 

color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; })); 

var cities = color.domain().map(function(name) { 
    return { 
    name: name, 
    values: data.map(function(d) { 
     return { date: d.date, temperature: +d[name]}; 
    }) 
    }; 
}); 

xScale.domain(d3.extent(data, function(d) { return d.date; })); 
yScale.domain([ 
    d3.min(cities, function(c) { 
    return d3.min(c.values, function(v) { return v.temperature; }); }), 
    d3.max(cities, function(c) { 
    return d3.max(c.values, function(v) { return v.temperature; }); }) 
]); 

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

svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 
    .append("text") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 6) 
     .attr("dy", ".71em") 
     .style("text-anchor", "end") 
     .text("Temperature (ºF)"); 

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

city.append("path") 
    .attr("class", "line") 
    .attr("d", function(d) { return line(d.values); }) 
    .style("stroke", function(d) { return color(d.name); }); 

city.append("text") 
    .datum(function(d) { return {name: d.name, values: d.values[0]}; }) 
     .attr("class", "label") 
    .attr("transform", function(d) { return "translate(" + 
     xScale(d.values.date) + "," + yScale(d.values.temperature) + ")"; }) 
    .attr("x", 3) 
    .attr("dy", ".35em") 
    .text(function(d) { return d.name; }); 

d3.selectAll("button").on("click", change); 

function change() { 

    data = newData.new(); 
    color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; })); 
    cities = color.domain().map(function(name) { 
     return { 
     name: name, 
     values: data.map(function(d) { 
      return { date: d.date, temperature: +d[name]}; 
     }) 
     }; 
    }); 
    console.log(cities[0].values[0]); 

    xScale.domain(d3.extent(data, function(d) { return d.date; })); 
    yScale.domain([ 
     d3.min(cities, function(c) { 
     return d3.min(c.values, function(v) { return v.temperature; }); }), 
     d3.max(cities, function(c) { 
     return d3.max(c.values, function(v) { return v.temperature; }); }) 
    ]); 

    var t0 = svg.transition().duration(750); 
    t0.selectAll(".line") 
     .attr("d", function(cities) { return line(cities.values); }) 
     .style("stroke", function(cities) { return color(cities.name); }); 
    t0.selectAll(".label").attr("transform", 
     "translate(0,0)").text(function(cities) { return cities.name; }); 


    var t1 = t0.transition(); 
// t1.selectAll(".line").attr("d", line(data)); 
// t1.select(".line") 
    t1.selectAll(".line") 
//  t1.selectAll(".city") 
     .attr("d", function(cities) { return line(cities.values); }) 
     .style("stroke", function(cities) { return color(cities.name); }); 
    t1.select(".y.axis").call(yAxis); 
    t1.select(".x.axis").call(xAxis); 
    t1.select(".label") 
     .attr("transform", function(d) { return "translate(" + 
     xScale(d.values.date) + "," + 
      yScale(d.values.temperature) + ")"; }); 
} // function change() 

</script> 
</html> 

我可以帮助修复您的转换,但我不确定您试图“链接”。在链接的例子中,Bostock将一行换成另一行(转换1),然后将该行适配到新的域(转换2)。你似乎不想交换线,所以你适合一个新的领域,然后过渡线(过渡1),但什么是过渡2?

现在要回答你更直接的问题,说明为什么你的转换不起作用,这只是因为你永远不会更新你的数据。在链接的例子中,Bostock将数据集绑定到他的行,然后交换他在行函数中绘制的数据集。但是,您只能拥有原始数据集。快速修复是:

function change() { 

    ... //<-- get new data 

    // bind your new data 
    var cities = svg.selectAll(".city") 
    .data(cities) 

    // sub selection to transition line 
    cities 
    .select(".line") 
    .transition() 
    .duration(750) 
    .attr("d", function(d) { return line(d.values); }) 
    .style("stroke", function(d) { return color(d.name); }) 

    // concurrent sub selection to move labels 
    cities 
    .select(".label") 
    .transition() 
    .duration(750) 
    .attr("transform", function(d){ 
     var last = d.values[0]; 
     return "translate(" + xScale(last.date) + "," + yScale(last.temperature) + ")"; 
    }) 

} 

运行代码:

<!DOCTYPE html> 
 

 
<head> 
 
    <title>Modified Chained Transitions</title> 
 
    <meta charset="utf-8"> 
 
    <script src="https://d3js.org/d3.v3.min.js"></script> 
 
    <style> 
 
    body { 
 
     font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 
 
     margin: auto; 
 
     position: relative; 
 
     width: 960px; 
 
    } 
 
    
 
    text { 
 
     font: 10px sans-serif; 
 
    } 
 
    
 
    .axis path, 
 
    .axis line { 
 
     fill: none; 
 
     stroke: #000; 
 
     shape-rendering: crispEdges; 
 
    } 
 
    
 
    .x.axis path { 
 
     display: none; 
 
    } 
 
    
 
    .line { 
 
     fill: none; 
 
     stroke: steelblue; 
 
     stroke-width: 1.5px; 
 
    } 
 
    
 
    form { 
 
     position: absolute; 
 
     right: 10px; 
 
     top: 10px; 
 
    } 
 
    </style> 
 
</head> 
 

 
<body> 
 
    <br> 
 
    <button type="button"> Request data</button> 
 

 
    <div id='chart'> </div> 
 
</body> 
 
<script> 
 
    var margin = { 
 
     top: 20, 
 
     right: 80, 
 
     bottom: 30, 
 
     left: 50 
 
    }, 
 
    width = 500 - margin.left - margin.right, 
 
    height = 500 - margin.top - margin.bottom; 
 

 
    var parseDate = d3.time.format("%Y%m%d").parse; 
 

 
    var xScale = d3.time.scale() 
 
    .range([0, width]); 
 

 
    var yScale = d3.scale.linear() 
 
    .range([height, 0]); 
 

 
    var color = d3.scale.category10(); 
 

 
    var xAxis = d3.svg.axis() 
 
    .scale(xScale) 
 
    .orient("bottom"); 
 

 
    var yAxis = d3.svg.axis() 
 
    .scale(yScale) 
 
    .orient("left"); 
 

 
    var line = d3.svg.line() 
 
    .interpolate("basis") 
 
    .x(function(d) { 
 
     return xScale(d.date); 
 
    }) 
 
    .y(function(d) { 
 
     return yScale(d.temperature); 
 
    }); 
 

 
    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 + ")"); 
 

 

 
    var getNewData = function() { 
 
    var data = []; 
 
    var counter = 0; 
 

 
    function generate() { 
 
     var startDate = new Date; 
 
     counter += 1; 
 
     var range = counter % 2 === 0 ? 10 : 100; 
 
     for (i = 0; i < 100; i++) { 
 
     data[i] = { 
 
      "date": new Date(startDate - i), 
 
      "New York": Math.random() * (range - 1), 
 
      "San Francisco": Math.random() * (range - 1), 
 
      "Austin": Math.random() * (range - 10) 
 
     }; 
 
     } 
 
     return data; 
 
    } 
 
    return { 
 
     new: function() { 
 
     return generate() 
 
     } 
 
    }; 
 
    }; // function getNewData() 
 

 
    var newData = getNewData(); 
 
    data = newData.new(); 
 

 
    color.domain(d3.keys(data[0]).filter(function(key) { 
 
    return key !== "date"; 
 
    })); 
 

 
    var cities = color.domain().map(function(name) { 
 
    return { 
 
     name: name, 
 
     values: data.map(function(d) { 
 
     return { 
 
      date: d.date, 
 
      temperature: +d[name] 
 
     }; 
 
     }) 
 
    }; 
 
    }); 
 

 
    xScale.domain(d3.extent(data, function(d) { 
 
    return d.date; 
 
    })); 
 
    yScale.domain([ 
 
    d3.min(cities, function(c) { 
 
     return d3.min(c.values, function(v) { 
 
     return v.temperature; 
 
     }); 
 
    }), 
 
    d3.max(cities, function(c) { 
 
     return d3.max(c.values, function(v) { 
 
     return v.temperature; 
 
     }); 
 
    }) 
 
    ]); 
 

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

 
    svg.append("g") 
 
    .attr("class", "y axis") 
 
    .call(yAxis) 
 
    .append("text") 
 
    .attr("transform", "rotate(-90)") 
 
    .attr("y", 6) 
 
    .attr("dy", ".71em") 
 
    .style("text-anchor", "end") 
 
    .text("Temperature (ºF)"); 
 

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

 
    city.append("path") 
 
    .attr("class", "line") 
 
    .attr("d", function(d) { 
 
     return line(d.values); 
 
    }) 
 
    .style("stroke", function(d) { 
 
     return color(d.name); 
 
    }); 
 

 
    city.append("text") 
 
    .datum(function(d) { 
 
     return { 
 
     name: d.name, 
 
     values: d.values[0] 
 
     }; 
 
    }) 
 
    .attr("class", "label") 
 
    .attr("transform", function(d) { 
 
     return "translate(" + 
 
     xScale(d.values.date) + "," + yScale(d.values.temperature) + ")"; 
 
    }) 
 
    .attr("x", 3) 
 
    .attr("dy", ".35em") 
 
    .text(function(d) { 
 
     return d.name; 
 
    }); 
 

 
    d3.selectAll("button").on("click", change); 
 

 
    function change() { 
 

 
    data = newData.new(); 
 
    color.domain(d3.keys(data[0]).filter(function(key) { 
 
     return key !== "date"; 
 
    })); 
 
    cities = color.domain().map(function(name) { 
 
     return { 
 
     name: name, 
 
     values: data.map(function(d) { 
 
      return { 
 
      date: d.date, 
 
      temperature: +d[name] 
 
      }; 
 
     }) 
 
     }; 
 
    }); 
 

 
    xScale.domain(d3.extent(data, function(d) { 
 
     return d.date; 
 
    })); 
 

 
    yScale.domain([ 
 
     d3.min(cities, function(c) { 
 
     return d3.min(c.values, function(v) { 
 
      return v.temperature; 
 
     }); 
 
     }), 
 
     d3.max(cities, function(c) { 
 
     return d3.max(c.values, function(v) { 
 
      return v.temperature; 
 
     }); 
 
     }) 
 
    ]); 
 

 
    var cities = svg.selectAll(".city") 
 
     .data(cities) 
 

 
    cities 
 
     .select(".line") 
 
     .transition() 
 
     .duration(750) 
 
     .attr("d", function(d) { 
 
     return line(d.values); 
 
     }) 
 
     .style("stroke", function(d) { 
 
     return color(d.name); 
 
     }) 
 

 
    cities 
 
     .select(".label") 
 
     .transition() 
 
     .duration(750) 
 
     .attr("transform", function(d) { 
 
     var last = d.values[0]; 
 
     return "translate(" + xScale(last.date) + "," + yScale(last.temperature) + ")"; 
 
     }) 
 

 
    svg.selectAll(".y.axis") 
 
     .transition() 
 
     .duration(750) 
 
     .call(yAxis); 
 

 
    svg.selectAll(".x.axis") 
 
     .transition() 
 
     .duration(750) 
 
     .call(xAxis); 
 

 
    } // function change() 
 
</script> 
 

 
</html>