LoginSignup
12
10

More than 5 years have passed since last update.

サンプルで確認するD3の配列メソッド

Last updated at Posted at 2015-07-17

D3.js には便利な関数がたくさんある感じなんですけど、 英語のページ をみてもよく分からんし 日本語の解説ページ を見ても難しくて分からん。ってことで、サンプル動かして動作を確認してみましたよ。

やっぱりデータ見たほうがわかりやすいですね。

全体的な感じからすると、Undefined を許容したりしなかったりソートされてることが前提って関数が多いんで、配列操作のときは事前にソートと値なしの排除をしとくのが確かっぽいですね。
ちなみに Array.sort() だと辞書順にならんでしまいますので、 d3.ascending() を使うのが確実です。

よく使いそうな関数には☆をつけて、ハマリポイントがありそうな関数には注釈のコメント入れてます。

D3: ARRAY METHODS

Ordering

d3.ascending(a, b) ☆

var a = 10,
    b = 1;
p(d3.ascending(a, b)); // return: 1
var c = undefined;
p(d3.ascending(a, c)); // return: NaN
var d = "-";
p(d3.ascending(a, d)); // return: NaN

d3.descending(a, b) ☆

var a = 10,
    b = 2;
p(d3.descending(a, b)); // return: -1

d3.min(array[, accessor])

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.min(a)); // return: 0
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.min(a, function(d, i) {
  return parseInt(d) + 1;
})); // return: 1

d3.max(array[, accessor])

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.max(a)); // return: 10
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.max(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 14

d3.extent(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.extent(a)); // return: 0,10
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.extent(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 0,14

d3.sum(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.sum(a)); // return: 15
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.sum(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 28

d3.mean(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.mean(a)); // return: 3
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.mean(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 5.6

d3.median(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.median(a)); // return: 2
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.median(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 5

d3.quantile(numbers, p)

var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                        // return: ["0",1,10,"2",2,null]
p(d3.quantile(a, 0.5));      // return: 6
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                        // return: ["0",1,"2",2,10,null]
p(d3.quantile(a, 0.5));      // return: 2
var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                        // return: ["0",1,10,"2",2,null]
p(d3.quantile(a, 0.75));     // return: 2
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                        // return: ["0",1,"2",2,10,null]
p(d3.quantile(a, 0.75));     // return: 8

d3.bisecLeft(array, x[, lo[, hi]])

var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                         // return: ["0",1,10,"2",2,null]
p(d3.bisectLeft(a, 3));       // return: 5
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                         // return: ["0",1,"2",2,10,null]
p(d3.bisectLeft(a, 3));       // return: 4
p(d3.bisectLeft(a, 3, 2, 3)); // return: 3

d3.bisect(array, x[, lo[, hi]]), d3.bisectRight(array, x[, lo[, hi]])

右側(後ろ)から調べてるようで配列の最後に Undefined があると期待した値が返ってきません。

var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                              // return: ["0",1,10,"2",2,null]
p(d3.bisect(a, 3));                // return: 6
p(d3.bisectRight(a, 3));           // return: 6
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                              // return: ["0",1,"2",2,10,null]
p(d3.bisect(a, 3));                // return: 6
p(d3.bisectRight(a, 3));           // return: 6
p(d3.bisect(a, 2));                // return: 6
p(d3.bisectRight(a, 2));           // return: 6
var b = a.filter(function(d, i) {
  return d != undefined;
});
p(b);                              // return: ["0",1,"2",2,10]
p(d3.bisect(b, 2));                // return: 4
p(d3.bisectRight(b, 2));           // return: 4
p(d3.bisect(b, 1));                // return: 2
p(d3.bisectRight(b, 1));           // return: 2
p(d3.bisect(b, 1, 3, 4));          // return: 3
p(d3.bisectRight(b, 1, 3, 4));     // return: 3

d3.bisector(accessor)

右側(後ろ)から調べてるようで配列の最後に Undefined があると期待した値が返ってきません。

var bisect = d3.bisector(function(d) { return d; }).right;
var bisectLeft = d3.bisector(function(d) { return d; }).left;
var a = ["0", 1, undefined, 2, 10, "2"];
p(a);                             // return: ["0",1,null,2,10,"2"]
p(bisect(a, 2));                  // return: 6
a.sort();
p(a);                             // return: ["0",1,10,"2",2,null]
p(bisect(a, 2));                  // return: 6
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                             // return: ["0",1,"2",2,10,null]
p(bisect(a, 2));                  // return: 6
var b = a.filter(function(d, i) {
  return d != undefined;
});
p(b);                             // return: ["0",1,"2",2,10]
p(bisect(b, 2));                  // return: 4
p(bisectLeft(b, 2));              // return: 2
p(bisect(b, 3));                  // return: 4
p(bisectLeft(b, 3));              // return: 4

d3.bisector(comparator)

右側(後ろ)から調べてるようで配列の最後に Undefined があると期待した値が返ってきません。

var bisect = d3.bisector(function(d) { return d; }).right;
var bisectComparator = d3.bisector(function(a, b) { return b - a; }).right;
var a = ["0", 1, undefined, 2, 10, "2"];
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
var b = a.filter(function(d, i) {
  return d != undefined;
});
p(b);                      // return: ["0",1,"2",2,10]
p(bisect(b, 2));           // return: 4
p(bisectComparator(b, 2)); // return: 5

d3.shuffle(array)

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.shuffle(a)); // return: ["0",1,"2",10,null,2]
p(d3.shuffle(a)); // return: [null,1,10,"2",2,"0"]
p(d3.shuffle(a)); // return: [null,2,"2",10,"0",1]

Associative Arrays

d3.keys(object)

var o = {
  b: 54,
  a: 30,
  c: 12
};
p(o);          // return: return: {"b":54,"a":30,"c":12}
p(d3.keys(o)); // return: ["b","a","c"]

d3.values(object)

var o = {
  b: 54,
  a: 30,
  c: 12
};
p(o);            // return: return: {"b":54,"a":30,"c":12}
p(d3.values(o)); // return: [54,30,12]

d3.entries(object)

var o = {
  b: [54, 34, 89],
  a: [30, 34, 59],
  c: [30, 12, 12]
};
p(o);             // return: {"b":[54,34,89],"a":[30,34,59],"c":[30,12,12]}
p(d3.entries(o)); // return: [{"key":"b","value":[54,34,89]},{"key":"a","value":[30,34,59]},{"key":"c","value":[30,12,12]}]

Maps

d3.map([object[, key])

キーを指定しないと数字の添字になってしまいますので、キーを指定する関数は必ず入れたほうがいいでしょう。
また、重複した要素があるときにキーを指定した時としない時では結果が違います。

var o = d3.map([{name: "foo"}, {name: "bar"}]);
p(o); // {"_":{"0":{"name":"foo"},"1":{"name":"bar"}}}
var m = d3.map([{name: "foo"}, {name: "bar"}, {name: "bar"}]);
p(m); // {"_":{"0":{"name":"foo"},"1":{"name":"bar"},"2":{"name":"bar"}}}
    m = d3.map([{name: "foo"}, {name: "bar"}, {name: "bar"}], function(d) { return d.name; });
p(m); // {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}

map.has(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);            // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.has("foo")); // return: true
p(m.has("baz")); // return: false

map.get(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);            // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.get("foo")); // return: {"name":"foo"}
p(m.get("baz")); // return: undefined

map.set(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m); // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
m.set("foo", {"name": "test"});
m.set("baz", {"name": "foo"});
p(m); // return: {"_":{"foo":{"name":"test"},"bar":{"name":"bar"},"baz":{"name":"foo"}}}

map.remove(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m); // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
m.remove("foo");
p(m); // return: {"_":{"bar":{"name":"bar"}}}

map.keys()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);        // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.keys()); // return: ["foo","bar"]

map.values()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);          // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.values()); // return: [{"name":"foo"},{"name":"bar"}]

map.entries()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);           // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.entries()); // return: [{"key":"foo","value":{"name":"foo"}},{"key":"bar","value":{"name":"bar"}}]

map.forEach(function)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);        // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
m.forEach(function(k, v) {
  p([k, v]); // return: ["foo",{"name":"foo"}], return: ["bar",{"name":"bar"}]
});

map.empty()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);                  // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.empty());          // return: false
p(d3.map([]).empty()); // return: true

map.size()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);                 // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.size());          // return: 2
p(d3.map([]).size()); // return: 0

Sets

d3.set([array]) ☆

配列の深さが違う場合にもゴニョゴニョしてくれる感じですけど、カンマ区切りの値になってしまうようです。

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a); // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
var a = d3.set([["foo"], ["bar", "baz"]]);
p(a);     // return: {"_":{"foo":true,"bar,baz":true}}

set.has(value)

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);        // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.has(2)); // return: true
p(a.has(3)); // return: false

set.add(value) ☆

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);     // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
a.add(5);
p(a);     // return: {"_":{"0":true,"1":true,"2":true,"5":true,"10":true,"undefined":true}}

set.remove(value)

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);     // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
a.remove(1);
p(a);     // return: {"_":{"0":true,"2":true,"10":true,"undefined":true}}

set.values() ☆

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);          // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.values()); // return: ["0","1","2","10","undefined"]

set.forEach(function)

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);          // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
a.forEach(function(v) {
    p(v); // return: "0", return: "1", return: "2", return: "10", return: "undefined"
});

set.empty()

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);                  // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.empty());          // return: false
p(d3.set([]).empty()); // return: true

set.size()

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);                 // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.size());          // return: 5
p(d3.set([]).size()); // return: 0

Array Operators

d3.merge(arrays)

var a = d3.merge([ [1], [2, 3] ]);
p(a); // return: [1,2,3]
var a = d3.merge([ [1], [2, 3], [5, [2,3]] ]);
p(a); // return: [1,2,3,5,[2,3]]

d3.range([start, ]stop[, step]) ☆

start <= range < stop という関係のようですのでちょっと注意が必要です。

var a = d3.range(5);
p(a);                     // return: [0,1,2,3,4]
p(d3.range(10, 100, 10)); // return: [10,20,30,40,50,60,70,80,90]

d3.permute(array, indexes) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(a);                        // return: ["0", 1, undefined, 2, 10, "2"]
p(d3.permute(a, [2, 5, 1])); // return: [null,"2",1]
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
p(a);                             // return: [0,1,2,3,4,5,6,7,8,9]
p(d3.permute(a, d3.range(3, 6))); // return: [3,4,5]

d3.zip(arrays...) ☆

要素数が足りない場合は配列が作成されない模様。

var a = d3.zip(["a", "b"], [1, 6], [2, 7], [3, 8]);
p(a); // return: [["a",1,2,3],["b",6,7,8]]
var a = d3.zip(["a", "b"], [1, 6, 10], [2, 7], [3, 8]);
p(a); // return: [["a",1,2,3],["b",6,7,8]]
var a = d3.zip(["a", "b", "c"], [1, 6], [2, 7], [3, 8]);
p(a); // return: [["a",1,2,3],["b",6,7,8]]

d3.transpose(matrix)

var a = d3.transpose([["a", 1, 11], ["b", 2, 12], ["c", 3, 13]]);
p(a); // return: [["a","b","c"],[1,2,3],[11,12,13]]

d3.d3.pairs(array)

var a = d3.pairs(["0", 1, undefined, 2, 10, "2"]);
p(a); // return: [["0",1],[1,null],[null,2],[2,10],[10,"2"]]

Nest

d3.nest()

var n = d3.nest();
p(n); // return: {}

nest.entries(array)

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .entries(o);
p(n); // return: [{"key":"foo","val":10},{"key":"bar","val":30},{"key":"baz","val":20}]

nest.key(function)

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "bar", "val": 15},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .entries(o);
p(n); // return: [{"key":"foo","values":[{"key":"foo","val":10}]},{"key":"bar","values":[{"key":"bar","val":30},{"key":"bar","val":15}]},{"key":"baz","values":[{"key":"baz","val":20}]}]

nest.sortKeys(comparator) ☆

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .sortKeys(d3.ascending)
          .entries(o);
p(n); // return: [{"key":"bar","values":[{"key":"bar","val":30}]},{"key":"baz","values":[{"key":"baz","val":20}]},{"key":"foo","values":[{"key":"foo","val":10}]}]

nest.sortValues(comparator)

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "bar", "val": 15},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .sortValues(function(a, b) {p([a, b]); return d3.ascending(a.val, b.val);})
          .entries(o);
p(n); // return: [{"key":"foo","values":[{"key":"foo","val":10}]},{"key":"bar","values":[{"key":"bar","val":15},{"key":"bar","val":30}]},{"key":"baz","values":[{"key":"baz","val":20}]}]

nest.rollup(function) ☆

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "bar", "val": 15},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .sortKeys(d3.ascending)
          .rollup(function(d) {
            var val = 0;
            d.forEach(function(v) {
              val += v.val;
            });
            return val;
          })
          .entries(o);
p(n); // return: [{"key":"bar","values":45},{"key":"baz","values":20},{"key":"foo","values":10}]

nest.map(array[, mapType])

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .map(o, d3.map);
p(n); // return: {"_":{"foo":[{"key":"foo","val":10}],"bar":[{"key":"bar","val":30}],"baz":[{"key":"baz","val":20}]}}
12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10