在d3.js中按顺序刻度绘制具有相同值的多个水平线

时间:2017-03-31 14:22:34

标签: d3.js data-visualization

我有一个如下所示的数组:

[
   {
      "name": "Omayeli Arenyeka",
      "positions":[
         {
            "start": 1993,
            "end": 2002,
            "title":"Senator of Abia"
         },
         {
            "start": 1993,
            "end": 2002,
            "title":"President"
         }
      ]
   },
   {
      "name": "John Cena",
      "positions":[
         {
            "start": 1993,
            "end": 2002,
            "title":"Senator of Abia"
         },
         {
            "start": 2004,
            "end": 2007,
            "title":"President"
         }
      ]
   }
];

My graph currently looks like this

对于y轴上的每个名称,我想为位置数组中的每个项目绘制,横跨x轴的水平线(因此对于Omayeli Arenyeka,从1993年开始然后在2002年结束,然后是另一个从2003-2007开始的行)我不希望连接线。

这就是我目前所拥有的:

var parseDate = d3.time.format("%Y").parse;
var maxyear = new Date("2017");
var minyear = new Date("1980");

var xScale = d3.time.scale()
 .domain([minyear, maxyear])    
 .range([padding, width - padding]);  

var yScale = d3.scale.ordinal()
 .range([height - padding, padding]);   // map these to the chart  height, less padding.  
//REMEMBER: y axis range has the bigger number first because the y value of zero is at the top of chart and increases as you go down.

// define the y axis
var yAxis = d3.svg.axis()
 .orient("left")
 .scale(yScale);

// define the y axis
var xAxis = d3.svg.axis()
 .orient("bottom")
 .scale(xScale)
 .tickFormat(d3.time.format("%Y")); // <-- format

 d3.json("data/politicians.json", function(error, data) {
  if (error) throw error;

  yScale.domain(data.map(function(d) { 
   console.log(d.name);
   return d.name; 
  })).rangeRoundBands([0, height - padding]);

 // draw x axis with labels and move to the bottom of the chart area
 vis.append("g")
   .attr("class", "xaxis")   // give it a class so it can be used to select only xaxis labels  below
   .attr("transform", "translate(0," + (height - padding) + ")")
   .call(xAxis);

// draw y axis with labels and move in from the size by the amount of padding
vis.append("g")
  .attr("class", "yaxis")
  .attr("transform", "translate(" + padding + ",0)")
  .call(yAxis)
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", -36)
  .attr("x", -36)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Politicians");

var line = {
  'x1':(function(d) { 
    return xScale(); 
  }),
  'y1':(function(d) { return yScale(d.name); }),
  'x2':(function(d) { 
    return xScale(); 
  }),
  'y2':(function(d) { return yScale(d.name); }),
}

});

1 个答案:

答案 0 :(得分:0)

D3中最重要的是将数据绑定到元素。关于这一点,你有很多参考资料。

简而言之,您需要输入&#34;输入&#34;选择。

在这里,我将设置两个输入选择:一个为每个政治家创建<g>个元素,另一个为每个政治家为每个位置创建<line>元素:

var groups = vis.selectAll("foo")
    .data(data)
    .enter()
    .append("g")
    .attr("transform", function(d) {
        return "translate(0," + (padding[2] + yScale(d.name)) + ")";
    });

var people = groups.selectAll("foo")
    .data(d => d.positions)
    .enter()
    .append("line");

因此,我们使用d.named.startd.end附加行。这是演示:

&#13;
&#13;
var data = [{
  "name": "Omayeli Arenyeka",
  "positions": [{
    "start": 1993,
    "end": 2002,
    "title": "Senator of Abia"
  }, {
    "start": 1993,
    "end": 2002,
    "title": "President"
  }]
}, {
  "name": "John Cena",
  "positions": [{
    "start": 1993,
    "end": 2002,
    "title": "Senator of Abia"
  }, {
    "start": 2004,
    "end": 2007,
    "title": "President"
  }]
}];

var width = 500,
  height = 200,
  padding = [10, 10, 30, 130];

var color = d3.scale.category10();

var vis = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

var parseDate = d3.time.format("%Y").parse;
var maxyear = new Date("2017");
var minyear = new Date("1980");

var xScale = d3.time.scale()
  .domain([minyear, maxyear])
  .range([padding[3], width - padding[1]]);

var yScale = d3.scale.ordinal()
  .rangePoints([height - padding[2], padding[0]], 1.5)
  .domain(data.map(function(d) {
    return d.name;
  })); // map these to the chart  height, less padding.  
//REMEMBER: y axis range has the bigger number first because the y value of zero is at the top of chart and increases as you go down.

// define the y axis
var yAxis = d3.svg.axis()
  .orient("left")
  .scale(yScale);

// define the y axis
var xAxis = d3.svg.axis()
  .orient("bottom")
  .scale(xScale)
  .tickFormat(d3.time.format("%Y")); // <-- format


// draw x axis with labels and move to the bottom of the chart area
vis.append("g")
  .attr("class", "xaxis") // give it a class so it can be used to select only xaxis labels  below
  .attr("transform", "translate(0," + (height - padding[2]) + ")")
  .call(xAxis);

// draw y axis with labels and move in from the size by the amount of padding
vis.append("g")
  .attr("class", "yaxis")
  .attr("transform", "translate(" + padding[3] + ",0)")
  .call(yAxis);

var groups = vis.selectAll("foo")
  .data(data)
  .enter()
  .append("g")
  .attr("transform", function(d) {
    return "translate(0," + (yScale(d.name)) + ")";
  })
  .style("stroke", (d, i) => color(i));

var people = groups.selectAll("foo")
  .data(d => d.positions)
  .enter()
  .append("line");

var line = people.attr({
  'x1': function(d) {
    return xScale(parseDate(d.start.toString()));
  },
  'x2': function(d) {
    return xScale(parseDate(d.end.toString()));
  }
}).attr("stroke-width", 2);
&#13;
.xaxis line, .yaxis line,
.xaxis path, .yaxis path {
  fill: none;
  stroke: black;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;