2013-09-16 8 views
20

私はx軸上に時間スケール付きのD3棒グラフを作成しています。 x軸の範囲は変化し得る。D3.js:変化する範囲で時間スケールの棒の幅を計算しますか?

棒グラフの棒の幅を正しく指定するにはどうすればよいですか?私は人々が順序尺度のために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の代わりに、最後の行に何を置くべきですか?

UPDATE:JSFiddleここ:http://jsfiddle.net/aWJtJ/2/

答えて

28

あり幅を取得するには何の機能はませんが、あなたは非常に簡単にそれを計算することができます。

.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をhere

+1

ありがとうございます!最初の提案はほぼそこにありますが、 'x'関数は棒の間にいくつかのパディングを挿入しているようです:http://jsfiddle.net/aWJtJ/1/もう2番目の関数を使ってみると、ほぼ正しいですが、それでもバーの間にパディングを挿入する:http://jsfiddle.net/aWJtJ/2/ - なぜ 'x'関数がバーの' x'位置がどこにあるべきか私のコードに伝えることはできませんが、理解できません幅がどんなものであるべきかをしっかりと考えているので、幅がどこにあるべきかを教えてください。 – Richard

+0

あなたが実際にもう少し必要です - 特に、最初のティックが最初の値になるので、範囲を調整する必要があります(編集された答えを参照)。なぜD3があなたに幅を教えてくれないのか分かりません。あなたは機能要求を開くことができます。 –

+0

なぜこの回答を2回upvoteできないのですか? – AperioOculus

2

時間スケールは連続しているので、「正しい」バー幅が何であるかについての多くの考えがあります。データポイントがきめ細かく不均一に分布している場合は、オーバーラップを最小限に抑えるために固定幅の細いバーを使用することができます。事前に予想されるデータ値について何かを知っていて、それらが均一な細かさであれば、@ LarsKotthoffのような何かをして均等に分散させることができます。

あなたが実際に時間スケールを望むかどうかは、考慮すべき1つのことです。バーは、一般的に、連続的なスケール上のポイントではなく、カテゴリ値を表すために使用されます。たぶん、日付範囲から派生したドメインの序数は、実際にはあなたが欲しいと思っているかもしれません。その場合、元の投稿ごとにrangeBandsを使用することができます。

あなたがしていることをするのは間違っていません。思考のためだけの食糧。

+0

ありがとう!私はティックのために時間フォーマットを使用したいのでタイムスケールを使用する必要があります:https://github.com/mbostock/d3/wiki/Quantitative-Scales#wiki-linear_tickFormat – Richard

+2

フォーマットが唯一の理由で、既知の数の離散値を使用すると、序数に日付を渡す前に日付を文字列として書式設定できます。もちろん、スケーリングの前に、すべての日付データを同じ方法で文字列にフォーマットすることに注意する必要があります。おそらく共有ゲッター関数などが必要です。または、早い段階でデータを文字列に変換します。時間データ型のセマンティクスが必要かどうかは本当に依存します。 –

+0

ところで、D3の時間パーサーとフォーマッタは、スケールに関係なく使用することができます:https://github.com/mbostock/d3/wiki/Time-Formatting –

3

棒グラフはx軸上の序数またはカテゴリデータと一緒に使用されることに同意していますが、時間軸を描くのに便利です。 d3.time.scaleは、様々な時間(時、日、月など)の描画時間軸とそのティックのd3.time.format.multiの助けを借りて実際に良い仕事をしているので、d3.time.scaleを軸に、d3.scale.ordinalをバンドに結合することをお勧めします幅の計算。

以下のスニペットは、D3 Googleグループのトピックについてのthe discussionに触発されています。序数の単位は1日です。

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>

2

I時系列基づいて、X軸と棒グラフのズームレベルを変更する場合、この問題に遭遇した2つの溶液を発見しました。。

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軸はこの時点で調整されています。

関連する問題