My data looks like this...
var data = [{name:'a', value : 97},
{name:'b', value : 24},
{name:'c', value : 10}];
I have an ordinal scale created like this...
var y = d3.scale.ordinal().rangeBands([0, 30 * data.length]);
and I am using it to create a basic graph like this...
chart.selectAll("rect")
.data(data)
.enter().append("svg:rect")
.attr("y", function(d,i){ return y(d.name);})
.attr("width", function(d,i){ return x(d.value);})
.attr("height", y.rangeBand());
According to the d3 docs (here) you dont HAVE to specify a domain for an ordinal scale, and it will get populated as you try to use it. In my situation however y(d.name) always returns 0 and y.rangeBand() raises an exception, even though when I look the domain array has been populated inside the scale object.
So, I have worked around this by pre-defining my domain...
.domain(data.map(function (d){ return d.name;}))
but I would like to be able to dynamically add to this domain and right now if I do, it doesn't expand beyond the original values set on creation. Is this even possible?
I'm very new to d3, so I may be missing something important here.
With rangeBands and rangePoints, you must define a domain in order to access the range. The domain tells the ordinal scale how many bands or points you want to display. However, you can change the domain later (by calling scale.domain(newDomain)
) and the range will update. You just can't do that implicitly by passing a previously-unseen value to the scale. It's generally a good idea to define domains with ordinal scales anyway, so that you always get deterministic behavior.
Elements in the domain must be unique when coerced to a string so if you're passing in an array of objects to domain, there might be unexpected results. For example, d3 might view the objects as all the same if the string representation of each object looks like "[object Object]". I've run into this problem before and the way I've worked around it is to do something like
d3.scale.ordinal(d3.range(0,myData.length)).rangeBands([0,myRangeBound])
which maps each data element to a unique array index. Keep in mind your data should be sorted if necessary before you set your scale in this case, and you'll have to reset the domain whenever your data changes. It's generally good to define a render method or the like to reset the scales and redraw everything when new data comes in, and to set the domain explicitly whenever you can.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With