이번 포스팅은 d3 라이브러리를 사용하기 위해 고군분투한 경험을 적겠습니다.
D3.js란 데이터를 기반으로 문서를 조작하기위한 JavaScript 라이브러리입니다. D3는 HTML, SVG 및 CSS를 사용하여 데이터를 시각화 하기에 아주 좋습니다. 데이터 시각화 프로그램인 R을 생각하면 쉬울텐데요. D3는 Javascript 라이브러리로써 웹에 바로 띄우기 아주 좋다는 장점이 있습니다.
자바스크립트 기반이기 때문에 프레임워크인 리액트에서도 사용할 수 있습니다. 그러나 활용하는 코드 방식이 좀 달라서 애를 먹었는데요.. 일단 react는 npm기반으로 create-react-app을 이용하여 설치했기 때문에 npm모듈을 이용하여 d3를 다운받아야 했습니다.
npm 패키지에 다행히 d3가 있더라고요. 근데 제가 활용하고자 하는 wordcloud기능은 없었습니다.
더 찾아보니 d3-cloud라고 따로 패키지가 존재했습니다.
들어가보면 d3-cloud에 대한 API 사용법은 있는데 자세한 건 안나와있고 특히 react에선 어떻게 사용해야하는지 안적혀있었어서 여러 검색과 시행착오를 통해 완성했습니다.
다운받는게 먼저니 두개의 패키지를 다운 받습니다.
$ npm install d3
$ npm install d3-cloud
두개를 설치하면 package.json에 해당 모듈이 추가가 됩니다.
이제 어떻게 react에서 사용할 것인가...
react로 그냥 d3.js 라이브러리를 사용한 예제 코드와 d3-cloud의 깃헙에 존재하는 예제 코드를 보며 짬뽕시켰습니다. ㅎ
// Result/index.js
import React, { useEffect } from 'react';
import * as d3 from 'd3';
import cloud from 'd3-cloud';
const width = 400
const height = 400
function HotelsResult() {
useEffect(() => {
const data = [
"Hello", "world", "normally", "you", "want", "more", "words",
"than", "this"]
cloud()
.size([width, height])
.words(data.map(function(d) {
return {text: d, size: 10 + Math.random() * 90, test: "haha"};
}))
.padding(5)
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", end)
.start();
function end(words) {
d3.select("#word-cloud")
.append("svg")
.attr("width", 500)
.attr("height", 500)
.style("border", "1px solid black")
.append("g")
.attr("transform", "translate(" + 500 / 2 + "," + 500 / 2 + ")")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
})
return (
<div>
<h1>리뷰 분석 결과</h1>
<div id="word-cloud"></div>
</div>
)
}
export default HotelsResult;
일단 import * as d3 from 'd3'
로 d3 모듈을 임포트합니다.
import cloud from 'd3-cloud'
로 d3-cloud 모듈도 따로 임포트 해줍니다.
원래는 d3 라이브러리 안에 d3-cloud가 있어서 d3.layout.cloud()
API로 워드클라우드 형성이 되어야 하는데 npm에선 따로 다운을 받았기 때문에 둘다 임포트 해주고 cloud()
API로 워드클라우드를 형성시킬 수 있습니다.
render로 div를 만들고 id를 설정해줍니다. 이는 나중에 d3.select()로 해당 div를 선택하여 만들 수 있습니다.
data는 아무거나 테스트용으로 설정해두고, cloud()부터는 예제 코드를 복붙했습니다. d3.select('#word-cloud')부분만 id를 선택하게끔 바꾸고 나머지는 그대로 했습니다. d3.js를 정식으로 공부하지 않았기 때문에 attr과 style에 대해 자세하겐 모르겠지만 어쨌든 해당 워드클라우드의 글씨 크기, 폰트 스타일, 기울임 정도 등을 설정한 것 같습니다.
또한 useEffect안에 함수를 넣어 데이터가 변동 될때 감지하여 rerendering하도록 했습니다.
다음과 같이 단어들이 잘 나오는 것을 확인 할 수 있습니다. ㅎㅎ
이제 리뷰단어들을 data부분에 배열의 형태로 잘 넣으면 워드클라우드 형태로 아주 잘 나올 것입니다!
!!여기서 함정!!
정상적인 wordcloud로 제일 많이 나온 단어가 크고, 제일 적게 나온 단어가 작고 그런 식이 아닙니다. D3.js는 그저 R과 같은 시각화 모듈이기 때문에 글자마다 size를 직접 설정해주어야 합니다. 근데 저 코드는 잘 보시면 알겠지만, size를 random으로 설정했습니다.. 그래서 랜덤으로 어떤 단어가 크고 작고 그럽니다... 이 부분은 python을 이용한 딥러닝 부분이므로 프론트엔드와 관련이 없어서 생략하였습니다.
거기다가 python으로 결과를 내어 어떻게 프론트로 전달할지 모르겠는 부분도 있습니다.. ㅜㅜ 기술적인 부분으로 인해 야매로 wordcloud를 만든 것이니 참고하시길 바랍니다.