d3 Quantize Scale is the best option if you want to display the interval. However, scale maps between discrete values โโand continuous intervals. I do not 100% understand what you want to do, but let's see how I could do some of the things you mentioned in the quantization scale.
Matching integers with intervals is simple if you know that d3 uses half-open intervals [,] to split a continuous domain.
var s1 = d3.scaleQuantize() .domain([0,400]) .range([0,1,2,3]); s1.invertExtent(0);
You can also list discrete values:
var interval = s.invertExtent(0); d3.range(interval[0], interval[1]);
These are the good values โโyou specified, and since you want to display integers in integer intervals, we need rounding when the numbers are not divisible. However, we can use Math.round.
var s2 = d3.scaleQuantize() .domain([0,250]) .range([0,1,2,3]); s2.invertExtent(0);
There is no mapping from the interval itself to an integer, but the scale displays a point in the interval from the domain (which is continuous) to its value in the range.
[0, 99, 99.9999, 100, 199, 250, 399, 400].map(s1);
I also suspect that you switched the output of rangeRound from the linear scale with something else. I get
var srr = d3.scaleLinear() .domain([0,3])
and
var srr2 = d3.scaleLinear() .domain([0,4])
The result looks like a scale for us with a histogram with 50% coverage (then each position will be the midpoint of the interval equal to 132 pixels). I'm going to guess the reason is that rangeRound uses round for interpolation, not for gender.
You can also use the function designed for histograms if you want the width of the interval.
var sb = d3.scaleBand().padding(0).domain([0,1,2,3]).rangeRound([0,400]); [0,1,2,3].map(sb);
Not that it simplifies the code.
As soon as I get to the functions you implement, it seems that the requirements are much simpler. Actually there are no intervals. The problem is that there is no single mapping. The best solution is what you did, or just use two linear scales with a custom interpolator (to find the floor, not round off.
var interpolateFloor = function (a,b) { return function (t) { return Math.floor(a * (1 - t) + b * t); }; } var canvasSize = 400; var sequenceLength = 4000; var coordinateFromSequenceIndex = d3.scaleLinear() .domain([0, sequenceLength]) .range([0, canvasSize]) .interpolate(interpolateFloor); var seqIndexFromCoordinate = d3.scaleLinear() .domain([0, canvasSize ]) .range([0, sequenceLength]) .interpolate(interpolateFloor);