6

我对 d3 和 nvd3 相对较新,并且想创建一个简单的散点图,就像示例一样,但具有序数y 轴。所以 y 轴值是分类字符串。这是我认为我需要做的:

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

但是,没有运气:

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 
..

y 轴简单地显示了从 -1 到 1 的线性轴。有趣的是,在 y=-1 和 y=1(极值)处绘制了一些圆圈。

要手动强制 cy 的正确值,我尝试在调用(图表)之后添加:

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

但仍然是同样的错误。如何让序数比例正常工作?请注意,当我使用 nvd3 图例在数据系列(将包含不同的 x/y 数据)之间切换时,我还需要它正确更新。

github上有一个相关的问题,但没有解决方案。


更新:经过一些调试后,我尝试替换chart.yAxis.scale(ys)chart.scatter.y(ys),这消除了错误。我也可以放下手册selectAll

但是,y 轴仍显示 0.99-1.01 的线性比例,并且所有点都绘制在 y=1 处。所以更近了一步,但还没有序数尺度。

4

3 回答 3

6

万一其他人偶然发现了这一点,这对我有用:我没有尝试在轴上强制使用序数刻度(在我的情况下为 X),而是使用了线性刻度,但提供了一个自定义的 tickFormat 函数,该函数返回了所需的标签.

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

其中 labelValues 在数值和所需标签之间映射。

于 2014-01-10T02:28:03.543 回答
2

@robinfhu有一个简单的解决方案

不要使用序数比例!

相反,将您的x函数设置为返回元素的索引:

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

并将您的tickFormat功能设置为读取正确的标签:

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

工作示例Plunker

复制和粘贴:

  nv.models.lineChart()
    .x(function(d, i) {
      return i;
    }).xAxis
    .tickFormat(function(d) {
      return that.data[0].values[d].x;
    });
于 2016-01-27T11:37:39.297 回答
1

我没有使用过 nvd3.js,但根据我的 d3 经验,错误似乎是您规模的范围。对于序数比例,您需要为要映射到的域定义一个对应值的数组。例如,我可以设置以下比例:

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

这个比例会将我的域映射到 1:5 范围内的数字,使用“this”-> 1、“is”-> 2 等。如果我不想单独设置每个点,我也可以定义我的范围用rangePoints,如下:

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

rangePoints 为我提供了从最小指定值到最大指定值的均匀间隔的点范围,因此这将导致生成相同的范围。

我已经制作了一些圆圈来说明如何在此处执行此操作。

当您更改为不同的数据系列时,您必须更新您的域。由于范围对应于您的点映射到的页面上的位置,因此您不需要更新它,除非 nvd3.js 应用辅助映射并分两步执行 ordinalDomain -> integers -> pointLocation。

另一种选择是在函数定义中应用比例。

yfun = function (d) { return ys(d.Title) } 
于 2013-06-25T15:18:17.727 回答