key함수, animation, colorize는 쉬워서 넘어갔다
색상척도는 세가지로 나뉜다
사실 척도부분에서 배운 세가지 척도를 활용하는거다.
순차적 색상척도는 치역(range)대신 보간(interpolator)이 필요하다.
주어진 두 점의 선분을 연결하는 방법. 즉 두 값 사이를 점진적으로 어떻게 전환할 것인지 정해야한다.
const ipNum = d3.interpolateNumber(10,20);
ipNum(0) // 10
ipNum(1) // 20
즉 y = x*10 + 10(최소값)
의 함수를 나타낸다고 볼 수 있다. (단, x는 0이상 1이하)
색상에 관한 보간도 설정할 수 있다.
const ipNum = d3.interpolateRgb('steelblue', 'brown');
ipNum(0) // rgb(70,130,180)
ipNum(1) // rgb(165,42,42)
값을 촘촘히 나눈다면 steelblue => brown그라데이션으로 보일 것이다.
또한 다양한 타입의 보간을 제공하니 공식문서를 보자!
선형 색상척도는 단순하게 치역(range)에 색상을 넣어주면 된다.
const myColor = d3.scaleLinear()
.domain([1,10])
.range(['white', 'blue']);
const myColor = d3.scaleOrdinal()
.domain(['A','B','C','D','E'])
.range([...색상들])
const myColor = d3.scaleOrdinal()
.domain(['A','B','C','D','E'])
.range(d3.schemaSet3) //d3에서 색상 스키마를 제공하기도 한다
범례는 보통 색상으로 구분한다. 따라서 색상척도를 이용한다.
범례는 두가지로 나뉜다
색상척도중 범주형 색상척도를 이용하면 쉽다
//컬러를 생성해준다
const scale = d3.scaleOrdinal()
.domain(['blueberries','oranges','apples'])
.range(d3.schemeCategory10);
//범례 그룹을 하나 만든다. margin, 폰트 설정은 일단 넣지않음
const legendGroup = svg.append('g')
//범례를 만든다
const legend = legendGroup.selectAll('.legend')
.data(scale.domain())
.join('g')
.attr('transform', (d,i) => `translate(${i*90},${0})`) // 한 범례당 90px씩 이동
//범례에 들어가는 사각형을 만듬
const rectOfLegend = legend.append('rect')
.attr('fill', scale) // 범주형 색상척도로 만든 색상을 넣어준다
//범례의 텍스트
const textOfLegend = legend.append('text')
.attr(...x축 y축 위치지정)
.text(d=>d); //여기서 d는 scale.domain()으로 넣어준 데이터들 ['blueberries','oranges','apples'] 이다
이 때는 순차적 색상척도를 사용하면 된다. 단, 눈금은 scaleLinear를 사용하면 된다 ㅎㅎ
const colorScale = d3.scaleSequential()
.domain([0,99])
.interpoltator(d3.tinerpolateYlOrRd);
const xScale = d3.scaleLinear()
.domain([0,99])
.range([margin.left, width - margin.right]);
const xAxis = d3.axisBottom(xScale)
.tickSize(15)
.tickFormat((v) => `${v}℉`)
.tickValues([25,50,75]);
const legendScale = legend.append('g');
legendScale.selectAll('rect')
.data(data)
.join('rect')
.attr('x', (d) => xScale(d))
//너비에 1.1~1.2배수를 주어야함. 1배수로 한다면선형적으로 이어진 rect들 사이사이 공간이 벌어져있다.
.attr('width', (width - margin.left - margin.right) / 100 * 1.2)
.attr('fill', (d) => colorScale(d));
척도를 이용하여 점을 찍은 뒤 d3.line()
메서드를 이용하여 선을 그리면 끝이다.
const line = d3.line()
.x((d) => xScale(d.date))
.y((d) => yScale(d.close));
svg.append('path')
.attr('class', 'line-path')
.attr('d', line(data));
선으로 만든 그래프를 색상으로 꽉 채우는 것이다.
y0
이 y값 기준선이고 y1
이 최상위선이다.
const area = d3.area()
.x((d) => xScale(d.date))
.y0(y(0))
.y1((d) => yScale(d.close)); //0~y최댓값 까지 영역을 차지한다.
svg.append('path')
.attr('class', 'area-path')
.attr('d', area(data));
영역을 겹쳐서 누적되게 보여준다(지층처럼). 추측해보면 영역의 y0값을 잘 조정하면 될 것 같다.
라고 생각했는데, stack
메서드가 따로 있네?😮
const data = [
{
month: new Date(2018, 1, 1),
fruitSales:{
apples:10,
bananas:20,
oranges:15
}
},
{
month: new Date(2018, 2, 1),
fruitSales:{
apples:15,
bananas:15,
oranges:15
}
},
{
month: new Date(2018, 3, 1),
fruitSales:{
apples:20,
bananas:25,
oranges:15
}
},
];
const fruits = ['apples', 'bananas', 'oranges'];
const stack = d3.stack()
keys(fruits)
.value((obj,key) => obj.fruitSales[key]);
const series = stack(data);
이렇게 하고 x,y축 척도도 만들어 넣으면 날짜별로 과일이 어떻게 변하는지 볼 수있다.
원형그래프를 그릴때 쓰인다. 호도법할때 그 '호'다
const data = [1,1,2,3,5,8,13,21];
const arcs = d3.pie()(data); //d3.pie는 해당 값에 호의 크기를 만들어준다.
// [{data, value, index, startAngle, endAngle, padAngle}] 이렇게 값을 제공해줌
const arc = d3.arc()
.innerRadius(40) //내부반경
.outerRadius(80) //외부반경
.startAngle(([startAngle, endAngle]) => startAngle); //시작 각
.endAngle(([startAngle, endAngle]) => endAngle); //끝 각
const n = 12;
Array.from({length:n}, (_,i) => {
svg.append('path')
.attr('fill', d3.interpolateRainbow(i/n))
.attr('d', arc([i / n*2 * Math.PI, (i+1) / n*2 * Math.PI]));
})