score:2

Accepted answer

The problem is that, despite its name, your linear xScale is not linear (the image of 0 is 100). So when you use return xScale(d.y); for the width, you're adding 100 to the width of every rectangles (in mathematical terms, the function used is xScale(z) = 0.00211 * z + 100 : this is affine, not linear).


Edit, examples :

  • a rect starting at d.y0=0 must have x=100
  • a rect with d.y=0 must have width=0
  • a rect with d.y0=71000 (around half the sum) must have x=250 (middle of the drawing)
  • a rect with d.y=71000 must have width=150 (half the width of the drawing)

=> It is not possible to use directly the same scale for width and x position. So either you use different functions to compute width and x, or you cheat with an additional transform for x (see my original solution below).


The easiest solution is to have a range of [0,300] (instead of [100,400]), and put the drawing area within a g with .attr("transform", "translate(100,0)") to center the plot.

Second option (sounds like the one you'd prefer): use xScale(d.y0+d.y) - xScale(d.y0) for the width (instead of just xScale(d.y)). This directly computes the distance between left and right endpoints, i.e. it gives the width. It should work with any scale (not necessarily linear).

As for your second question, I don't really know another general way of doing this (other than writing your own drawing procedure, it won't be too hard). But you can easily translate a simple array into a layout-friendly one:

var dataset = [66852, 7550]
var layoutDataset = dataset.map(function(d){ return [{y:d}] });

Related Query