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

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

本文关键字:何生成 记号 标签 数据 如果 D3js 一个      更新时间:2023-09-26

在我的例子中,我有加载到d3Js图中的动态数据。如果我有像这样的用户数据,一切都很好

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

问题不是源于所有值都为零,而是源于所有的值都相同,因此域的宽度为零(域的最大值和最小值相同)。

在这种情况下,线性比例会分解,因为您要创建一个线性关系,以便范围的开始值和结束值都等于域中的相同值。如果范围为零宽度,则不会得到除以零的误差,但不会得到有意义的刻度或有意义的记号值。

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

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

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

  • 如果你知道你的域通常是小整数,你可以从最大值和最小值中加1和减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/

(您可能想将域检查和校正作为一个单独的函数,将小数位数作为参数调用。这样,您就可以将其用于两个线性小数位数,而不会用额外的变量扰乱主代码。)