繁体   English   中英

D3.js:计算时间尺度的条形宽度,改变范围?

[英]D3.js: calculate width of bars in time scale with changing range?

我正在构建一个带有x轴时间刻度的D3条形图。 x轴的范围可以变化。

如何为条形图上的条形指定正确的宽度? 我见过人们使用rangeBands作为序数尺度,但我不知道如何用时间尺度来做这件事。

这是我的代码:

var x = d3.time.scale().range([0, width]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
[...]

// After new data has been fetched, update the domain of x...
x.domain(d3.extent(data, function(d) { return d.date; }));
d3.select(".x.axis").call(xAxis);

// ... and draw bars for chart
var bars = svg.selectAll(".air_used")
    .data(data, function(d) { return d.date; });

bars.attr("y", function(d) { return y(d.air_used); })
.attr("height", function(d) { return height - y(d.air_used); })
.attr("x", function(d) { return x(d.date); })
.attr("width", 20) // ??

我应该把最后一行代替20?

更新:JSFiddle: http//jsfiddle.net/aWJtJ/2/

没有获得宽度的功能,但您可以很容易地计算它:

.attr("width", width/data.length);

如果您不想触摸条形,您可能希望从中减去少量金额。 您还需要相应地调整x位置,例如

.attr("x", function(d) { return x(d.date) - (width/data.length)/2; })
.attr("width", width/data.length);

为了使刻度线正确对齐,您还需要调整x轴刻度的范围,因为第一个刻度将放在第一个值:

var x = d3.time.scale().range([width/data.length/2, width-width/data.length/2]);

在这里完成jsfiddle。

尽管我同意斯科特认为条形图与x轴上的序数或分类数据一起使用,但我想问题更多的是绘制时间轴的便利性。 由于d3.time.scaled3.time.format.multi的帮助下做了很好的工作,绘制时间轴的各种持续时间(小时,天,月等)及其刻度,结合起来可能是一个好主意d3.time.scale表示轴, d3.scale.ordinal表示带宽计算。

该片段下面被激发讨论的话题在D3谷歌集团。 有序规模的单位是一天。

 function prepare(data) { var dateParse = d3.time.format('%Y-%m-%d'); data.forEach(function(v) { v.date = dateParse.parse(v.date); }); var dateValueMap = data.reduce(function(r, v) { r[v.date.toISOString()] = v.value; return r; }, {}); var dateExtent = d3.extent(data.map(function(v) { return v.date; })); // make data have each date within the extent var fullDayRange = d3.time.day.range( dateExtent[0], d3.time.day.offset(dateExtent[1], 1) ); fullDayRange.forEach(function(date) { if(!(date.toISOString() in dateValueMap)) { data.push({ 'date' : date, 'value' : 0 }); } }); data = data.sort(function(a, b) { return a.date - b.date; }); return data; } function draw(data) { var margin = { 'top' : 10, 'right' : 20, 'bottom' : 20, 'left' : 60 }; var size = { 'width' : 600 - margin.left - margin.right, 'height' : 180 - margin.top - margin.bottom }; var svg = d3.select('#chart').append('svg') .attr('width', '100%') .attr('height', '100%') .append('g') .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); var dates = data.map(function(v) { return v.date; }); var x = d3.time.scale() .range([0, size.width]) .domain(d3.extent(dates)); var y = d3.scale.linear() .range([size.height, 0]) .domain([0, d3.max(data.map(function(v) { return v.value; }))]); var xAxis = d3.svg.axis() .scale(x) .orient('bottom'); var yAxis = d3.svg.axis() .scale(y) .orient('left'); var barWidth = d3.scale.ordinal() .domain(dates) .rangeRoundBands(x.range(), 0.1) .rangeBand(); svg.append('g') .attr('class', 'x axis') .attr('transform', 'translate(' + barWidth / 2 + ',' + size.height + ')') .call(xAxis); svg.append('g') .attr('class', 'y axis') .call(yAxis) .append('text') .attr('transform', 'rotate(-90)') .attr('y', 6) .attr('dy', '.71em') .style('text-anchor', 'end') .text('Amount'); svg.selectAll('.bar') .data(data) .enter() .append('rect') .attr('class', 'bar') .attr('x', function(d) { return x(d.date); }) .attr('width', barWidth) .attr('y', function(d) { return y(d.value); }) .attr('height', function(d) { return size.height - y(d.value); }); } function getData() { return [ {'date': '2014-01-31', 'value': 5261.38}, {'date': '2014-02-02', 'value': 7460.23}, {'date': '2014-02-03', 'value': 8553.39}, {'date': '2014-02-04', 'value': 3897.18}, {'date': '2014-02-05', 'value': 2822.22}, {'date': '2014-02-06', 'value': 6762.49}, {'date': '2014-02-07', 'value': 8624.56}, {'date': '2014-02-08', 'value': 7870.35}, {'date': '2014-02-09', 'value': 7991.43}, {'date': '2014-02-10', 'value': 9947.14}, {'date': '2014-02-11', 'value': 6539.75}, {'date': '2014-02-12', 'value': 2487.3}, {'date': '2014-02-15', 'value': 3517.38}, {'date': '2014-02-16', 'value': 1919.08}, {'date': '2014-02-19', 'value': 1764.8}, {'date': '2014-02-20', 'value': 5607.57}, {'date': '2014-02-21', 'value': 7148.87}, {'date': '2014-02-22', 'value': 5496.45}, {'date': '2014-02-23', 'value': 296.89}, {'date': '2014-02-24', 'value': 1578.59}, {'date': '2014-02-26', 'value': 1763.16}, {'date': '2014-02-27', 'value': 8622.26}, {'date': '2014-02-28', 'value': 7298.99}, {'date': '2014-03-01', 'value': 3014.06}, {'date': '2014-03-05', 'value': 6971.12}, {'date': '2014-03-06', 'value': 2949.03}, {'date': '2014-03-07', 'value': 8512.96}, {'date': '2014-03-09', 'value': 7734.72}, {'date': '2014-03-10', 'value': 6703.21}, {'date': '2014-03-11', 'value': 9798.07}, {'date': '2014-03-12', 'value': 6541.8}, {'date': '2014-03-13', 'value': 915.44}, {'date': '2014-03-14', 'value': 9570.82}, {'date': '2014-03-16', 'value': 6459.17}, {'date': '2014-03-17', 'value': 9389.62}, {'date': '2014-03-18', 'value': 6216.9}, {'date': '2014-03-19', 'value': 4433.5}, {'date': '2014-03-20', 'value': 9017.23}, {'date': '2014-03-23', 'value': 2828.45}, {'date': '2014-03-24', 'value': 63.29}, {'date': '2014-03-25', 'value': 3855.02}, {'date': '2014-03-26', 'value': 4203.06}, {'date': '2014-03-27', 'value': 3132.32} ]; } draw(prepare(getData())); 
 #chart { width : 600px; height : 180px; } .bar { fill : steelblue; } .axis { font : 10px sans-serif; } .axis path, .axis line { fill : none; stroke : #000; shape-rendering : crispEdges; } .x.axis path { display : none; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <div id='chart'></div> 

我在使用基于x轴的时间序列更改条形图上的缩放级别时遇到了这个问题,并找到了两个解决方案。

1)创建一个伴随序数比例来帮助计算宽度。(痛苦)

2)时间序列x轴是你的朋友 - 用它来计算宽度。

如果你希望你的酒吧总是一个“月”宽,不管缩放级别如何,你可以做这样的事情。 我假设d.date在数据中可用。

 svg.selectAll(".air_used").attr("width", function(d.date) {
    var next = d3.time.month.offset(d.date, 1);
    return (x(next)- x(d));
  });

这很好用,因为它适用于每个缩放比例,你只需要在你的“缩放”处理程序的末尾调用这个函数,即.on(“缩放”,缩放); 此时通常会调整x轴。

由于时间尺度是连续的,因此可以有许多关于“正确”条宽度的想法。 如果您的数据点非常精细且分布不均匀,则可能需要使用固定宽度的细条来最小化重叠。 如果您提前了解了预期的数据值并且它们具有统一的粒度,那么您可以执行类似于@LarsKotthoff的操作来均匀分布它们。

要考虑的一件事是你真的想要一个时间尺度。 条形通常用于表示分类值,而不是连续刻度上的点。 也许从日期范围派生的域的序数量表实际上是您想要的。 在这种情况下,您可以根据原始帖子使用rangeBands。

不是说做你正在做的事是错的。 只是值得深思。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM