简体   繁体   中英

D3js: How to generate X axis labels/ticks if data for one of axis is 0?

In my case i have dynamic data which loads into d3Js graph. everything works perfeclty if i have userdata like :

Name : bla, y: 1, x:1
Name : bla2, y: 1, x:2
Name : bla3, y: 3, x:3
Name : bla4, y: 7, x:4

but the problem comes when i have a data like this:

Name : bla, y: 0, x:1
Name : bla2, y: 0, x:2
Name : bla3, y: 0, x:3
Name : bla4, y: 0, x:4

then whole y axis have no labels at all. how do i show predefined labels in this case?

Here is the code to generate axis :

                var x = d3.scale.linear().range([0, width]);

            var y = d3.scale.linear().range([height, 0]);

            var xAxis = d3.svg.axis().scale(x).orient("bottom");

            var yAxis = d3.svg.axis().scale(y).orient("left");

                   y.domain(d3.extent(data, function(d) { return d.y; })).nice();
         x.domain([0, d3.max(data, function(d) { return d.x; })]).nice();

The problem stems not from the fact that all your values are zero, but from the fact that all your values are the same and that your domain therefore has zero width (the max and min domain values are the same).

The linear scale falls apart in this case, because you are telling to create a linear relationship such that both the start and end values of the range are equal to the same value in the domain. You don't get a divide-by-zero error like you would if your range was zero width, but you don't get a meaningful scale, or meaningful tick values.

Even the .nice() function can't help you, since it's designed to extend the domain to the next tick value after determining an appropriate tick spacing based on your domain.

Working fiddle based on your code, demonstrating the problem:
http://fiddle.jshell.net/LJdZZ/

How can you fix it? You have to force the domain's start and end points to be different. There are a few different approaches you can use, you'll have to decide which is appropriate for your data:

  • If you know that your domain is normally going to be small integers, you can add and subtract 1 from the max and min values:

     y.domain(d3.extent(data, function (d) { return dy; }).map(function(d, i) { //map the two-element array returned by d3.extent if (i) return d+1; //if i=1 return d-1; //if i=0 }); ) .nice(); 
  • If you will normally want the domain to include zero you can force it to include both zero and one:

     y.domain(d3.extent(data.concat([{y:0},{y:1}]), function (d) { return dy; })) .nice(); 
  • If your data values and scale are likely to vary such that you don't want to force any values normally, you can check if the domain width is zero and only then set a specific domain:

     y.domain(d3.extent(data, function (d) { return dy; })) .nice(); var yDomain = y.domain(); if (yDomain[0] == yDomain[1] ) { y.domain([yDomain[0], yDomain[0] + 1]) .nice(); } 

Adaption of the fiddle with the last method implemented:
http://fiddle.jshell.net/LJdZZ/1/

(You might want to make the domain check & correction a separate function that you call with the scale as a parameter. That way you can use it for both linear scales, without cluttering up your main code with extra variables.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM