#D3Thursday is back again with a new series of articles over the next few weeks leading up to SAS Global Forum 2019. My colleagues, Elliot Inman and Olivia Wright, and I wrote a paper titled Kustomizing Your SAS Viya Engine Using SAS Studio Custom Tasks and D3.js. In this paper we create a custom end-to-end analytics workflow in SAS Viya. We start by using SAS Studio Custom Tasks to create analytic models. Then, we pass this data into SAS Visual Analytics, where we use custom D3 graphs to visualize the data. These articles will give you a sneak peak at the visualizations used in our SGF paper. Olivia Wright, author of Custom Task Tuesdays will be doing the same thing with her
series leading up to SGF. You can check out her series of posts to learn more about how we get from our source data to our analytic model output, and then use CAS to load the output data for use in SAS Visual Analytics.
Last week we described how you can download, modify, and host any #D3Thursday visualizations I have posted. This week we will look at how we can modify our existing sunburst chart to visualize the results of our analytic model.
Like last week, the sample data (Sample_Data_14.sas7bdat) for this post is the output of the analytic model that Olivia Wright built using SAS Studio Custom Tasks!
Before we start modifying the code, we need to take take a moment to discuss how the output of our clustering model differs from the traditional hierarchies we previously visualized with our sunburst. Here's an example of a traditional hierarchy visualized with a simple binary tree.
In a traditional hierarchy like this one, every node is unique and appears only at one depth of the tree. That is to say that France will never appear twice in the tree and will always be at the third level of this tree because the third level represents country. Our clustering model output, however, looks more like the pseudo-hierarchy shown below.
Unlike our traditional hierarchy above, we can see duplicate nodes in this tree. Additionally, we can see that multiple parent nodes feed into the same child node (both Cluster 1 and Cluster 2 in level 2 feed into Cluster 1 in level 3). We can rectify this situation by modifying our hierarchy as follows.
By thinking of Cluster 1 in level 3 of our hierarchy as two different nodes we can begin to picture what our sunburst will actually look like instead of getting lost in the tangle of our pseudo-hierarchy. At our innermost ring, we will have two arcs: Cluster 1 and Cluster 2. At the next ring, we will have four arcs: Cluster 1a and Cluster 3 which are children of Cluster 1 in the innermost ring, and Cluster 1b and Cluster 2 which are children of Cluster 2 in the innermost ring.
In order to properly visualize our pseudo-hierarchy we need to perform a few modifications to our existing sunburst chart. The most important changes we need to make are how the arcs are colored and what happens when we click on an arc. Let's start with the color.
DATA_ARCS.enter()
...
.attr("fill", function(d) {
return GRAD.fill[d.data.key]
? GRAD.fill[d.data.key]
: GRAD.fillScale(d.data.key);
})
...
Rather than using progressively lighter shades that we calculate when we nest our data we can simply color our arcs based on their keys, which correspond to which cluster the arc represents. Now we can change what happens when we click on an arc.
// Handle click events on arcs
function handleArcClick(arcD) {
// Prevent event from falling through to underlying elements or causing scroll
d3.event.stopPropagation();
d3.event.preventDefault();
// Remove selected class from all arcs
d3.selectAll(".focused").classed("focused", false);
// For selected arcs, bring opacity to 1 and move to front
d3.selectAll(".data-arc")
.filter(function(d) {
return d.depth && d.data.key == arcD.data.key && d.depth == arcD.depth;
})
.moveToFront()
.classed("focused", true)
.transition()
.duration(HOVER_TRANS_TIME)
.style("opacity", 1)
.each(function(d) {
// Focus all parents of selected arc
let node = d.parent;
while (node.parent) {
d3.select("#" + node.data.id)
.moveToFront()
.classed("focused", true)
.transition()
.duration(HOVER_TRANS_TIME)
.style("opacity", 1);
node = node.parent;
}
});
// Select all other arcs, bring opacity to unfocus opacity
d3.selectAll(".data-arc:not(.focused)")
.classed("focused", false)
.transition()
.duration(HOVER_TRANS_TIME)
.style("opacity", UNFOCUS_OPACITY);
}
Unlike our original sunburst, we no longer care about what percentage of the total a single arc encompasses. Instead, we are interested in seeing how many times a particular cluster appears in a certain ring, and what the parents of that cluster are. To help the user answer these questions we can modify what happens when an arc is selected. Whenever an arc is clicked, we search that ring and highlight any other appearance of that cluster. Then we can traverse the hierarchy from each highlighted arc and highlight that arc's parents.
Next post we will wrap up this series of posts leading up to SAS Global Forum 2019 by creating an all new chart: a circle packing graph!
Remember to follow these articles on the SAS Communities Library and the #D3Thursday Twitter hashtag. Comment below or Tweet your questions and comments!
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning and boost your career prospects.