dman
dman

Reputation: 11064

D3 - tick values aren't spaced evenly with domain and range

How do I space tick values on Y axis evenly? As you can see, everything on the graph is not correct

enter image description here

          var y = d3.scaleLinear()
            .domain([0,4])
            .range([height, 0]);

          var graph = setGraphSize(attrs.graphSize);

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

          var parseDate = d3.timeParse('%H:%M');

          // converts strings to date times
          scope.curveData.meta.forEach(function(d) {
            d.timeStamp = parseDate(d.timeStamp);
            d.glucoseLevel = +d.glucoseLevel;
          });

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

          var y = d3.scaleLinear()
            .domain([0,4])
            .range([height, 0]);

          var timeStampList = scope.curveData.meta.map(function (d) { return d.timeStamp; });

          // creates X axis
          var xAxis = d3.axisBottom(x)
                        .tickValues(timeStampList)
                        .tickFormat(d3.timeFormat("%I:%M %p"))

          var glucoseLevelList = getTicks('glucoseLevel', scope.curveData);
          var yAxis = d3.axisLeft(y).tickValues(glucoseLevelList);

          var curve = d3.line()
            .x(function(d) { return x(d.timeStamp); })
            .y(function(d) { return y(d.glucoseLevel); })
            .curve(d3.curveCatmullRom.alpha(0.5));

          var divEl = element[0].querySelector('div');
          divEl.classList.add(attrs.graphSize);

          var svg = d3.select(divEl).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 + ')');


          x.domain(d3.extent(scope.curveData.meta, function(d) { return d.timeStamp; }));
          y.domain(d3.extent(scope.curveData.meta, function(d) { return d.glucoseLevel; }));

          // Add the scatterplot
          svg.selectAll("dot")
            .data(scope.curveData.meta)
            .enter().append("circle")
            .attr("r", 3.5)
            .attr("cx", function(d) { return x(d.timeStamp); })
            .attr("cy", function(d) { return y(d.glucoseLevel); });

          // Add the X Axis
          svg.append('g')
            .attr('class', 'x axis')
            .attr('transform', 'translate(0,' + height + ')')
            .call(xAxis);

          // Add the Y Axis
          svg.append('g')
            .attr('class', 'y axis')
            .call(yAxis)

          // Add the value curve path.
          svg.append('path')
            .attr('class', 'curve')
            .attr('d', curve(scope.curveData.meta));

          var graphTitle = graphTitleGenerator(scope.curveData);
          svg.append("text")
            .attr("x", (width / 2))             
            .attr("y", 0 - (margin.top / 4))
            .attr("text-anchor", "middle")  
            .style("font-size", graph.font) 
            .style("font-weight", "500") 
            .style("font-family",
              "'Roboto Mono',RobotoDraft,Helvetica,Arial,sans-serif")  
            .text(graphTitle);

Upvotes: 1

Views: 1481

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

There is nothing wrong with your axis. You set the domain using the data:

y.domain(d3.extent(scope.curveData.meta, function(d) 
    { return d.glucoseLevel; 
}));

This means that the max tick is the maximum value in your data (400), and the min tick is the minimum value in your data (33).

If you want some padding, set the domain like this:

y.domain([d3.max(scope.curveData.meta, function(d) 
    { return d.glucoseLevel; 
})*someValue],
[d3.min(scope.curveData.meta, function(d) 
    { return d.glucoseLevel; 
})*someValue]);

Where someValue is the padding, something like 1.05 and 0.95 for instance.

Now comes your question:

tick values aren't spaced evenly. How do I space tick values on Y axis evenly?

And the problem is here:

var yAxis = d3.axisLeft(y).tickValues(glucoseLevelList);

You are setting the ticks using glucoseLevelList. I bet you have only three data points here. The first solution here is just remove tickValues, but you have several other options, like using d3.ticks().

For the curve, it's expected that it's going below the x axis, not only because of the minimum domain, but because of this:

.curve(d3.curveCatmullRom.alpha(0.5));

Upvotes: 2

Related Questions