Dashboards & Visualizations

How to edit my D3 custom visualization code to incorporate data entry, update and exit to produce a wordcloud based on twitter hashtags?

jeffland
SplunkTrust
SplunkTrust

Hi.

I'm trying to produce a wordcloud based on twitter hashtags with Jason Davies' D3 wordcloud visualization (https://www.jasondavies.com/wordcloud/)

My problem is that I haven't yet fully understood how to properly implement the concept of data entry, update and exit (http://bost.ocks.org/mike/join/). I understand the idea, I just don't see why it doesn't work in my example.

I know how to retrieve the search results, and I know how to generate the word cloud initially, but I fail at updating the word cloud - that is, removing words that are no longer in the results and adding new ones (when I change the search).

Here is my (lengthy) code:

var search = splunkjs.mvc.Components.getInstance("search1"); // get the search manager
var myResults = search.data("results"); // get the data from that search
var resultArray = []; // prepare array to hold rows
var searchresult_tags = []; // array for hashtags
var searchresult_weight = []; // array for corresponding importance
var duration = 750; // duration for transitions
var fontSizeRange = d3.scale.linear(); // a scale to map importance to pixels

// A group in which to present the cloud
var cloudGroup = d3.select("#wordcloud").append("svg")
    .attr("width", 600)
    .attr("height", 600)
    .append("g")
    .attr("transform", "translate(300,300)");

// When data arrives:
myResults.on("data", function() {
    // Fill two arrays with results (tags and weight)
    resultArray = myResults.data().rows;
    for (i = 0; i < resultArray.length; i++) {
        searchresult_tags[i] = resultArray[i][0];
        searchresult_weight[i] = parseInt(resultArray[i][1]);
    }

    // Dynamically calculate the font sizes
    fontSizeRange
        .domain([searchresult_weight[9], searchresult_weight[0]])
        .range([8, 35]);

    // And start to layout the cloud
    d3.layout.cloud()
        .size([600, 600])
        .words(searchresult_tags.map(function(d, i) {
            var result = {text: searchresult_tags[i], size: searchresult_weight[i]};
            return result;
        }))
        .padding(1)
        .rotate(function() { return ~~(Math.random() * 70) - 35 ; })
        .font("Impact")
        .fontSize(function(d) { return fontSizeRange(d.size); })
        .on("end", draw)
        .start();

    // This function placed here to increase readability
    function draw(words) {
        cloudData = cloudGroup
            .selectAll("text")
            .data(words);

        // This part should deal with (newly) entering data
        cloudData.enter().append("text")
            .style("font-size", "0px")
            .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; })
            .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });

        // This with updating existing data
        cloudData.transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });

        // And this with exiting unused data
        cloudData.exit()
            .transition().duration(duration).style("font-size", "0px")
            .remove();
    }
});

As I said, this works fine initially, and when I change the search and the new results come in, the font size of the existing words is adjusted - the words themselves just don't change. My guess is that something is wrong with the way I'm trying to update my data, but I can't seem to figure out how to do it properly.

Thanks for your efforts.

0 Karma
1 Solution

jeffland
SplunkTrust
SplunkTrust

Ha, I got it.
The problem was not with the data, but with the display: to change the text that the wordcloud displays, you need to use the .text(...) operator (duh). In my particular case, I changed my function draw(words) to the following, altough you can certainly do it in other ways as well.

function draw(words) {
    cloudData = cloudGroup
        .selectAll("text")
        .data(words);

    // This part should deal with (newly) entering data
    cloudData.enter().append("text")
        .style("font-size", "0px")
        .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; })
        .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });

    // This with updating existing data
    cloudData
        .transition().duration(duration).style("font-size", "0px")
        .remove()
        .style("font-size", "0px")
        .attr("transform", function(d) {
            return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
        })
        .text(function(d) { return d.text; })
        .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });
}

View solution in original post

jeffland
SplunkTrust
SplunkTrust

Ha, I got it.
The problem was not with the data, but with the display: to change the text that the wordcloud displays, you need to use the .text(...) operator (duh). In my particular case, I changed my function draw(words) to the following, altough you can certainly do it in other ways as well.

function draw(words) {
    cloudData = cloudGroup
        .selectAll("text")
        .data(words);

    // This part should deal with (newly) entering data
    cloudData.enter().append("text")
        .style("font-size", "0px")
        .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; })
        .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });

    // This with updating existing data
    cloudData
        .transition().duration(duration).style("font-size", "0px")
        .remove()
        .style("font-size", "0px")
        .attr("transform", function(d) {
            return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
        })
        .text(function(d) { return d.text; })
        .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });
}
Get Updates on the Splunk Community!

How to Monitor Google Kubernetes Engine (GKE)

We’ve looked at how to integrate Kubernetes environments with Splunk Observability Cloud, but what about ...

Index This | How can you make 45 using only 4?

October 2024 Edition Hayyy Splunk Education Enthusiasts and the Eternally Curious!  We’re back with this ...

Splunk Education Goes to Washington | Splunk GovSummit 2024

If you’re in the Washington, D.C. area, this is your opportunity to take your career and Splunk skills to the ...