Im relatively new to d3 and nvd3 and wanted to create a simple scatterplot, just like the example but with an ordinal y-axis. So y axis values are categorical strings. This is what I thought I needed to do:
var xfun = function (d) { return d.Pos } //simple ints
, yfun = function (d) { return d.Title } //the ordinal values
var chart = nv.models.scatterChart()
.showDistX(true)
.showDistY(true)
.color(d3.scale.category10().range())
.margin({ top: 30, right: 20, bottom: 50, left: 130 })
.tooltips(false)
.x(xfun)
.y(yfun);
// create an ordinal scale with some test values
var ys = d3.scale.ordinal()
.domain(["this","is","an","ordinal","scale"])
.range(5);
// tell nvd3 to use it
chart.yAxis.scale(ys);
// add to the page
nv.addGraph(function () {
d3.select(selector).datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
However, no luck:
Error: Invalid value for <circle> attribute cy="NaN" d3.js:690
Error: Invalid value for <line> attribute y1="NaN" d3.js:690
Error: Invalid value for <line> attribute y2="NaN" d3.js:690
Error: Invalid value for <circle> attribute cy="NaN" d3.js:7532
Uncaught TypeError: Cannot read property '0' of undefined
..
And the y-axis simply shows a linear axis from -1 to 1. Iterestingly there are some circles plotted at y=-1 and y=1 (the extremes).
To manually force correct values for cy I tried adding after call(chart):
d3.selectAll("#mychart circle").attr("cy", function(d){
return = ys(yfun(d));
});
But still the same error. How do I get the ordinal scale to work properly? Note I also need it to update correctly when I use the nvd3 legend to switch between dataseries (which will contain different x/y data).
There is a related question on github, but no solution.
Update: after some debugging I tried replacing chart.yAxis.scale(ys)
with chart.scatter.y(ys)
and this gets rid of the errors. I can also drop the manual selectAll
.
However, the y-axis still shows a linear scale from 0.99-1.01 and all points are plotted at y=1. So a step closer but no ordinal scale yet.
In case somebody else stumbles upon this, here's what worked for me: instead of trying to force an ordinal scale on the axis (X, in my case), I used a linear scale, but provided a custom tickFormat function that returned the desired label.
chart.xAxis.tickFormat(function(d){
return labelValues[d];
});
Where labelValues maps between the numerical value and the desired label.