Andrej Andrej - 1 year ago 59
Javascript Question

Draw wordcloud for each point in scatterplot

I create a scatterplot which is defined on the following data (note that only first two fields are currently using for plotting):

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

Next, when we click on each particular point in the scatterplot the application should attach a wordcloud which is defined from words stored in the 3rd field of the
variable. I use Jason Davies's implementation of wordcloud. Currently (for demo purposes), the wordcloud is generating onlyfrom the static data stored in variable
. The current code is also stored on JSFiddle.

Any idea how to proceed?

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

var margin = {top: 20, right: 15, bottom: 60, left: 60},
width = 500 - margin.left - margin.right,
height = 250 - - 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 ='body')
.attr('width', width + margin.right + margin.left)
.attr('height', height + + margin.bottom)
.attr('class', 'chart')

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

// Draw the x axis
var xAxis = d3.svg.axis()

.attr('transform', 'translate(0,' + height + ')')
.attr('class', 'main axis date')

// draw the y axis
var yAxis = d3.svg.axis()

.attr('transform', 'translate(0,0)')
.attr('class', 'main axis date')

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

.attr("cx", function (d,i) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 5)
.on("mouseover", function(){"fill", "red")})
.on("mouseout", function(){"fill", "black")});

g.on('mouseover', function(){"display", "block")"krog").style("fill", "orange");

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

var div ="body")
.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()
.range(["#ddd", "#ccc", "#bbb", "#aaa", "#999", "#888", "#777", "#666", "#555", "#444", "#333", "#222"]);

// Generates wordcloud
function generate(){[800, 300])
.fontSize(function(d) { return d.size; })
.on("end", draw)

function draw(words) {"div").append("svg")
.attr("width", 850)
.attr("height", 350)
.attr("class", "wordcloud")
// 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)")
.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; });

Answer Source

You have a couple of problems here.

First, your data has strings for the words. I changed that for an array of objects:

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

After that, I changed the function draw: instead of appending a new div every time you hover a circle, it just change the div content:

    .attr("width", 300)
    .attr("height", 300)
    .attr("class", "wordcloud")

But now comes the most important change:

You are displaying the wordcloud every time the user hover a circle, but you're calling the mouseover for the group element. That way, we cannot access the data bound to each specific circle.

Instead of that, we'll set a variable for the circles:

var circle = g.selectAll("scatter-dots")

Thus, we can get the data for each hovered circle, which is the third element in the array:

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

And we pass this third element (d[2]) to the function generate as a parameter named thisWords:

function generate(thisWords){[800, 300])
    .fontSize(function(d) { return d.size; })
    .on("end", draw)

here is your fiddle:

PS: you'll have to improve the translate for that words.