D3js:如果其中一个轴的数据为0,如何生成X轴标签/刻度?

时间:2014-04-27 21:36:04

标签: javascript d3.js

在我的情况下,我有动态数据加载到d3Js图表。如果我有像user这样的用户数据,那么一切都很完美:

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

但问题来自于我有这样的数据:

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

然后整个y轴根本没有标签。在这种情况下如何显示预定义标签?

以下是生成轴的代码:

                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();

1 个答案:

答案 0 :(得分:2)

问题不在于所有值都为零的事实,而在于所有值都相同并且域的宽度为零(最大和最小域值相同)这一事实。

在这种情况下,线性刻度会分崩离析,因为您要告诉您创建一个线性关系,使得范围的起始值和结束值都等于域中的相同值。如果范围为零宽度,但没有得到有意义的比例或有意义的刻度值,则不会出现除零错误。

即使.nice()函数也无法帮助您,因为它设计为在根据您的域确定合适的节拍间距后将域扩展到下一个刻度值

根据您的代码工作小提琴,演示问题:
http://fiddle.jshell.net/LJdZZ/

你怎么解决?您必须强制域的起点和终点不同。您可以使用几种不同的方法,您必须决定哪种方法适合您的数据:

  • 如果你知道你的域通常是小整数,你可以从最大值和最小值中加减1:

    y.domain(d3.extent(data, function (d) {
            return d.y;
        }).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();
    
  • 如果您通常希望域包含零,则可以强制它包含零和一:

    y.domain(d3.extent(data.concat([{y:0},{y:1}]), function (d) {
            return d.y;
        }))
    .nice();
    
  • 如果您的数据值和比例可能会发生变化,以至于您不想正常强制任何值,则可以检查域宽是否为零,然后才设置特定域:

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

使用最后实施的方法改编小提琴:
http://fiddle.jshell.net/LJdZZ/1/

(您可能希望将域检查和校正作为一个单独的函数,您可以使用比例作为参数调用。这样,您可以将它用于两个线性比例,而不会使用额外的变量使主代码混乱。)