d3js -- 词云(word cloud)
词云也叫标签云,是文本数据的可视化展示,通常根据字体颜色和大小表示每个标签的重要性。d3并没有词云模块,因此需要独立导入d3-cloud这个模块。
词云用到的数据形式是一组数组对象。通常,默认使用text表示显示标签,value用来计算字体大小。用户也可以使用自定义的名称,这时候需要改变函数。
下面是一个制作词云的事例。首先先看看词云的效果, 其中archimedean和rectangular为单词的螺旋类型,也可以自定义其他形式。此文只展示这两种。
图一、阿基米德螺线式词云
图二、rectangular式词云
一、html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>词云图</title> <script src="../../../d3.min.js"></script> <!-- 专门绘制词云的包 --> <script src="../d3.layout.cloud.js"></script> </head> <body> <div id="selectButton"></div> <div id="word_cloud"></div> <script src="./index.js" type="module"></script> </body> </html>
二、js文件
步骤一、前置准备
// 1、create dimensions const dms = { width: 1000, height: 550, margin: { top: 50, left: 50, bottom: 50, right: 50 } } dms.innerWidth = dms.width - dms.margin.left - dms.margin.right; dms.innerHeight = dms.height - dms.margin.top - dms.margin.bottom; const svg = d3.select('#word_cloud') .append('svg') .attr('width', dms.width) .attr('height', dms.height); const maingroup = svg.append('g') .attr('transform', `translate(${dms.margin.left}, ${dms.margin.top})`); const wordCloundArea = maingroup.append('g') .attr('class', 'word-cloud-area'); // 设置颜色 const colors = d3.scaleOrdinal(d3.schemeCategory10);
// 设置data和单词螺旋类型
let data, spiralValue = 'archimedean';
步骤二、读取文件
这里直接准备txt文件,里面存放需要的中文或者英文篇章。
// 文本文件路径 const path = '../data/word.txt'; // 读取文件 d3.text(path).then(loadData => { // 处理数据,将数据转换成指定格式的数据 data = handleRequestData(loadData); //console.log(newData); renderWord(); })
handleRequestData是用来获取所需数据对象的方法,可将其处理成下面这种形式,也就是第二段落所述的用户自定义的名称:
[{ text: "Life", fontSize: 0.9999 }, ...... ]
这里这个函数不做多介绍,根据自身需要来处理,大致过程就是
1、正则处理,去除不需要的符号或其他元素,比如, ; :等
2、计算每个单词出现的次数,并分配字体大小
3、转换格式,即转换成上述格式。
另外,直接使用上述格式,更方便,就不需要做1,2两步的处理了
步骤三、renderWord()函数
function renderWord() { // add button const button = d3.select('#selectButton'); button.call(changeValueButton, { value: ['archimedean', 'rectangular'], onButtonClicked: onButtonSelectionClicked }); let transition = d3.transition().duration(2000).ease(d3.easeLinear); // 布局 const layout = d3.layout.cloud() .size([dms.innerWidth, dms.innerHeight]) .words(data) .font('Impact') .spiral(spiralValue) // archimedean, rectangular .fontSize(d=>d.fontSize * 12) // 如果不是默认的数据,需要自定义哪个属性来应用,比如fontSize .on('end', draw); // 执行layout算法 layout.start(); // 执行完layout算法后,会返回一个新数据。 function draw(words) { // console.log(words, layout.size()); const wordCloud = wordCloundArea .attr('transform', `translate(${layout.size()[0] / 2}, ${layout.size()[1] / 2})`); const wordCloudG = wordCloud.selectAll('text') .data(words); const wordCloudGEnter = wordCloudG .enter().append('text') .text(d=>d.text) .attr('text-anchor', 'middle') .style('font-size', d=>d.size) .style('font-family', d=>d.font) .style('fill', (d, i)=>colors(i%10)) .merge(wordCloudG) .transition(transition) .attr('transform', d=>`translate(${d.x}, ${d.y})rotate(${d.rotate})`); } }
上述通过d3.layout.cloud()创建了布局对象,size设置了词云的大小,words为词云数据,font为设置的字体,spiral为单词螺旋模式 ,fontSize为字体大小,on方法定义了draw函数,用来在布局完成后去执行。layout.start(),用来启动布局算法。
draw()函数里进行了绘图,呈现了上面的效果。
步骤四、定义按钮。
// 定义按钮 export const changeValueButton = (selection, options) => { let { value, onButtonClicked } = options; // selectButton let button = selection.selectAll('button') .data(value); // button.exit().remove() button = button .enter() .append('button') .merge(button) .attr('id', value) .attr('value', d=>d) // .style('color', '#fff') .style('background', d=>d===spiralValue ? '#00bcd4' : '') .text(d=>d) .on('click', function() { // console.log('tttt', this.value) onButtonClicked(this.value); }) }
步骤五、获取点击的按钮
const onButtonSelectionClicked = radio => { spiralValue = radio; renderWord() }
到这里词云绘制完成。