본문 바로가기

미분류/SIDE

D3.js를 이용하여 그래프 그리기 - 선 그래프 분석

그래프를 그리기 이전에 샘플 그래프를 분석하는 것도 좋은 공부가 될 것 같아 진행하였다. 이번에 분석할 그래프는 선 그래프이다. 코드는 이 곳에서 제공해주고 있다. v5이므로 많은 참고가 될 것이다. D3.js의 경우 3, 4, 5 버전이 전부 기능이 다르기 때문에 버전에 유의하여 공부하여야 한다. 현재 가장 많은 자료를 가지고 있는 버전은 4버전이지만 새로운 버전을 공부하는 것은 나쁘지 않기 때문이다.
참고한 코드를 실행하면 다음과 같은 결과가 나온다.
새로고침 할 때마다 값이 달라지는 Random Line Chart이다.

하나씩 차근차근 살펴보자. 풀 코드는 링크에서 보자.

  • margin을 설정해준다.

    // 2. Use the margin convention practice 
    var margin = {top: 50, right: 50, bottom: 50, left: 50}
    , width = window.innerWidth - margin.left - margin.right // Use the window's width 
    , height = window.innerHeight - margin.top - margin.bottom; // Use the window's height

    그래프가 동적으로 그려지기 위해 window.inner 로 width를 정해준 것을 알 수 있다. 이렇게 그리면 띄워지는 창에 따라 그래프의 크기가 변화하고 일정한 폭의 margin 값을 가지게 된다.

    • 데이터 포인트를 정해준다. 샘플 코드에서는 21개인 것을 볼 수 있다.
      // The number of datapoints
      var n = 21;
      n 값을 바꿔주면 나타나는 값도 변하는 것을 알 수 있다.

    n 값을 30으로 바꿔보았다. 점(포인트)가 30개로 늘어났다.

  • Scale을 설정해준다

    // 5. X scale will use the index of our data
    var xScale = d3.scaleLinear()
    .domain([0, n-1]) // input
    .range([0, width]); // output
    // 6. Y scale will use the randomly generate number 
    var yScale = d3.scaleLinear()
    .domain([0, 1]) // input 
    .range([height, 0]); // output 

    D3에서 가장 중요한 요소 중 한 가지가 Scale이다. Sclae은 척도라고 생각하면 된다. scale을 정해줄 때 set 해주는 게 domain과 range인데 domain은 축의 값을 정해주는 것이고 range는 축의 물리적인 위치를 정해주는 것이다.
    변경해보면 어떻게 다른지 알 수 있다. 편의상 나타내는 값을 10개로 변경하고 domain을 n+2로 바꿔본다.

    x축을 보면 값이 12까지 나온다. n값에 영향을 받기 때문에 n+2인 12까지 나타난것이다. 하지만 점은 9까지밖에 그려지지 않았다. 이는 n의 갯수는 0~9인 10개이기 때문이다.

    range를 변경해보자. 물리적인 그래프 길이를 조절할 수 있다. range를 0~200으로 변경해보았다.

아주 옹졸한 그래프가 그려진다. 이 부분을 어떻게 설정하느냐에 따라 그래프의 크기와 각 축의 값이 정해지는 것이다.

  • 라인을 생성해준다

    // 7. d3's line generator
    var line = d3.line()
     .x(function(d, i) { return xScale(i); }) // set the x values for the line generator
     .y(function(d) { return yScale(d.y); }) // set the y values for the line generator 
     .curve(d3.curveMonotoneX) // apply smoothing to the line

    바로 사용되는 것이 아니고 향후 사용된다. 여기서 curve 옵션이 있을 때에는 그림과 같은 완만한 곡선이 만들어지고 없을 때에는 아래와 같은 꺾은선 그래프가 된다.

  • 데이터를 생성해준다

    // 8. An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
    var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })

    dataset에 랜덤하게 데이터를 생성하여 넣어준다. 이 때 y값이 랜덤한 값인 것을 알 수 있다.

    • SVG를 생성한다.
      // 1. Add the SVG to the page and employ #2
      var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    이제 드디어 그래프를 그릴 스케치북인 svg 판을 하나 만들어준다. body안에 만들어주고 width와 height는 각각 원하는 값으로 설정해준다.

    • 축을 생성한다.
    // 3. Call the x axis in a group tag
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom
    // 4. Call the y axis in a group tag
    svg.append("g")
      .attr("class", "y axis")
      .call(d3.axisLeft(yScale)); // Create an axis component with d3.axisLeft

    각각 x,y axis라는 이름을 가진 축을 만들어준다. 축은 이전에 만들어 둔 scale로 생성해주고 방향 조정을 통해 어떤 방향으로 나타날지 정할 수 있다. 현재 y축은 왼쪽에 그려졌지만 axisRight로 바꾸고 transform 옵션을 설정하면 오른쪽에 고정할 수 있다.

    // 4. Call the y axis in a group tag
    svg.append("g")
      .attr("class", "y axis")
      .attr("transform", "translate( " + width + ", 0 )")
      .call(d3.axisRight(yScale)); // Create an axis component with d3.axisLeft

    • path를 넣어준다. 그래프를 보면 선+점으로 되어 있는 것을 알 수 있다. 둘은 서로 다른 요소이다. 먼저 선을 넣어주는 것이다.

      // 9. Append the path, bind the data, and call the line generator 
      svg.append("path")
      .datum(dataset) // 10. Binds data to the line 
      .attr("class", "line") // Assign a class for styling 
      .attr("d", line); // 11. Calls the line generator 


      하지만 갖가지 이벤트를 넣으려면 선은 문제점들이 있다. 클릭 이벤트나 다른 이벤트를 인식하지 못한다는 것이다. 그래서 대부분 값마다 dot를 찍어주어서 인식할 수 있는 부분을 만들어 준다

    • dot를 생성한다

    svg.selectAll(".dot")
      .data(dataset)
    .enter().append("circle") // Uses the enter().append() method
      .attr("class", "dot") // Assign a class for styling
      .attr("cx", function(d, i) { return xScale(i) })
      .attr("cy", function(d) { return yScale(d.y) })
      .attr("r", 5)
        .on("mouseover", function(a, b, c) { 
                console.log(a) 
          this.attr('class', 'focus')
          })
        .on("mouseout", function() {  });

이렇게 하면 제법 그럴듯한 선 그래프가 만들어진다. 색이 마음에 들지 않으면 미리 정해놓은 클래스명이나 id로 css 셀렉터를 통해 변경할 수 있다. 선은 그대로 두고 점을 skyblue로 바꿔보자. 점은 미리 dot이라는 class를 가지고 있어 바로 사용하면 된다.

 /* Style the dots by assigning a fill and stroke */
.dot {
    fill: skyblue;
    stroke: #fff;
}

이제 마우스 오버 이벤트도 한 번 넣어보자. 해당하는 dot을 클릭했을 때 검은색으로 변경되게 한다.

 .dot:hover {
    fill:black;
}

d3에서도 마우스 오버 이벤트를 제공하지만 데이터 값을 사용하지 않을 경우에는 css로 처리하는 것이 편하다. 다음은 d3에 여러 요소 그래프를 그려보아야겠다.