-
Notifications
You must be signed in to change notification settings - Fork 47
Arrays
Wiki ▸ API Reference ▸ Core ▸ Arrays
D3를 데이터를 시각화 하기 위해서 사용할 때, 일반적으로 배열 조작 을 많이 하게 된다. 이건 D3의 공식적인 데이터 표현이 배열이기 때문이다. 배열 조작은 일반적으로 배열에서 인접한 조각을 부분집합으로 취득, 서술 함수를 사용해서 배열을 필터링, 변환 함수를 사용해서 배열을 동일 선상 값들과 매핑과 같은 작업을 포함한다. D3가 배열 작업을 위해 제공하는 유틸리티들을 보기전에 자바스크립트의 배열 관련 빌트인 메서드에 먼저 익숙해져야 한다.
다음은 배열을 변경하는 **mutator method(setter)**들이다.
- array.reverse - 배열 원소의 순서를 역순으로 바꾼다.
- array.shift - 배열의 첫 원소를 제거한다.
- array.sort - 배열 원소를 정렬한다.
- array.splice - 배열에 원소를 추가하거나 제거한다.
- array.unshift - 배열의 앞쪽에 하나 이상의 원소를 추가한다.
다음은 배열의 한 형태를 반환하는 **accessor method(getter)**이다.
- array.concat - 배열을 다른 배열이나 값과 합친다.
- array.join - 배열의 모든 원소를 문자열로 합친다.
- array.slice - 배열의 일부를 추출한다.
- array.indexOf - 배열에서 찾는 값의 첫 위치를 찾는다.
- array.lastIndexOf - 배열에서 찾는 값의 마지막 위치를 찾는다.
끝으로, 배열의 원소별로 함수를 적용하는 iteration method다.
- array.filter - 콜백 함수가 true에 해당하는 원소만 신규 배열로 생성한다.
- array.forEach - 배열의 각 원소별로 콜백 함수를 호출한다.
- array.every - 배열의 모든 원소가 콜백 함수에 합당한지를 검사한다.
- array.map - 배열의 모든 원소에 콜백 함수를 적용한 결과로 신규 배열을 생성한다.
- array.some - 배열의 원소중에 하나라도 콜백 함수에 합당한지를 검사한다.
- array.reduce - 배열을 왼쪽에서 오른쪽으로 값을 하나씩 줄여가면서 콜백 함수를 적용한다.
- array.reduceRight - 배열의 오른쪽에서 왼쪽으로 값을 하나씩 줄여가면서 콜백 함수를 적용한다.
# d3.ascending(a, b)
a 가 b 보다 작으면 -1, a 가 b 보다 크면 1, 같으면 0을 반환한다. 이 함수는 natural order 위한 비교 함수다. 오름차순 정렬로 원소를 나열하기 위해서 자바스크립트 빌트-인 배열 메서드인 sort와 조합해서 사용할 수 있다.
function(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
자바스크립트에는 빌트-인 sort 메서드에 지정할 비교 함수가 없다. sort 메서드의 기본 정렬은 natural이 아닌 lexicographic(alphabetical) 정렬이고 숫자 배열을 정렬 할 때도 오류를 유발할 수 있다.
lexicographic order는 왼쪽에서 오른쪽으로 한 글자씩 비교하며 알파벳 순으로 정렬하는 방식을 의미한다. 그래서 ["1", "10", "2", "3", ] 처럼 정렬된다.
# d3.descending(a, b)
a 가 b 보다 크면 -1, a 가 b 보다 작으면 1, 같으면 0을 반환한다. 이 함수는 reverse natural 정렬을 위한 비교 함수다. 내림차순 정렬로 원소를 나열하기 위해서 자바스크립트 빌트인 배열 메서드인 sort와 조합해서 사용할 수 있다.
function(a, b) {
return b < a ? -1 : b > a ? 1 : 0;
}
자바스크립트에는 빌트 인 sort 메서드에 지정할 비교 함수가 없다. sort 메서드의 기본 정렬은 natural이 아닌 lexicographic(alphabetical) 정렬이고 숫자 배열을 정렬 할 때도 오류를 유발할 수 있다.
# d3.min(array[, accessor])
전달인자 array 에서 natural 정렬 기준으로 최소값을 반환한다. 배열이 비었으면 undefined를 반환한다. 최소값 계산전에 array.map(accessor) 처럼 적용하고 싶으면 accessor 함수를 옵션으로 사용할 수 있다. 이 메서드는 자바스크립트 빌트-인 메서드 Math.min와는 달리 undefined 값를 무시한다. 이 메서드는 데이터의 범위를 고려하면서 scale의 입력 범위를 계산하는데 유용하다. 그리고 배열 원소는 numeric 정렬이 아니라 natural 정렬을 사용해 비교된다. 예를 들어, ["20", "3"]의 최소값은 "20"이고 [20, 3]의 최소값은 3이다.
# d3.max(array[, accessor])
전달인자 array 에서 natural 정렬 기준으로 최대값을 반환한다. 배열이 비어있으면 undefined를 반환한다. 최대값 계산전에 array.map(accessor) 처럼 적용하고 싶으면 accessor 함수를 옵션으로 사용할 수 있다. 이 메서드는 자바스크립트 빌트-인 메서드 Math.max와는 달리 undefined 값를 무시한다. 이 메서드는 데이터의 범위를 고려하면서 scale의 입력 범위를 계산하는데 유용하다. 그리고 배열 원소는 numeric 정렬이 아니라 natural 정렬을 사용해 비교된다. 예를 들어, ["20", "3"]의 최대값은 "3"이고 [20, 3]의 최대값은 20이다.
# d3.extent(array[, accessor])
전달인자 array 배열을 natural 정렬을 사용해서 최대, 최소값을 반환한다. 이 메서드는 d3.min과 d3.max를 동시에 호출한 것과 같다.
# d3.sum(array[, accessor])
전달인자 array 배열 원소의 합을 반환한다. 배열이 비였으면 0을 반환한다. 합을 계산하기전에 arrary.map(accessor) 처럼 적용하고 싶으면 accessor 함수를 옵션으로 사용할 수 있다. 이 메서드는 NaN과 undefined 같은 유효하지 않은 값은 무시한다. 그래서 유효한 값만으로 데이터를 합산하는 계산에 유용하다.
# d3.mean(array[, accessor])
전달인자 array 원소들의 평균을 반환한다. 배열이 비였으면 undefined를 반환한다. 평균을 계산하기 전에 array.map(accessor) 처럼 적용하고 싶으면 accessor 함수를 옵션으로 사용할 수 있다. 이 메서드는 NaN과 undefined 같은 유효하지 않은 값은 무시한다. 그래서 유효한 값만으로 데이터를 평균내는 계산에 유용하다.
# d3.median(array[, accessor])
R-7알고리즘을 사용해서 전달인자 array 배열의 원소들의 중앙값을 반환한다. 배열이 비어있으면 undefined를 반환한다. 중앙값을 계산하기전에 array.map(accessor) 처럼 적용하고 싶으면 accessor 함수를 옵션으로 사용할 수 있다. 이 메서드는 NaN과 undefined 같은 유효하지 않은 값은 무시한다. 그래서 유효한 값만으로 데이터 중앙값을 계산에 유용하다.
# d3.quantile(numbers, p)
전달인자 numbers 배열을 정렬해서 p-quantile를 반환한다. 전달인자 p 는 [0,1] 사이의 숫자이다. 예를 들어 중앙값은 p = 0.5를 사용하면 계산할 수 있다. p = 0.25이면 1/4 지점 값은, p = 0.75이면 3/4 지점 값이다. 이런 독특한 구현은 R 프로그래밍과 액셀의 기반인 R-7 알고리즘을 사용한다. 이 메서드는 인자인 numbers 는 원소가 숫자형이여야 하고 d3.ascending같은 메서드를 사용해서 오름차순으로 사전에 정렬이 되어있어야 한다.
# d3.bisectLeft(array, x[, lo[, hi]])
전달인자 array 배열에서 그 정렬 순서하의 x 의 삽입위치. lo 와 hi 는 사용될 기본 전체 배열로 결정되야 하는 배열의 하위집합을 지정하기 위해 사용한다. x 가 이미 array 안에 있다면, 삽입 위치는 이미 존재하는 원소의 앞이 된다. (왼쪽에 해당함.) 반환 값이 array 가 이미 정렬되어있다는 가정하에 splice의 첫 번째 전달인자로 사용할 수 있다. 왼쪽은 array.slice(lo, i)의 v 가 모두 v < x 이고 오른쪽은 array.slice(i, hi)의 v 가 모두 v >= x 이도록 반한된 삽입 지점 i가 array 를 둘로 나눈다.
# d3.bisect(array, x[, lo[, hi]])
# d3.bisectRight(array, x[, lo[, hi]])
bisectLeft와 비슷하지만 array 에 이미 존재하는 x 의 오른쪽 지점을 삽입 지점으로 반환한다. 왼쪽은 array.slice(lo, i)의 v 가 모두 v <= x 이고 오른쪽은 array.slice(i, hi)의 v 가 모두 v > x 이도록 반한된 삽입 지점 i가 array 를 둘로 나눈다.
# d3.bisector(accessor)
전달인자 accessor 함수를 사용한 이등분 객체을 반환한다. 반환 객체에는 bisectLeft와 bisectRight와 유사한 left
, right
프로퍼티가 있다. 이 메서드는 단순한 원소 배열이 아닌 객체 배열 분할에 사용할 수 있다. 예를 들어 다음같은 객체 배열이 있다면,
var data = [
{date: new Date(2011, 1, 1), value: 0.5},
{date: new Date(2011, 2, 1), value: 0.6},
{date: new Date(2011, 3, 1), value: 0.7},
{date: new Date(2011, 4, 1), value: 0.8}
];
적절한 분할 함수를 생성한다.
var bisect = d3.bisector(function(d) { return d.date; }).right;
그리고나서 bisect(data, new Date(2011, 1, 2))
를 적용해서 색인을 얻는다.
# d3.shuffle(array)
Fisher–Yates shuffle를 사용해서 전달인자 array 의 순서를 랜덤하게 만든다.
# d3.first(array[, comparator])
Returns the lowest element in the specified array, as ordered by the specified comparator. If no comparator is specified, d3.ascending is used. This method is similar to d3.min, except you can use an arbitrary comparator, rather than mapping array elements to a numeric value.
# d3.last(array[, comparator])
Returns the highest element in the specified array, as ordered by the specified comparator. If no comparator is specified, d3.ascending is used. This method is similar to d3.max, except you can use an arbitrary comparator, rather than mapping array elements to a numeric value.
자바스크립트에는 배열 말고도 범용 데이터 타입으로 연관 배열이 있다. 연관 배열에는 명명된 프로퍼티들이 있고 간혹 더 단순한 객체일 때도 있다. 이 타입은 자바에서는 map, 파이썬에서는 dictionary에 해당한다. 자바스크립트의 연관배열은 키(또는 프로퍼티 명)로 순환하기 위한 표준 메카니즘으로 for…in loop을 지원하지만 정렬을 할 수 없으므로 정렬을 할 수 있도록 D3가 연관 배열을 표준 색인 배열로 변환하는 몇가지 연산자를 제공한다.
# d3.keys(object)
전달인자로 넘어온 객체(연관 배열)의 프로퍼티 명을 가진 배열을 반환한다. 반환 배열은 정렬되지 않은 상태다.
# d3.values(object)
전달인자로 넘어온 객체(연관 배열)의 프로퍼티 값을 가진 배열을 반환한다. 반환 배열은 정렬되지 않은 상태다.
# d3.entries(object)
전달인자로 넘어온 객체(연관 배열)의 프로퍼티 명과 값을 가진 배열을 반환한다. 각 배열 원소는 {key: "foo", value: 42}처럼 key와 value 속성을 가진 객체다. 반환 배열은 정렬되지 않은 상태다.
자바스크립트에서 일반 객체를 map으로 사용하고자 하면, 내장 프로퍼티 명이 키로 사용될 때 예상치 못한 동작(unexpected behavior)이 일어날 수 있다. 예를 들어 object["__proto__"] = 42
라고 지정할 경우 여러분이 기대하는 동작은 일어나지 않으며, 키가 맵 안에 정의되었는지를 알아보기 위해 조회를 시도할 때도 마찬가지다. 즉, 일반 객체는 Object prototype에서 hasOwnProperty 메서드를 상속하기 때문에 "hasOwnProperty" in object
는 true를 반환한다. 이런 문제를 피하기 위해서 ES6은 simple maps and sets를 제안한 상태이며 주류 브라우저들이 이 콜랙션들을 지원할 때 까지는 d3.map을 사용하는게 좋다.
주의: ES6이 제안한 map과는 달리, d3.map은 아직 key를 위해서 항등 비교(===, !==)대신에 문자열로 강제 변환하는 일반 비교(==, !=)를 사용한다.
# d3.map([object])
신규 맵을 생성한다. object 전달인자를 넘기면 object 의 모든 열거형 프로퍼티를 맵으로 복사한다.
# map.has(key)
전달인자 key 에 해당하는 원소가 맵에 있으면 true를 반환한다. key에 해당하는 값이 있으나 null이거나 undefined일 수는 있다.
# map.get(key)
전달인자 key 에 해당하는 값을 반환한다. key에 해당하는 원소가 맵에 없으면 undefined를 반환한다.
# map.set(key, value)
전달인자 key 에 value 를 지정하고 그 value 를 반환한다. 맵에 이미 동명의 원소가 있으면, 새로운 값으로 대체 된다.
# map.remove(key)
맵에 전달인자 key 에 해당하는 원소가 있으면 제거하고 true를 반환한다. 없으면 아무일도 하지 않고 false를 반환한다.
# map.keys()
맵의 모든 원소의 key를 문자열 배열로 반환한다. 반환 key의 순서는 임의로 결정된다.
# map.values()
맵의 모든 원소의 값을 배열로 반환한다. 반환 값의 순서는 임의로 결정된다.
# map.entries()
맵의 모든 원소의 키-값 객체를 배열로 반환한다. 반환 원소들의 순서는 임의로 결정된다.
# map.forEach(function)
맵의 각 원소별로 function 를 호출한다. 이 함수는 원소의 key와 value를 전달인자로 갖는다. function 의 this
컨텍스트는 해당 맵이다. 반환값은 undefined이며 순회 순서는 임의로 결정된다.
# d3.split(array[, function])
Splits the specified array into multiple arrays at breakpoints identified by the specified function. If no breakpoint function is specified, the array will be split at any null or undefined values, equivalent to the following function:
function breakpoint(d) {
return d == null;
}
Elements that are identified as breakpoints, as by the function returning a truthy value, will not be included in the returned arrays. (In the future, a more general API might use a breakpoint function that takes two arguments and decides whether to split them, and also gives some indication as to whether to include those two values in the split arrays…)
This method is often used in conjunction with the line shape, such that missing data points are elided; each contiguous slice of the array where the data is defined is rendered as a line segment.
# d3.merge(arrays)
전달인자 arrays 를 하나의 배열로 합쳐준다. 이 메서드는 배열 빌트-인 메서드 concat과 비슷하지만 배열안에 배열이 있는 형태에서 더 유용하다는 차이점이 있다.
# d3.range([start, ]stop[, step])
등차수열을 담은 배열을 생성한다. 파이썬의 빌트-인 메서드 range와 비슷하다. 이 메서드는 배열의 색인 같은 정수 값들이나 수열을 순회하기 위해서 사용한다. 파이썬 range와는 달리, 부동소수점 정밀도로 인해서 결과가 더 예상 가능하지만 전달인자가 꼭 정수일 필요는 없다. step 을 생략하면 기본값은 1이고, start 를 생략하면 기본값이 0이다. stop 값은 결과에 포함되지 않는다. 결과의 전체 형태는 [ start , start + step, start + 2 * step , …]의 숫자 배열로 반환된다. step 이 양수면 마지막 원소는 stop 보다 start + i * step 만큼 크다. step 이 음수면 마지막 원소는 stop 보다 start + i * step 만큼 작다. 반환 배열의 값이 무한값으 되면 무한루프를 돌지 않고 에러를 던진다.
# d3.permute(array, indexes)
indexs 배열을 사용해서 array 의 순열(permutation)을 반환한다. 반환 배열은 indexs 배열의 각 색인에 대한 해당 원소를 순서대로 담고 있다. 예를 들어, permute(["a", "b", "c"], [1, 2, 0])는 ["b", "c", "a"]를 반환한다. 색인 배열 indexs는 원소 배열인 array 와 길이가 다를 수 있으며 중복되거나 생략 가능하다.
이 메서드는 정렬 순서를 유지하면서 배열의 객체에서 값을 추출하는데도 사용할 수 있다. (자바스크립트에서 배열 색인값은 .length
과 특별한 관계를 맺은 프로퍼티일 뿐이다.) 중첩 선택물에서 data 배열을 생성하려 할 때 정렬순서대로 명명된 값을 추출하는 기능이 유용하다. 예를 들어 테이블 형태로 사전에 Minnesota barley yield 데이터중 일부를 출력할 수 있다.
var cols = ["site", "variety", "yield"];
thead.selectAll('th').data(cols)
.enter().append('th').text(function (d) { return d.toUpperCase(); });
tbody.selectAll('tr').data(yields)
.enter().append('tr').selectAll('td').data(function (row) { return d3.permute(row, cols); })
.enter().append('td').text(function (d) { return d; });
# d3.zip(arrays…)
배열의 배열을 반환하는데, i번째 배열은 전달인자 arrays 각각에서 i번째 원소을 담고 있다. 반환 배열은 arrays 중 가장 짧은 배열의 길이로 재단된다. arrays 로 배열이 하나만 지정되면 반환 배열은 원소가 하나인 배열이 된다. 전달인자가 없으면 반환 배열을 빈 배열이다.
# d3.transpose(matrix)
d3.zip.apply(null, matrix)
와 동일하다. 2차원 전치행렬(matrix transpose)를 위해서 zip 연산자를 사용한다.
배열의 원소는 중첩(nestring)을 통해서 계층 트리구조로 그룹지을 수 있다. 중첩은 SQL의 GROUP BY 연산자와 유사하지만 그룹핑이 여러단계 가능하고 결과가 단면 테이블이 아닌 트리구조라는 점이 다르다. 트리의 레벨은 key 함수로 지정한다. 트리의 중간 단계 노드는 key로 정렬할 수 있고 리프(leaf) 노드는 value으로 정렬 가능하다. 옵션인 rollup 함수는 합산 함수를 사용한 리프 노드별로 원소들을 숨긴다. nest 연산자 객체(d3.nest가 반환한 객체)는 재 사용가능하지만 중첩된 데이터 참조를 유지하지 않는다.
예를 들어, 1931~1932년 사이, Minnesota주 여러지역의 보리밭에 대한 집계자료를 보자.
var yields = [{yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
{yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca"},
{yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris"}, ...]
시각화를 손쉽게 하려면 year, variety 순으로 원소를 중첩시키는게 편하다.
var nest = d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.variety; })
.entries(yields);
다음이 반환된 배열이다. 결과 배열의 각 원소는 각 key에 해당하는 values를 나열한 한 쌍의 key-values이다.
[{key: 1931, values: [
{key: "Manchuria", values: [
{yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
{yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca"},
{yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris"}, ...]},
{key: "Glabron", values: [
{yield: 43.07, variety: "Glabron", year: 1931, site: "University Farm"},
{yield: 55.20, variety: "Glabron", year: 1931, site: "Waseca"}, ...]}, ...]},
{key: 1932, values: ...}]
이런 중첩된 모양은 SVG나 HTML에서 계층구조 생성과 순회를 쉽게 해준다.
# d3.nest()
신규 nest 연산자를 생성한다. 생성시에는 key 집합이 비어있다. key 함수를 등록안하고 map나 entries 연산자를 호출하면, nest 연산자는 그냥 그 연산자의 입력 배열을 반환한다.
# nest.key(function)
신규 key function 을 등록한다. key 함수는 입력 배열의 각 원소별로 호출되고 함수는 반드시 원소를 그룹화 하는데 사용할 식별 문자열을 반환해야 한다. 그래서 대부분, 함수는 앞의 예제에서 year과 variety 접근자처럼 단순한 접근자로 구현된다. key는 등록될 때 마다 내부의 keys 배열의 끝에 푸쉬되고 map이나 항목의 결과물에는 추가 계층 단계가 생긴다. 등록된 key를 조회하거나 제거하는 기능이 현재는 없다. 마지막 등록한 key는 메서드 체이닝의 다음 메서드에서 해당 key로 참조된다.
# nest.sortKeys(comparator)
전달인자 comparator(d3.descending 같은 비교자)를 사용해서 해당 key에서 값을 정렬한다. 해당 key를 위한 비교자를 지정하지 않으면 key가 반환될 위치의 정렬은 undefined가 된다. 주의할 점은 이 연산자는 entries 연산자 결과에만 영향을 준다. comparator 인자에 상관없이 map 연산자가 반환한 key정렬은 항상 undefined이다.
# nest.sortValues(comparator)
전달인자 comparator 연산자(d3.descending같은 비교자)를 이용해서 리프 원소를 정렬한다. 이는 nest 연산자를 적용하기전에 입력 배열을 정렬하는 동작과 유사하지만 룹핑한 각 그룹의 크기가 상대적으로 작으므로 일반적으로는 좀더 효과적이다. 값 비교를 위한 comparator 를 지정하지 않으면 원소는 입력 배열의 정렬 순서로 반환된다. 이 연산자는 map, entires 연산자 모두에 적용된다.
# nest.rollup(function)
리프 원소 그룹 별로 적용할 rollup function 을 제공한다. 리프 값들의 배열이 rollup 함수의 반환 값으로 교체 되는데, map 연산자 반환값인 연관 배열이나 entries 연산자가 반환하는 각 원소의 values 속성이든 관계없다.
# nest.map(array)
array 로 nest 연산자를 적용하며, 연관배열을 반환한다. 반환된 연관배열의 각 원소는 첫 key함수가 반환하는 key 값에 부합한다. 원소값은 등록된 key 함수의 수와 관련있다. key함수가 여러개면, 원소값은 중첩된 다른 연관 배열이다. 그렇지 않으면 원소값은 첫번째 key 함수가 반환한 key 값으로 입력 array 의 원소를 필터링한 배열이다.
# nest.entries(array)
array 로 nest 연산자를 적용하며, key와 values 원소를 가진 배열을 반환한다. 이론적으론 map가 반환하는 연관배열에 d3.entries를 적용하는것과 유사하지만 첫단계 만이 아니라 계층 단계를 타고 모두 적용한다는 점이 다르다. 반환 배열의 각 원소는 첫번째 key 함수가 반환하는 key 값에 부합한다. 원소값은 등록된 key 함수의 수와 관련이 있다. 즉, key함수가 여러개면, 그 원소값은 다시 별도의 중첩 배열이지만, 그렇지 않으면 원소값은 첫번째 key 함수가 반환한 key 값으로 입력 array 의 원소를 필터링한 배열이다.