サンプルデータを生成する
サンプルデータって必要ですよね。そんな時の方法です
var size = 24 * 7 * 14, mean = 100, stdev = 20;
var norm = d3.random.normal(mean, stdev);
var data = d3.range(0,size).map(function(d, id){
return {
id: id,
age: 0|Math.random() * 40 + 20,
gender: Math.random() > 0.5 ? 'male' : 'female',
score: norm()
}
});
データをネスト化する
何度も繰り返しする作業をやってくれるメソッドで一番使うのがコレです
便利なのでperlに移植したほどです(もう少し拡充させる予定)
var data;
var nested = d3.nest().key(function(d){ return d.gender;})
.key(function(d){ return 0|d.age / 10; }).entries(data);
データをネスト化する(map)
var nestedMap = d3.nest().key(function(d){ return d.gender;})
.key(function(d){ return 0|d.age / 10; }).map(data);
nestの注意点
- keyが全部、stringになります。年月日とかをkeyでとった時にノリでDateとして扱おうとすると当然エラーになります
- entriesの時の子要素はchildrenじゃなくてvaluesです。d3.layout.hierarchy系のlayoutを使うときは、
.children()
APIでchildren属性を指定する必要があります。
.map()
は便利なようでイマイチ使い道がありません(d3では)
2データ間の間を埋める
「色のグラデーション欲しいわー」とか「この2点間を時系列合わせて埋めたいわー」って時に使うのが、.interpolate()
です。これも実は.interpolateString()
,.interpolateNumber()
,.interpolateRgb()
,.interpolateHsl()
,.interpolateLab()
,.interpolateHcl()
,.interpolateArray()
,.interpolateObject()
とファミリーがあってたまにハマります。
.interpolate()
だいたいの場合は、「数値→色的な奴→文字列→配列→オブジェクト」の内部でよきにやってくれています
d3.interpolators = [
d3_interpolateObject,
function(a, b) { return Array.isArray(b) && d3_interpolateArray(a, b); },
function(a, b) { return (typeof a === "string" || typeof b === "string") && d3_interpolateString(a + "", b + ""); },
function(a, b) { return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb(|hsl()/.test(b) : b instanceof d3_Color) && d3_interpolateRgb(a, b); },
function(a, b) { return !isNaN(a = +a) && !isNaN(b = +b) && d3_interpolateNumber(a, b); }
];
はまるケース
1要素の配列でinterpolateArrayが適用されると信じるケース
var a = [0], b = [10];
var ip = d3.interpolate(a, b);
ip(0);
!isNaN(a = +a)
適当に必要に応じてinterpolateArrayを明示的に使っていたんですがissueおくっておいた
時系列に合わせて埋める
var data = [
{date: new Date(2013, 0, 1), value: 10},
{date: new Date(2013, 0, 11), value: 100}
];
var interpolate = d3.interpolate(data[0], data[1]);
var interpolater = d3.time.days(data[0].date, data[1].date).map(function(d){
return interpolate( (d - data[0].date) / 86400000 / d3.time.days(data[0].date, data[1].date).length) );
});
data.splice(0, 0, interpolater);
簡単ですね!(ェ
_人人人人人人人_
> うそです! <
 ̄Y^Y^Y^Y^Y^Y ̄
ハマりどころ
- interplateは内部でオブジェクトのリファレンスを使いまわします!issue:1030
- spliceは配列で置換要素を受け取れません!
回避策
var interpolater = d3.time.days(data[0].date, data[1].date).map(function(d){
return JSON.parse(JSON.stringify(interpolate( (d - data[0].date) / 86400000 / d3.time.days(data[0].date, data[1].date).length) )) ;
});
interpolated.unshift(0, 0);
data.splice.apply(data, interpolater);
簡単ですね!