user6020020
user6020020

Reputation:

Line chart not aligned with x axis

I want to create a linechart using this data:

var mydata = [
  {
    "year": "2019",
    "myvalue": "50"
  },
  {
    "year": "2018",
    "myvalue": "50"
  },
  {
    "year": "2017",
    "myvalue": "NaN"
  },
  {
    "year": "2016",
    "myvalue": "NaN"
  },
  {
    "year": "2015",
    "myvalue": "10"
  },
  {
    "year": "2014",
    "myvalue": "25.6"
  },
  {
    "year": "2013",
    "myvalue": "4.2"
  },
  {
    "year": "2012",
    "myvalue": "60"
  },
  {
    "year": "2011",
    "myvalue": "826"
  },
  {
    "year": "2010",
    "myvalue": "32"
  },
  {
    "year": "2009",
    "myvalue": "50"
  },
  {
    "year": "2008",
    "myvalue": "70"
  }
];

Entire code HERE.

The chart I build works but it has some problems: some x axis ticks are missing and linechart (and circle) are not allineated to x axis (as you can see in this image):

enter image description here

Upvotes: 2

Views: 643

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

Your code needs a lot of refactor. However, addressing only the problem stated in your question, you have 3 issues here:

  1. You are applying the margins to a <g> element, and then applying it again to the axis group. Drop the translatehere:

    thisSvg.append('g')
        .attr('class', 'y axis')
        .attr('transform', 'translate(' + margin.left + ', 0)')
    
  2. You are not parsing your dates. When calling your scales the year values are strings, not date objects. Parse the dates:

    mydata.forEach(function(d) {
        d.year = parseTime(d.year)
    })
    
  3. You cannot call your axes without setting the scale's domains first.

All together, this is your code with those changes:

var mydata = [{
    "year": "2019",
    "myvalue": "50"
  },
  {
    "year": "2018",
    "myvalue": "50"
  },
  {
    "year": "2017",
    "myvalue": "NaN"
  },
  {
    "year": "2016",
    "myvalue": "NaN"
  },
  {
    "year": "2015",
    "myvalue": "10"
  },
  {
    "year": "2014",
    "myvalue": "25.6"
  },
  {
    "year": "2013",
    "myvalue": "4.2"
  },
  {
    "year": "2012",
    "myvalue": "60"
  },
  {
    "year": "2011",
    "myvalue": "826"
  },
  {
    "year": "2010",
    "myvalue": "32"
  },
  {
    "year": "2009",
    "myvalue": "50"
  },
  {
    "year": "2008",
    "myvalue": "70"
  }
];

var margin = {
  top: 10,
  right: 10,
  bottom: 50,
  left: 40
};

var svg = d3.select('#linechart')
  .append('svg')
  .attr('width', 600)
  .attr('height', 200);

var parseTime = d3.timeParse("%Y");

mydata.forEach(function(d) {
  d.year = parseTime(d.year)
})

var values = createAxisLine(svg);
var x = values[0];
var y = values[1];
var width = values[2];
var height = values[3];
var svg2 = values[4];

createChartLine(svg, x, y, width, height, svg2);

function createAxisLine(thisSvg) {
  var width = thisSvg.attr('width') - margin.left - margin.right;
  var height = thisSvg.attr('height') - margin.top - margin.bottom;

  thisSvg = thisSvg.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

  var x = d3.scaleTime()
    .rangeRound([0, width]);

  var y = d3.scaleLinear()
    .rangeRound([height, 0]);

  x.domain(d3.extent(mydata, function(d) {
    return d.year;
  }));
  y.domain([0, 1000]);

  var xAxis = d3.axisBottom(x); //.tickSize(0, 0);
  var yAxis = d3.axisLeft(y);

  thisSvg.append('g')
    .attr('class', 'x axis')
    .attr('transform', 'translate(0, ' + height + ')')
    .call(xAxis)
    .selectAll('text')
    .style('text-anchor', 'end')
    .attr('dx', '-.8em')
    .attr('dy', '.15em')
    .attr('transform', 'rotate(-65)');

  thisSvg.append('g')
    .attr('class', 'y axis')
    .call(yAxis)
    .append('text')
    .attr('transform', 'rotate(-90)')
    .attr('y', 6)
    .attr('dy', '.71em')
    .style('text-anchor', 'end');

  return [x, y, width, height, thisSvg];
}

function createChartLine(thisSvg, x, y, width, height, thisSvg) {
  var lines = thisSvg
    .attr('transform', function(d) {
      return 'translate(' + margin.left + ', ' + margin.top + ')';
    });

  var line = d3.line()
    .x(function(d) {
      return x(d.year);
    })
    .y(function(d) {
      return y(d.myvalue);
    })
    .defined(function(d) { // for missing (0) data
      if (isNaN(d.myvalue)) {
        d.myvalue = 0;
      }
      return d.myvalue !== 0;
    });

  lines.append('path')
    .data([mydata])
    .attr('class', 'mylines')
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('stroke-width', 1.5)
    .attr('d', line);

  thisSvg.append('g').attr('class', 'circles')
    .selectAll('.dot')
    .data(mydata)
    .enter()
    .append('circle')
    .attr('class', 'dot')
    .attr('cx', function(d) {
      return x(d.year);
    })
    .attr('cy', function(d) {
      return y(d.myvalue);
    })
    .attr('r', 3);
}
<script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
<div style='height:50px;'></div>
<div id='linechart'></div>

Upvotes: 3

Related Questions