新数据的D3JS刷新图

时间:2015-12-08 05:55:41

标签: javascript html d3.js svg

我正在尝试通过调用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>

3 个答案:

答案 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

希望这有帮助!