mindcraft
mindcraft

Reputation: 13

d3.js multiple line chart rendering: Same dataset but different curve

I am completely new to d3.js and currently working on a multiple line chart in d3.js and therefore prepared two different datasets ("dataset", "datasetIndividual"). I noticed that the curve for the individual curve (green) differed from the points that are drawn after reload.

So in order to determine wether the problem was the curve or the dots I started using the same dataset for each curve and the problem definitely seems to be the rendering of the individual curve. After each reload sometimes the curves might completely overlap and other times differ. I am not able to determine a reason nor the solution for this particular problem. I assume it has something to do with the nesting/sequence of the code. I admit, the whole code is a bit "pedestrian".

The code for the line chart:

/*create svg element*/
var svg = d3.select('.linechart')
  .append('svg')
  .attr('width', w)
  .attr('height', h)
  .attr('id', 'chart');

/*x scale*/
var xScale = d3.scale.linear()
  .domain([0, d3.max(dataset, function(d) {
    return d[0];
  })])
  .range([padding, w - padding]);

/*y scale*/
var yScale = d3.scale.linear()
  .domain([0, d3.max(dataset, function(d) {
    return d[1];
  })])
  .range([h - padding, padding]);

/*x axis*/
var xAxis = d3.svg.axis()
  .scale(xScale)
  .orient('bottom')
  .ticks(20)
  .tickSize(0, 0)
  //.tickPadding(padding);

/*append x axis*/
svg.append('g')
  .attr({
    'class': 'xaxis',
    //'transform': 'translate(0,' + (h - padding) + ')'
    'transform': 'translate(0,' + 0 + ')'
  })
  .call(xAxis);

/*y axis*/
var yAxis = d3.svg.axis()
  .scale(yScale)
  .orient('left')
  .tickSize(0, 0)
  .tickValues([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);

/*append y axis*/
svg.append('g')
  .attr({
    'class': 'yaxis',
    'transform': 'translate(' + padding + ',0)'
  })
  .call(yAxis);


/*define line*/
var lines = d3.svg.line()
  .x(function(d) {
    return xScale(d[0])
  })
  .y(function(d) {
    return yScale(d[1])
  })
  .interpolate('monotone');


/*append line*/
var path = svg.append('path')
  .attr({
    'd': lines(dataset),
    'fill': 'none',
    'class': 'lineChart'
  });

/*get length*/
var length = svg.select('.lineChart').node().getTotalLength();

/*animate line chart*/
svg.select('.lineChart')
  .attr("stroke-dasharray", length + " " + length)
  .attr("stroke-dashoffset", length)
  .transition()
  .ease('linear')
  .delay(function(d) {
    return dataset.length * 100;
  })
  .duration(3000)
  .attr("stroke-dashoffset", 0);

/*add points*/
var points = svg.selectAll('circle')
  .data(dataset)
  .enter()
  .append('circle');

/*point attributes*/
points.attr('cy', function(d) {
    return yScale(d[1])
  })
  .style('opacity', 0)
  .transition()
  .duration(1000)
  .ease('elastic')
  .delay(function(d, i) {
    return i * 100;
  })
  .attr({
    'cx': function(d) {
      return xScale(d[0]);
    },
    'cy': function(d) {
      return yScale(d[1]);
    },
    'r': 5,
    'class': 'datapoint',
    'id': function(d, i) {
      return i;
    }
  })


.style('opacity', 1);

//  LINES INDIVIDUAL

//function drawIndividualLines (){

/*x scale*/
var xScaleIndividual = d3.scale.linear()
  .domain([0, d3.max(datasetIndividual, function(d) {
    return d[0];
  })])
  .range([padding, w - padding]);

/*y scale*/
var yScaleIndividual = d3.scale.linear()
  .domain([0, d3.max(datasetIndividual, function(d) {
    return d[1];
  })])
  .range([h - padding, padding]);

/*define line*/
var linesIndividual = d3.svg.line()
  .x(function(d) {
    return xScaleIndividual(d[0])
  })
  .y(function(d) {
    return yScaleIndividual(d[1])
  })
  .interpolate('monotone');

/*append line*/
var pathIndividual = svg.append('path')
  .attr({
    //'d': linesIndividual(datasetIndividual),
    'd': linesIndividual(dataset),
    'fill': 'none',
    'class': 'lineChartIndividual'
  });

/*get length*/
var lengthIndividual = svg.select('.lineChartIndividual').node().getTotalLength();

/*animate line chart*/
svg.select('.lineChartIndividual')
  .attr("stroke-dasharray", lengthIndividual + " " + lengthIndividual)
  .attr("stroke-dashoffset", lengthIndividual)
  .transition()
  .ease('linear')
  .delay(function(d) {
    return datasetIndividual.length * 100;
  })
  .duration(3000)
  .attr("stroke-dashoffset", 0);

/*add points*/
var pointsIndividual = svg.selectAll('circleIndividual')
  .data(dataset)
  .enter()
  .append('circle');

/*point attributes*/
pointsIndividual.attr('cy', function(d) {
    return yScale(d[1])
  })
  .style('opacity', 0)
  .transition()
  .duration(1000)
  .ease('elastic')
  .delay(function(d, i) {
    return i * 100;
  })
  .attr({
    'cx': function(d) {
      return xScale(d[0]);
    },
    'cy': function(d) {
      return yScale(d[1]);
    },
    'r': 5,
    'class': 'datapointIndividual',
    'id': function(d, i) {
      return i;
    }
  })


.style('opacity', 1);

I prepared a fiddle in hope someone of you is able to determine the source of the problem:

https://jsfiddle.net/4vf6s6e9/

I would apreciate any help. I don´t often post questions and tried to incorprate suggestions from my last experience. If you need anything from me to improve this post, feel free to tell me.

Thanks a lot in advance.

Upvotes: 0

Views: 1074

Answers (1)

Mark
Mark

Reputation: 92440

You are drawing the lines with two slightly different scales.

var xScale = d3.scale.linear()
  .domain([0, d3.max(dataset, function(d) {
    return d[0];
  })])
  .range([padding, w - padding]);

/*y scale*/
var yScale = d3.scale.linear()
  .domain([0, d3.max(dataset, function(d) {
    return d[1];
  })])
  .range([h - padding, padding]);

and

/*x scale*/
var xScaleIndividual = d3.scale.linear()
  .domain([0, d3.max(datasetIndividual, function(d) {
    return d[0];
  })])
  .range([padding, w - padding]);

/*y scale*/
var yScaleIndividual = d3.scale.linear()
  .domain([0, d3.max(datasetIndividual, function(d) {
    return d[1];
  })])
  .range([h - padding, padding]);

This makes the calculations of the position of each line just a tiny bit different and that difference depends on the random difference between the extents of the two data sets.

Passing the same data to both scales (or just using the same scale for both lines) fixes the problem. Here's an updated fiddle with that single change: https://jsfiddle.net/oa0rsvgc/

Upvotes: 1

Related Questions