javascript - 为散点图中的每个点绘制词云

标签 javascript d3.js

我创建了一个根据以下数据定义的散点图(请注意,当前仅使用前两个字段进行绘图):

var data = [[5,3,"{'text':'word1',size:4},{'text':'word2','size':1}"], 
            [3,5,"{'text':'word3',size:5},{'text':'word4','size':4}"],
            [1,4,"{'text':'word1',size:3},{'text':'word2','size':5},{'text':'word3','size':2}"],
            [2,3,"{'text':'word2',size:1},{'text':'word3','size':5}"]];

接下来,当我们单击散点图中的每个特定点时,应用程序应附加一个词云,该词云是根据存储在 data 变量的第三个字段中的单词定义的。我使用 Jason Davies 的 wordcloud 实现。目前(出于演示目的),词云仅根据变量 Frequency_list 中存储的静态数据生成。当前代码也存储在JSFiddle上.

知道如何继续吗?

var data = [[5,3,"{'text':'word1',size:4},{'text':'word2','size':1}"], 
            [3,5,"{'text':'word3',size:5},{'text':'word4','size':4}"],
            [1,4,"{'text':'word1',size:3},{'text':'word2','size':5},{'text':'word3','size':2}"],
            [2,3,"{'text':'word2',size:1},{'text':'word3','size':5}"]];

var margin = {top: 20, right: 15, bottom: 60, left: 60},
    width = 500 - margin.left - margin.right,
    height = 250 - margin.top - margin.bottom;

var x = d3.scale.linear()
  .domain([0, d3.max(data, function(d) { return d[0]; })])
  .range([ 0, width ]);

var y = d3.scale.linear()
  .domain([0, d3.max(data, function(d) { return d[1]; })])
  .range([ height, 0 ]);

var chart = d3.select('body')
  .append('svg:svg')
    .attr('width', width + margin.right + margin.left)
    .attr('height', height + margin.top + margin.bottom)
    .attr('class', 'chart')

var main = chart.append('g')
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
    .attr('width', width)
    .attr('height', height)
    .attr('class', 'main')   

// Draw the x axis
var xAxis = d3.svg.axis()
    .scale(x)
    .orient('bottom');

main.append('g')
    .attr('transform', 'translate(0,' + height + ')')
    .attr('class', 'main axis date')
    .call(xAxis);

// draw the y axis
var yAxis = d3.svg.axis()
    .scale(y)
    .orient('left');

main.append('g')
    .attr('transform', 'translate(0,0)')
    .attr('class', 'main axis date')
    .call(yAxis);

var g = main.append("svg:g"); 

g.selectAll("scatter-dots")
  .data(data)
  .enter().append("svg:circle")
  .attr("cx", function (d,i) { return x(d[0]); } )
  .attr("cy", function (d) { return y(d[1]); } )
  .attr("r", 5)
  .on("mouseover", function(){d3.select(this).style("fill", "red")})
  .on("mouseout", function(){d3.select(this).style("fill", "black")});

// FUNCTION TO DISPLAY CIRCLE
g.on('mouseover', function(){
  div.style("display", "block")
  d3.select("krog").style("fill", "orange");
  generate();
});

g.on('mouseout', function(){
  //div.style("display", "none")
  div.select("svg").remove();
});

var div = d3.select("body")
  .append("div")
  .attr("class", "tooltip")
  .style("display", "none");


// Functions to draw wordcloud
var frequency_list = [{"text":"study","size":40},{"text":"motion","size":15},{"text":"forces","size":10},{"text":"electricity","size":15},{"text":"movement","size":10},{"text":"relation","size":5},{"text":"things","size":10},{"text":"force","size":5},{"text":"ad","size":5}];

var color = d3.scale.linear()
            .domain([0,1,2,3,4,5,6,10,15,20,100])
            .range(["#ddd", "#ccc", "#bbb", "#aaa", "#999", "#888", "#777", "#666", "#555", "#444", "#333", "#222"]);

// Generates wordcloud
function generate(){
  d3.layout.cloud().size([800, 300])
    .words(frequency_list)
    .rotate(0)
    .fontSize(function(d) { return d.size; })
    .on("end", draw)
    .start();
}

function draw(words) {
  d3.select("div").append("svg")
    .attr("width", 850)
    .attr("height", 350)
    .attr("class", "wordcloud")
    .append("g")
    // without the transform, words words would get cutoff to the left and top, they would
    // appear outside of the SVG area
    .attr("transform", "translate(320,200)")
    .selectAll("text")
    .data(words)
    .enter().append("text")
    .style("font-size", function(d) { return d.size + "px"; })
    .style("fill", function(d, i) { return color(i); })
    .attr("transform", function(d) {
      return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
    })
    .text(function(d) { return d.text; });
}

最佳答案

这里有几个问题。

首先,您的数据包含单词的字符串。我为一组对象更改了它:

var data = [[5,3,[{'text':'word1',size:4},{'text':'word2','size':1}]], 
        [3,5,[{'text':'word3',size:5},{'text':'word4','size':4}]],
        [1,4,[{'text':'word1',size:3},{'text':'word2','size':5},{'text':'word3','size':2}]],
        [2,3,[{'text':'word2',size:1},{'text':'word3','size':5}]]];

之后,我更改了函数draw:不再是每次将鼠标悬停在圆圈上时附加一个新的 div,而是仅更改 div 内容:

div.append("svg")
    .attr("width", 300)
    .attr("height", 300)
    .attr("class", "wordcloud")
    .append("g")

但现在最重要的变化来了:

每次用户将鼠标悬停在一个圆圈上时,您都会显示词云,但您正在为组元素调用鼠标悬停。这样,我们就无法访问绑定(bind)到每个特定圆圈的数据。

取而代之的是,我们将为圆圈设置一个变量:

var circle = g.selectAll("scatter-dots")
    .data(data)
    .enter()
    .append("svg:circle");

这样,我们就可以获得每个悬停圆圈的数据,这是数组中的第三个元素:

circle.on('mouseover', function(d){
    div.style("display", "block")
    d3.select("krog").style("fill", "orange");
    generate(d[2]);//here, d[2] is the third element in the data array
});

我们将第三个元素 (d[2]) 作为名为 thisWords 的参数传递给函数 generate:

function generate(thisWords){
    d3.layout.cloud().size([800, 300])
    .words(thisWords)
    .rotate(0)
    .fontSize(function(d) { return d.size; })
    .on("end", draw)
    .start();
}

这是你的 fiddle :https://jsfiddle.net/jwrbps4j/

PS:您必须改进该单词的翻译

关于javascript - 为散点图中的每个点绘制词云,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40200359/

相关文章:

javascript d3 刻度格式

reactjs - 将 dc.js 转换为 React 有意义吗?

javascript - 删除D3中的线元素

javascript - SVG 可以渲染,但仅在 Firefox 中被切断 - 为什么?

javascript - 如何生成唯一代码

javascript - 在 iframe 中使用 jQuery 修改父窗口

javascript - 选中所有复选框

javascript - 当最内层循环等待响应时如何延迟嵌套迭代?

JavaScript 阴影与初始化

javascript - 是否可以触发位于其他元素后面的元素事件