D3如何获得'行的数量'从tsv数据?

时间:2014-02-24 15:54:39

标签: d3.js tsv

第一次使用D3并且我坚持认为应该简单的事情:

我正在尝试制作百分比宽度条形图SVG,我想将每个条形图的宽度设置为它将创建的“条形图”的数量。

svg.selectAll(".bar")
  .data(function(d) {return d.values;})
  .enter()
  .append("rect")
  .attr("class", "bar")
  .attr("x", function(d) { return x(d.browser); })
  .attr("width", function(d) { return (100 / d.browser.length);})
  .attr("y", function(d) { return y(d.time); })
  .attr("height", function(d) { return height - y(d.time); })
  .attr("fill", function(d) {return "#"+d.colour;})
  .on('mouseover', tip.show)
  .on('mouseout', tip.hide);

不起作用的关键部分是:.attr("width", function(d) { return (100 / d.browser.length);})

哪个不起作用。以下是我的TSV数据样本:

    test    browser time    colour
1 - attr selector   Chrome  65  fad009
1 - attr selector   Firefox 125 dd8e27
1 - attr selector   Opera   72  cc0f16
1 - attr selector   IE9 140 27b7ed
1 - attr selector   Android-4   120 80bd01
2 - attr qualified  Chrome  64  fad009
2 - attr qualified  Firefox 132 dd8e27
2 - attr qualified  Opera   78  cc0f16
2 - attr qualified  IE9 120 27b7ed
2 - attr qualified  Android-4   145 80bd01

第1列和第2列都是常量,因为它们只是5个值中的一个,而我可以在那里硬编码20%,我想正确设置它,这样我就可以添加另一组结果了空格正确。

我的JS-fu很弱,所以随意光顾我,就像你在教孩子一样;)

有什么想法吗?

进一步要求代码:

    // Adapted from http://bl.ocks.org/officeofjane/7315455
var margin = {top: 45, right: 20, bottom: 20, left: 200},
    width = 850 - margin.left - margin.right,
    height = 90 - margin.top - margin.bottom;

var formatPercent = d3.format(".0%");


var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], 0.1);

// Scales. Note the inverted domain fo y-scale: bigger is up!
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")
    .tickFormat(formatPercent);

var tip = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-10, 0])
    .html(function(d) {
        return "<strong>" + d.test + "\t" + d.browser + "</strong><br/><span style='color:#fff'>" + d.time + " ms</span>";
});

// csv loaded asynchronously
d3.tsv("data2.tsv", type, function(data) {

    // Data is nested by country
    var selectorTests = d3.nest()
        .key(function(d) { return d.test; })
        .entries(data);

    // Compute the minimum and maximum year and percent across symbols.
    x.domain(data.map(function(d) { return d.browser; }));
    y.domain([0, d3.max(selectorTests, function(s) { return s.values[0].time; })]);

    // Add an SVG element for each country, with the desired dimensions and margin.
    var svg = d3.select("#selectors").selectAll("svg")
    .data(selectorTests)
    .enter().append("svg")
    .attr({
        "width": "100%",
        "height": "100%"
    })
    .attr("viewBox", "0 0 " + width + " " + height )
    .attr("preserveAspectRatio", "xMidYMid meet")
    .attr("pointer-events", "all")

    .append("g").attr("transform", "translate(0,0)");

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g")
        .append("text")
        .attr("x", "0")
        .attr("y", '-100%')
        .attr("dy", ".71em")
        .attr("text-anchor", "start")
        .attr("font-size", "1.1em")
        .text(function(d) { return d.key;});

    // Accessing nested data: https://groups.google.com/forum/#!topic/d3-js/kummm9mS4EA
    svg.selectAll(".bar")
        .data(function(d) {return d.values;})
        .enter()
        .append("rect")
        .attr("class", "bar")
        .attr("x", function(d) { return x(d.browser); })
        .attr("width", data.length)
        .attr("y", function(d) { return y(d.time); })
        .attr("height", function(d) { return height - y(d.time); })
        .attr("fill", function(d) {return "#"+d.colour;})
        .on('mouseover', tip.show)
        .on('mouseout', tip.hide);
        svg.call(tip);
});

function type(d) {
    d.time = +d.time;
    return d;
}

如果我只使用data.length我得到'10'这是'条目'的总数(道歉我可能在这里完全不正确的术语) - 我希望/期望看到'5',因为那是每个实例创建的柱数给出数据。希望有道理吗?

1 个答案:

答案 0 :(得分:0)

我认为可视化您的数据格式化和“传播”的方式很有用:

d3.nest以这种格式返回您的数据:

[
   {key: "1 - attr selector", values: [
     {test: "1 - attr selector", browser: "Chrome", time: 65, colour: "fad009"},
     {test: "1 - attr selector", browser: "Firefox", time: 125, colour: "dd8e27"},
     ...
   ]},
   {key: "2 - attr qualified", values: [
     {test: "2 - attr qualified", browser: "Chrome", time: 64, colour: "fad009"},
     {test: "2 - attr qualified", browser: "Firefox", time: 132, colour: "dd8e27"},
     ....
   ]},
   ...
]

然后您有两个后续调用data:一个在svg定义中,另一个在您发布的第一个代码段中。在第一个元素之后,d元素的格式为

{key: "1 - attr selector", values: [
     {test: "1 - attr selector", browser: "Chrome", time: 65, colour: "fad009"},
     {test: "1 - attr selector", browser: "Firefox", time: 125, colour: "dd8e27"},
     ...
]}

这是您应该致电d.values.length以获取该特定测试的浏览器数量的地方。

第二次调用data后,您.data(function(d) {return d.values;})每个d元素的格式为

{test: "1 - attr selector", browser: "Chrome", time: 65, colour: "fad009"}

你看到,此时调用d.browser.length将返回带有浏览器名称的字符串长度 - 实际上并不是你想要的。

你必须在第二次调用data之前获得浏览器的数量,但是在调用之后你必须使用它 - 这就是问题所在。您需要获取父数据 我希望我能把问题告诉你。

谈论解决方案,有几个。我不确定,但是d3.select(this.parentNode).datum().lengthd3.select(this).node().parentNode.__data__.length或类似的内容可以代替d.browser.length。或者你可以记住一个变量中的长度(更好的是,一个数组:每个测试可能有不同数量的测试浏览器),然后使用它。