Anna Melzer
Anna Melzer

Reputation: 1613

D3 line chart clipped y axis

I am trying to build a chart in d3 and it works easily in the fiddle. However, when I put the code into my actual implementation the resulting svg element is cut of on the top and on the left. I played around with size and margins but somehow, nothing changes.

Here is the fiddle with the working code and the pasted svg as my actual implementation provides: http://jsfiddle.net/16jjdyt1/5/

An here is a picture of the output I am getting: enter image description here And here is the code from my actual implementation.

 function updateGraph(data) {
  var selector = "#" + id + " .chart svg";

  // NOTE this is a hack, sometimes chart is null!
  if (!_.isEmpty(data.primary)) {

    d3.selectAll(selector + " > *").remove();


    var width = 400,
      height = 140;
    var margin = {top: 30, right: 60, bottom: 30, left: 50}

    var parseDate = d3.time.format('%d.%m.%y %H:%M').parse;
    var x = d3.time.scale().range([0, width]);
    var y0 = d3.scale.linear().range([height, 0]);
    var y1 = d3.scale.linear().range([height, 0]);


    // ticks
    var xAxis = d3.svg.axis().scale(x)
        .orient("bottom").tickFormat(function(d) {
          return d3.time.format('%d.%m.%y %H:%M')(new Date(d))
        })
        .ticks(5); // TODO change this

    var yAxisLeft = d3.svg.axis().scale(y0)
        .orient("left").tickFormat(d3.format(',.2f'));

    var yAxisRight = d3.svg.axis().scale(y1)
        .orient("right").tickFormat(d3.format(',.2f'));

    // function for left aligned lines
    var valueline = d3.svg.line()
        .x(function(d) { return x(d.x); })
        .y(function(d) { return y0(d.y); })
        .interpolate("cardinal").tension(0.8);

    // function for right aligned lines
    var valueline2 = d3.svg.line()
        .x(function(d) { return x(d.x); })
        .y(function(d) { return y1(d.y); })
        .interpolate("cardinal").tension(0.8);

d3.select(selector)
        .attr("width", width + margin.left + margin.right + 20)
        .attr("height", height + margin.top + margin.bottom +20)
        .append("g")
          .attr("transform","translate(" + margin.left + "," + margin.top + ")");


    // TODO refactor this
  var x_values = [];
  var y0_values = [];
  var y1_values = [];



  _.each(data.primary, function(d){
      _.each(d.values, function(f){
          x_values.push(f.x);
          y0_values.push(f.y);
      });
  });   // TODO refactor this!

  _.each(data.secondary, function(d){
      _.each(d.values, function(f){
          x_values.push(f.x);
          y1_values.push(f.y);
      });
  });   // TODO refactor this!

  x.domain(d3.extent(x_values)); // scale  x axis
  y0.domain(d3.extent(y0_values)); // scale  y axis 1
  y1.domain(d3.extent(y1_values)); // scale y axis 2


  // Add left aligned graphs
  data.primary.forEach(function(d){
    d3.select(selector).append("path")
      .style("stroke", d.color) 
      .attr("d",valueline(d.values));
  });

  // Add right aligned graphs
  data.secondary.forEach(function(d){
    d3.select(selector).append("path")
      .style("stroke", d.color)
      .attr("d",valueline2(d.values));
  });



  d3.select(selector).append("g")            // Add the X Axis
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);


  d3.select(selector).append("g") // Add first y axis
      .attr("class", "y axis")
      .call(yAxisLeft);

  d3.select(selector).append("g") // Add second y axis
      .attr("class", "y axis")
      .attr("transform", "translate(" + width + " ,0)")
      .call(yAxisRight);


  }
}

return timechart;
  };

I have no idea where this error might lay so I am happy for any hints with this. Thanks in advance!

Upvotes: 0

Views: 892

Answers (1)

Henry S
Henry S

Reputation: 3112

Your paths, axis etc should be sitting inside the gelement, like this::

<g transform="translate(50,30)">
    // in 'test', chart goes here
</g>

However, in you 'output' version, the chart elements are all after the g:

<g transform="translate(50,30)"></g>
// in 'output', chart goes here

In the code for you actual implementation, you first append that g to the selector (which is the svg element) ...

d3.select(selector)
    .attr("width", width + margin.left + margin.right + 20)
    .attr("height", height + margin.top + margin.bottom +20)
    .append("g")
        .attr("transform","translate(" + margin.left + "," + margin.top + ")");

And then you append other bits, which will go after, rather than being nested inside, the translated g, like this:

d3.select(selector).append("g")            // Add the X Axis
  .attr("class", "x axis")

To avoid this, one thing you could do is define an id for the g, and select that to use to add your axis and paths to, eg:

d3.select(selector)
    .attr("width", width + margin.left + margin.right + 20)
    .attr("height", height + margin.top + margin.bottom +20)
    .append("g")
        .attr("transform","translate(" + margin.left + "," + margin.top + ")")
        .attr("id", "selector_g";

and then

d3.select("#selector_g").append("g")            // Add the X Axis
  .attr("class", "x axis")

Upvotes: 1

Related Questions