【问题标题】:nvd3 scatter plot with ordinal scalenvd3 散点图与序数比例
【发布时间】:2013-06-22 05:26:32
【问题描述】:

我对 d3 和 nvd3 比较陌生,想创建一个简单的散点图,就像 example 但带有 ordinal 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上有related question,但是没有解决办法。


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

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

【问题讨论】:

  • 你检查过原始的散点图吗...你看到的圆圈不是圆圈。它们是圆形的路径 drwan :)
  • @Dom: 可能是这样,但它仍然在抱怨 svg 元素,我绝对可以在 dom 中看到它们(但所有的 cy 都有 NaN 值)

标签: javascript d3.js scatter-plot nvd3.js ordinal


【解决方案1】:

@robinfhu 有一个简单的solution

不要使用序数比例!

相反,将您的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;
    });

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 是的,这行得通。现在我需要弄清楚如何将标签旋转为垂直。
    • chart.xAxis.rotateLabels(90) 确实会根据需要旋转标签,但是根据库的标签隐藏算法,只有每第 n 个标签才会呈现,这取决于它的出现,以避免重叠。在我的例子中,每 7 个标签都会被渲染一次。
    • 您能否提供一个“数值与所需标签之间的映射”的示例?
    • @MiguelVazq 试试我的可能对你有帮助
    【解决方案3】:

    我没有使用过 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 为我提供了从最小指定值到最大指定值的均匀分布的点范围,因此这将导致生成相同的范围。

    我做了一些圈子来说明如何做到这一点here.

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

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

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

    【讨论】:

    • 谢谢。我也试过了,但没有运气。请参阅上面的编辑。似乎问题比这更早,即首先让 nvd3 真正使用序数比例。至于动态系列切换,nvd3 在多栏示例中提供了开箱即用的功能(也带有序数数据)。所以我想它也应该与这里的散点图一起使用。
    • 我明白你对 nvd3 的意思。一种可能性是在原始函数中使用 ys 在 nvd3 看到它们之前更改值。我在上面的帖子中添加了如何做到这一点。
    • 确实,在这种情况下,我对 nvd3 隐藏了它的序数比例,只返回一些整数。这确实有效,这就是我现在所拥有的。然后我可以尝试手动覆盖刻度线,但这感觉就像一个巨大的黑客:) 在 nvd3 方面也创建了一个 github 问题github.com/novus/nvd3/issues/177
    猜你喜欢
    • 1970-01-01
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多