Nvd3 scatter plot with ordinal scale

Im relatively new to d3 and nvd3 and wanted to create a simple scatterplot like, but with an ordinal y-axis. Thus, the y axis values โ€‹โ€‹are categorical strings. This is what I thought was necessary 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 just shows the linear axis from -1 to 1. There are several circles in Yerevo, built on y = -1 and y = 1 (extremes).

To manually enter the correct values โ€‹โ€‹for cy, I tried adding after the call (diagram):

 d3.selectAll("#mychart circle").attr("cy", function(d){ return = ys(yfun(d)); }); 

But still the same mistake. How to get a normal scale for proper operation? 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 will get rid of errors. I can also refuse the selectAll .

However, the y axis still shows a linear scale from 0.99-1.01, and all points are shown at y = 1. So, the step is closer, but not an ordinal scale.

+6
source share
3 answers

In case someone else stumbles upon this, this worked for me: instead of trying to force the ordinal scale on the axis (X, in my case), I used a linear scale, but provided a custom tickFormat function that returned the desired one label.

 chart.xAxis.tickFormat(function(d){ return labelValues[d]; }); 

Where labelValues โ€‹โ€‹displays between a numeric value and the desired label.

+6
source

There is an easy solution @robinfhu .

Do not use ordinal scale!

Instead, set the function x to return the index of the element:

 chart.x(function(d,i){ return i;}) 

And set the tickFormat function to read the corresponding label:

 tickFormat(function(d) {return that.data[0].values[d].x;}) 

Working example : Plunker

Copy and paste:

  nv.models.lineChart() .x(function(d, i) { return i; }).xAxis .tickFormat(function(d) { return that.data[0].values[d].x; }); 
+2
source

I have not used nvd3.js, but from my experience with d3, the error seems to be a range on your scale. For the ordinal scale, you need to define an array of corresponding values โ€‹โ€‹for the domain on which it will be displayed. For example, I could set the following scale:

 var myScale = d3.scale.ordinal() .domain(['this','is','an','ordinal','scale']) .range([1,2,3,4,5]) 

This scale will map my domain to numbers in the range 1: 5, with 'this' โ†’ 1, 'is' โ†’ 2, etc. If I did not want to set each point separately, I could also define my range using ranges, as shown below:

 var myScale = d3.scale.ordinal() .domain(['this','is','an','ordinal','scale']) .rangePoints([1,5]) 

rangePoints gives me a uniformly distributed range of points from the minimum setpoint to the maximum setpoint, so this will create the same range.

I made a few circles that illustrate how to do this here.

When you move on to another series of data, you will need to update your domain. Since the range corresponds to where your points are displayed on the page, you will not need to update it if nvd3.js does not use secondary matching and does not make ordinalDomain โ†’ integers โ†’ pointLocation in two stages.

Another option is to apply scale in the definition of a function.

 yfun = function (d) { return ys(d.Title) } 
+1
source

Source: https://habr.com/ru/post/948058/


All Articles