在d3.js中将x轴与刻度标记对齐 [英] Line up x-axis with tick marks in d3.js

查看:153
本文介绍了在d3.js中将x轴与刻度标记对齐的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何正确地将x轴值对齐到图表中的垂直线?目前,他们没有正确对齐。

  var data = [
{
due:89.99,
datestr :2012-12-01 00:00:00,
paid:89.99
},
{
due:89.99,
datestr :2013-01-01 00:00:00,
paid:101.25
},
{
due:109.99,
datestr:2013-02-01 00:00:00,
paid:143.69
},
{
due:109.99,
datestr:2013-03-01 00:00:00,
paid:130.65
},
{
due:139.99,
datestr:2013-04-01 00:00:00,
paid:150.25
},

{
到期 149.99,
datestr:2013-05-01 00:00:00,
paid:139.99
},
{
:149.99,
datestr:2013-06-01 00:00:00,
paid:139.99
},
{
:89.99,
datestr:2013-07-01 00:00:00,
paid:139.99
}
]




//将值加载到新数组中

var amtDue = new Array();
var amtPaid = new Array();

for(var i = 0; i amtDue [i] = data [i] .due;
amtPaid [i] = data [i] .paid;
}

//边距,宽度和高度。
var margin = {top:20,right:20,bottom:60,left:50},
width = 1000,
height = 400,
padding = 100;

//秤。
var x = d3.time.scale()。range([0,width]);
var y = d3.scale.linear()。range([height,0]);
var due = d3.scale.linear()。range([0,width]);
var paid = d3.scale.linear()。range([0,width]);


//域名
x.domain([d3.min(data,function(d){return d.date;}),d3.max (d){return d.date;})]);
y.domain([50,300]);
due.domain([0,amtDue.length]);
paid.domain([0,amtPaid.length]);

//构造我们的SVG对象。
var svg = d3.select(。system-efficiency)。append(svg)
.attr(width,width + margin.left + margin.right)
.attr(height,height + margin.top + margin.bottom)
.append(g)
.attr(transform,translate(+ margin.left + + margin.top +))

// X轴MONTHS。
var xAxis = d3.svg.axis()
.scale(x)
.orient(top)
.tickSize(-height)
.tickFormat (d3.time.format('%b'));
svg.append(g)
.attr(class,x axis)
.attr(transform,translate(100,+ 0 +) )
.call(xAxis);

// X轴到期日期
var dDate = d3.svg.axis()
.scale(due)
.orient(bottom)
.tickSize(0)
.tickFormat(function(d,i){return amtDue [i];});
svg.append(g)
.attr(class,damount axis)
.attr(transform,translate ))
.call(dDate);

// X轴付费日期
var pDate = d3.svg.axis()
.scale(付费)
.orient(bottom)
.tickSize(0)
.tickFormat(function(d,i){return amtPaid [i];});
svg.append(g)
.attr(class,pamount axis)
.attr(transform,translate )+))
.call(pDate);

// Y轴
var yAxis = d3.svg.axis()
.scale(y)
.orient(left)
.tickSize(0);

svg.append(g)
.attr(class,y axis)
.attr(transform,translate ,0))
.call(yAxis);

//日期解析。
var parseDate = d3.time.format(%Y-%m-%d%H:%M:%S);
data.forEach(function(d){
d.date = parseDate.parse(d.datestr);
d.close = + d.close;
});

//设置缩放域。
x.domain(d3.extent(data,function(d){return d.date;}));
//y.domain([0,d3.max(data,function(d){return d.due;})]);

//调用x轴。
d3.select(。x.axis)
//.transition().duration(1000)
.call(xAxis);


//绘制条应付金额。
var bars = svg.selectAll(rect)
.data(data,function(d){return d.datestr;});

bars.exit()。remove();

// bars.transition()。duration(1000)
// .attr(x,function(d){return x(d.date);})
// .attr(width,width / data.length)
// .attr(y,function(d){return y(d.due);})
/ / .attr(height,function(d){return height - y(d.due);});

bars.enter()。append(rect)
.attr(class,duebar)
.attr(width,width / data。 length)
.attr(x,function(d,i){return i *(width / data.length);})
.attr(y,height)
.attr(height,0)
.transition()。duration(1000)
.attr(y,function(d){return y(d.due);})
.attr(height,function(d){return(y(d.due)+3)-y(d.due);});



//行函数。
var line = d3.svg.line()
.x(function(d){return x(d.date);})
.y (d.paid);});


//绘制线。
svg.append(path)
.datum(data)
.attr(class,line)
.attr(d,line);

这是



代码是:

  //从数据的第一个日期 - 不要硬编码! 
var previousdate = new Date(2012-12-01 00:00:00)

bars.enter()。append(rect)
.attr class,duebar)
.attr(width,function(d,i){
widthval = x(d.date) - (x(previousdate));
previousdate = d.date;
return widthval;
})
.attr(x,function(d,i){
xval = x(previousdate);
previousdate = d.date;
console.log(previousdate);
return xval;
})
...

请注意,此代码突出显示另一个问题:条形图显示在2个日期之间显示数据,但实际上显示在特定时间点的数据。 12月的应付金额值未显示,而1月13日的值在图表中显示为Dec和Jan之间的柱状图。您需要决定如何显示此


How can I properly line up the x-axis values to the vertical lines in the chart? Currently they are not properly aligned.

var data = [
  {
    "due": 89.99, 
    "datestr": "2012-12-01 00:00:00", 
    "paid": 89.99
  }, 
  {
    "due": 89.99, 
    "datestr": "2013-01-01 00:00:00", 
    "paid": 101.25
  }, 
  {
    "due": 109.99, 
    "datestr": "2013-02-01 00:00:00", 
    "paid": 143.69
  }, 
  {
    "due": 109.99, 
    "datestr": "2013-03-01 00:00:00", 
    "paid": 130.65
  }, 
  {
    "due": 139.99, 
    "datestr": "2013-04-01 00:00:00", 
    "paid": 150.25
  },

  {
    "due": 149.99, 
    "datestr": "2013-05-01 00:00:00", 
    "paid": 139.99
  },
  {
    "due": 149.99, 
    "datestr": "2013-06-01 00:00:00", 
    "paid": 139.99
  },
  {
    "due": 89.99, 
    "datestr": "2013-07-01 00:00:00", 
    "paid": 139.99
  }
];




//Load values into new arrays

var amtDue = new Array();
var amtPaid = new Array();

for(var i=0; i < data.length; i++) {
  amtDue[i] = data[i].due;
  amtPaid[i] = data[i].paid;
}

// Margins, width and height. 
var margin = {top: 20, right: 20, bottom: 60, left: 50},
    width = 1000,
    height = 400,
    padding = 100;

// Scales.
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var due = d3.scale.linear().range([0, width]);
var paid = d3.scale.linear().range([0, width]);


//Domains
x.domain([d3.min(data, function(d) { return d.date; }), d3.max(data, function(d) { return d.date;})]);
y.domain([50, 300]);
due.domain([0, amtDue.length]);
paid.domain([0, amtPaid.length]);

// Construct our SVG object.
var svg = d3.select(".system-efficiency").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// X-axis MONTHS.
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("top")
    .tickSize(-height)
    .tickFormat(d3.time.format('%b'));
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(100," + 0 + ")")
    .call(xAxis);

//X-axis Due Date
var dDate = d3.svg.axis()
    .scale(due)
    .orient("bottom")
    .tickSize(0)
    .tickFormat(function(d, i) {return amtDue[i];});
svg.append("g")
    .attr("class", "damount axis")
    .attr("transform", "translate(100," + (height) + ")")
    .call(dDate);

//X-axis Paid Date
var pDate = d3.svg.axis()
    .scale(paid)
    .orient("bottom")
    .tickSize(0)
    .tickFormat(function(d, i) {return amtPaid[i];});
svg.append("g")
    .attr("class", "pamount axis")
    .attr("transform", "translate(100," + (height+20) + ")")
    .call(pDate);

//Y-axis
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickSize(0);

svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + 0 + ",0)")
    .call(yAxis);

// Date parsing.
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S");
data.forEach(function(d) {
  d.date = parseDate.parse(d.datestr);
  d.close = +d.close;
});

// Set scale domains. 
x.domain(d3.extent(data, function(d) { return d.date; }));
//y.domain([0, d3.max(data, function(d) { return d.due; })]);

// Call x-axis. 
d3.select(".x.axis")
    //.transition().duration(1000)
    .call(xAxis);


// Draw bars for amount due. 
var bars = svg.selectAll("rect")
        .data(data, function(d) { return d.datestr; });

bars.exit().remove();

// bars.transition().duration(1000)
//     .attr("x", function(d) { return x(d.date); })
//     .attr("width", width / data.length)
//     .attr("y", function(d) { return y(d.due); })
//     .attr("height", function(d) { return height - y(d.due);});

bars.enter().append("rect")
    .attr("class", "duebar")
    .attr("width", width/data.length)
    .attr("x", function(d, i) {  return i * (width / data.length); })
    .attr("y", height)
    .attr("height", 0)
    .transition().duration(1000)
    .attr("y", function(d) { return y(d.due); })
    .attr("height", function(d) { return (y(d.due)+3)-y(d.due);});



// Line function.
var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.paid); });


// Draw line. 
 svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);

This is the fiddle.

解决方案

Fiddle here: http://jsfiddle.net/henbox/hbmwbnx6/

Using your current approach, this is sort-of-fixable. To start with, you have 8 data values (Dec '12 to July '13). Using the d3.time.scale() with that date domain will give you 8 'month' tick, but a scale divided into 7 equal 'gaps' between the ticks.

So for the d3.scale.linear() scales to line up, you should use:

due.domain([0, amtDue.length - 1]);

rather than:

due.domain([0, amtDue.length]);

because the array length counts from 1, not 0.

Also note that from your code I removed several horizontal translate's.

The reason I say this is only a sort-of-fix, is that the bars for "amount due" don't line up correctly with the months. That's because the bar widths are equal (using .attr("width", width/(data.length -1))) but months (on the d3.time scale) are not of equal length:

The solution to this would be to use the x (time) scale to define the bar width

Update

Here's an update of the fiddle with a (slightly hacky) solution to the bar width issue by taking the current date and previous date values from the data: http://jsfiddle.net/henbox/hbmwbnx6/1/

Code is:

// The first date from your data - don't hardcode!
var previousdate = new Date("2012-12-01 00:00:00")

bars.enter().append("rect")
    .attr("class", "duebar")
    .attr("width", function(d, i) { 
        widthval = x(d.date) - (x(previousdate));
        previousdate = d.date;
        return widthval;
    })
    .attr("x", function(d, i) { 
        xval = x(previousdate);
        previousdate = d.date;
        console.log(previousdate);
        return xval;
    })
    ...

Note that this code highlights another issue: Bars appear to show data between 2 dates, but actually show data at a specific point in time. The December '12 'amount due' value isn't shown, while the Jan '13 value is shown as the bar between Dec and Jan in your chart. You'd need to decide how you wanted to display this

这篇关于在d3.js中将x轴与刻度标记对齐的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆