我正在尝试通过调用update来更新带有新csv文件(data2.csv)的图形,但图形没有变化。下面的代码是单击按钮时调用的函数。
Plnkr是示例代码..
建议!
http://plnkr.co/edit/pOYqmaOxy1lmY82jlhfA
<script>
function update(){
d3.csv("data2.csv", function(error, data) {
if (error) throw error;
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.State; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.ages, function(d) { return d.value; }); })]);
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("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
}
</script>
答案 0 :(得分:1)
您说您希望使用更新功能更新现有图表,并在某些事件发生后更新来自csv的新数据,对吗?
D3代表数据驱动文档,因此绘制图形时数据非常重要。 D3根据您要显示的数据使用选择(或集合,如果它更适合您)。
假设你想要一个显示以下数组的条形图:[10,20,30]。条的高度与数组中的数据一致。
创建新元素
如果您的页面上没有条形元素,则表示您需要添加&#39;他们到图表。这通常使用类似于:
的代码模式来完成svg.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
使用此代码,您可以获取svg变量(基本上是包含一个元素的d3选择,svg)并选择所有&#34; rect&#34;页面上但在svg元素内的元素。在这个时刻没有,请记住,你将创造它们。在selectAll之后,您会看到data函数,该函数指定将绑定到元素的数据。您的数组包含3个数据,这意味着您希望看到3个数据条。 D3如何知道?这是因为 .enter()(意思是:哪些元素还没有出现在图表上?)和 .append(元素)函数。 enter函数基本上意味着:在我当前的d3选择中(selecAll(&#39; rect&#39;)),我需要追加多少个指定的元素?由于您当前的选择是空的(您还没有&#39; rect&#39;元素),并且d3在您的数据函数中发现了3个数据,使用.append()它将为您创建和附加3个元素。使用attr功能,您可以指定元素的外观。
更新元素
假设我的[10,20,30]数组突然变为[40,50,60]。注意到这里非常重要的东西,我的数组仍然包含3个数据!只是他们的价值发生了变化!
我真的很想看到我的酒吧反映这个更新! (我认为你的情况与此相符)。
但如果我再次使用这种模式,会发生什么?
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x1.rangeBand())
...
state.selectAll(&#34; rect&#34;)选择包含3个元素,d3检查你有多少数据(仍然是3),它看到它不需要附加任何东西!
这是否意味着您无法使用D3进行更新?绝对不!它会比你想象的要简单得多:-)。
如果我想更新我的栏,以便它们的高度反映我的数据的新值,我应该这样做:
state.selectAll("rect")
.data(function(d) { return d.ages; })
.attr("height", function(d) { return height - y(d.value); });
基本上,我选择了所有我的作品,我告诉d3我正在处理什么数据然后我只是告诉d3改变我的矩阵的高度。你甚至可以通过过渡来做到这一点! (有关转换的更多信息here)。 我认为这是你需要做的,而不是追加&#34; rect&#34;元素再次。
更新元素,第2部分
继续我的例子,如果我的阵列突然变成这样的话怎么办:[100,200,300,400]?请注意我的值再次改变但是那里有一个额外的元素!!
好吧,当处理更改数据的事件(例如单击按钮或提交数据)时,您需要告诉D3它需要附加内容并更新现有的条形图。这可以通过对两种模式进行编码来完成:
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.attr("height", function(d) { return height - y(d.value); });
删除元素
如果我的数据阵列突然只包含2个数据怎么办:[10,20]?
就像有一个函数告诉d3它需要附加某些东西,你可以告诉它它如何处理似乎没有数据被绑定的元素:
svg.selectAll("rect")
.data(function(d) { return d.ages; })
.exit().remove();
退出功能会匹配您拥有的数据量与所选元素的数量。然后退出函数告诉d3删除这些元素。
我希望这有用。这是一个基本的解释(它稍微复杂一点)但我必须快点,所以如果有问题或错误,请告诉我。
答案 1 :(得分:0)
d3.csv("data2.csv", function(error, data) {
如果您的服务器正在缓存此引用 - 请尝试Math.random()
:D
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
这将强制(ish)刷新数据 - 可能成本很高,因此可以根据您的需求通过服务器端进程进行分类
编辑:
d3.csv("data2.csv?=" + (Math.random() * (100 - 1) + 1), function(error, data) {
将是改动。它草率但说明了如何暗示强制缓存刷新
答案 2 :(得分:0)
你可以这样做:
制作一个buildMe()
函数来制作图表。
function buildMe(file) {//the file name to display
d3.csv(file, function(error, data) {
if (error) throw error;
var ageNames = d3.keys(data[0]).filter(function(key) {
return key !== "State";
});
data.forEach(function(d) {
d.ages = ageNames.map(function(name) {
return {
name: name,
value: +d[name]
};
});
});
x0.domain(data.map(function(d) {
return d.State;
}));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.ages, function(d) {
return d.value;
});
})]);
svg.selectAll("g").remove();//remove all the gs within svg
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("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) {
return "translate(" + x0(d.State) + ",0)";
});
state.selectAll("rect")
.data(function(d) {
return d.ages;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.name);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d) {
return color(d.name);
});
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
});
}
然后在加载时执行此buildMe("data.csv");
在按钮上单击执行此操作
function updateMe() {
console.log("Hi");
buildMe("data2.csv");//load second set of data
}
工作代码here
希望这有帮助!