如何重新绘制 D3 条形图



我想在单选按钮选择值时更新条形图。此值作为查询的参数传递,以获取相应的 JSON 数据。

代码工作正常,不包括一个方面。当我通过单击任何单选按钮选择一个值时,条形图将绘制在现有条形图的顶部。我希望每次选择新选项时都重新绘制图表。

// set the dimensions of the canvas
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var compSvg = d3.select(".company");
var companies = [];
d3.json("http://localhost:8983/solr/techproducts/select?q=popularity:[10%20TO%20*]&wt=json&fl=cat&facet=true&facet.field=cat", function(error, resp) {
var results = resp.facet_counts.facet_fields.cat;
for (var i = 0; i < 5; i++) {
var value = results[i*2];
companies.push(value);
}
});

//functions for toggling between data
function change(value){
update(value);
}
function update(comp){
var query = 'cat:"' + comp + '"';
var url = "http://localhost:8983/solr/techproducts/select?q=" + encodeURIComponent(query) + "&rows=10&fl=manu,price&wt=json"

// load the data
d3.json(url, function(error, resp) {
if (error) return console.error(error);
resp.response.docs.forEach(function(d) {
d.manu = d.manu;
d.price = +d.price;
});
// scale the range of the data
x.domain(resp.response.docs.map(function(d) { return d.manu; }));
y.domain([0, d3.max(resp.response.docs, function(d) { return d.price; })]);
// add axis
compSvg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
compSvg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price");

// Add bar chart
compSvg.selectAll("bar")
.data(resp.response.docs)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.manu); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.price); })
.attr("height", function(d) { return height - y(d.price); });
});
}

首次加载图表时,一切都按预期工作:您有一个空选择,输入选择为数据数组中的每个项目创建一个元素。您还可以附加轴。

当您使用change函数第二次加载图表时,您重复您最初创建图表所做的操作:您有一个空选择,因为selectAll("bar")将为空,并且输入选择为数据数组中的每个项目创建一个新元素。您还可以附加轴。

您需要使用更新和退出选项来正确完成此操作:

追加初始数据后,您需要使用更新选择来修改条形,使用 Enter 引入新条形(如果一个数据集使用的条形数多于另一个数据集(,以及使用退出选择来退出不需要的条形图(如果一个数据集使用的条形数少于另一个数据集(。网上有很多关于进入、更新、退出过程的信息;请记住,v4 和 v3 之间存在差异。

这看起来像:

var data = [
[1,2,3,4,5],
[6,4,3],
[5,10,1,7,1,3]
];
var i = 0;
var width = 500;
var height = 500;
var svg = d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);

var y = d3.scale.linear().range([height, 0]);
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
update(data[0]);
timer();
function update(dataset) {
// update scales
y.domain([0,d3.max(dataset, function(d) { return d; })] );
x.domain(dataset.map(function(d,i) { return i; }) );

// Bind Data
var bars = svg.selectAll(".bars")
.data(dataset);

// Update existing bars:
bars.transition()
.attr("x",function(d,i) { return x(i); })
.attr("y",function(d) { return y(d); })
.attr("width", x.rangeBand() )
.attr("height", function(d) { return height - y(d); })
.duration(1000);


// New Bars 
bars.enter()
.append("rect")
.attr("class","bars")
.attr("x",function(d,i) { return x(i); })
.attr("width", x.rangeBand() )
.attr("y",height)
.attr("height",0)
.transition() 
.attr("y",function(d) { return y(d); })
.attr("height", function(d) { return height - y(d); })
.duration(1000);;

// Un-needed Bars:
bars.exit()
.transition()
.attr("height", 0)
.duration(1000)
.remove();

}
function timer() {
setTimeout(function() { update(data[i++%3]); timer() } , 1500);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

稍作修改即可满足您的需求:

function change(value){
// erase all contents before update
compSvg.html("");
update(value);
}

最新更新