Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically update chart data in D3

I'm working on a real-time visualization of incoming data. I use D3 for the visualization and started based on this example: http://bl.ocks.org/mbostock/3883195

This is the version I'm currently working on:

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

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

  var xAxis = d3.svg.axis().scale(x).orient("bottom");
  var yAxis = d3.svg.axis().scale(y).orient("left");

  var area = d3.svg.area()
      .x(function(d) { return x(d.x); })
      .y0(height)
      .y1(function(d) { return y(d.y); });

  var svg = d3.select("div#chart").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 data = [[1,1],[2,3],[3,2],[4,4]];

  var dataCallback = function(d) {
    d.x = +d[0];
    d.y = +d[1];
  };
  data.forEach(dataCallback);

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

  svg.append("path")
      .datum(data)
      .attr("class", "area")
      .attr("d", area);

  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("Number of Messages");

This produces the following graph:

simple graph

Now, as it should update itself regularly, I wanted to dynamically update the data in the graph using the following code:

  var n = svg.selectAll("path").data([5,20])
  n.enter();
  n.exit().remove();

However, that does not work. I'm new to D3 and still learning the basics. Ideally, the graph visualization shifts to the left and the new data is shown in the graph. But so far I can't even add new data to it. Could someone help me with that? I also searched for examples similar to this, but did not found anything which really helped me so far.

like image 947
str Avatar asked Feb 19 '13 13:02

str


1 Answers

d3 is pretty good at keeping track of what data's been added and what's being removed - it does this with joins. Take a look at http://bl.ocks.org/mbostock/3808218

IF we use the data binding (instead of "datum")

svg.append("path")
  .data([data])
  .attr("class", "area")
  .attr("d", area);

and then on update do something like:

// update the list of coordinates
data.splice(0,1);
data.push([5,20]);

// re-decorate the last, newly added item
dataCallback(data[data.length - 1]);

// You will also need to update your axes
x.domain(d3.extent(data, function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);

// update the data association with the path and recompute the area
svg.selectAll("path").data([data])
    .attr("d", area);

And you should get your area to update.

You can try it out here

With the way your data is organized using the joined data (instead of datum) may not make much difference. Note that here the (single) data element you are associating with the path is the full list of coordinates so to update the area you need to pass in a new full list of coordinates.

If you really want to minimized the amount you need to redraw you could break up the area and draw each line segment. Then essentially you fall back to the bar chart example but with not-flat bars and no spacing.

like image 82
Superboggly Avatar answered Nov 07 '22 09:11

Superboggly