Pentaho Tools :

Pentaho C-Tools(CDE,CDF,CDA),Pentaho CE & EE Server,OLAP-Cubes,Analysis using Pivot4J, Saiku Analytics, Saiku Reporting, Ad-hoc Reporting using Interactive Reporting Tool,Dashboards,Reports using PRD, PDD,Data Integration using Kettle ETL,Data Mining usign WEKA,Integration of Servers with Databases,Mobile/iPad compatible Dashboards using Bootstrap Css,Drilldown dashboards,Interactive Dashboards

Tuesday, 10 May 2016

D3 Chord diagram Visualization example in Pentaho CDE

Hi,
In this post you will learn how to develop D3 Chord diagram.

Software used for this example : 
1) Pentaho BA Server 6.1 CE
2) Postgre SQL foodmart database
3) Pentaho Ctools 6.1.0.1-196 (master)
4) D3 Component Library 14.06.18

NOTE: Original Code is taken from this site with slight java script modifications 
https://bl.ocks.org/mbostock/4062006

(Click on image to get best view)

 Steps : 
1) Install D3 Components Library from Market Place
2) After successful installation, restart the server if it is already running. 
3) From the home menu click on "Create New" -> "CDE Dashboard"

4) Layout section :
#) Design the layout as shown in above image
2 rows, first row is for dashboard title, 2nd row is for dashboard content(table & chord diagram). 
Adjust the layout if you have any parameters to display 
(This dashboard is not associated with any parameters). 

5) Data sources section :
Connect to postgre SQL database as shown in below image and test the connection using CDA editor and preview the query written. 

( Click on image to get best view)
6) Components section :
#) From D3 Components section select "D3 Component" as shown in below image
#) Fill the Component properties as shown in below image

(Click on image to get best view)

#) Core part : Convert SQL result set to matrix format and write D3 script for chord diagram
Copy paste below code in "Custom Chart Script" code section (later modify it as per your requirement)


function f(dataset){

var matrix = [];

for(var i=0; i < dataset.resultset.length; i++){
    var dataObject=[];
    /*
    dataObject.a = dataset.resultset[i][0];
    dataObject.b = dataset.resultset[i][1];
   alert(dataObject.a);
   matrix.push(dataObject);
   */
   matrix.push([dataset.resultset[i][0],dataset.resultset[i][1],dataset.resultset[i][2],dataset.resultset[i][3]]);

    alert([dataset.resultset[i][0]]);
   alert([dataset.resultset[i][1]]);
   alert([dataset.resultset[i][2]]);
   alert([dataset.resultset[i][3]]);
    }
  

/*   
var matrix = [
  [11975,  5871, 8916, 2868],
  [ 1951, 10048, 2060, 6171],
  [ 8010, 16145, 8090, 8045],
  [ 1013,   990,  940, 6907]
];
*/

var chord = d3.layout.chord()
    .padding(.05)
    .sortSubgroups(d3.descending)
    .matrix(matrix);

var width = 860,
    height = 400,
    innerRadius = Math.min(width, height) * .41,
    outerRadius = innerRadius * 1.1;

var fill = d3.scale.ordinal()
    .domain(d3.range(4))
    .range(["#000000", "#FFDD89", "#957244", "#F26223"]);

var svg = d3.select("#"+this.htmlObject).append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

svg.append("g").selectAll("path")
    .data(chord.groups)
  .enter().append("path")
    .style("fill", function(d) { return fill(d.index); })
    .style("stroke", function(d) { return fill(d.index); })
    .attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius))
    .on("mouseover", fade(.1))
    .on("mouseout", fade(1));

var ticks = svg.append("g").selectAll("g")
    .data(chord.groups)
  .enter().append("g").selectAll("g")
    .data(groupTicks)
  .enter().append("g")
    .attr("transform", function(d) {
      return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
          + "translate(" + outerRadius + ",0)";
    });

ticks.append("line")
    .attr("x1", 1)
    .attr("y1", 0)
    .attr("x2", 5)
    .attr("y2", 0)
    .style("stroke", "#000");

ticks.append("text")
    .attr("x", 8)
    .attr("dy", ".35em")
    .attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180)translate(-16)" : null; })
    .style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
    .text(function(d) { return d.label; });

svg.append("g")
    .attr("class", "chord")
  .selectAll("path")
    .data(chord.chords)
  .enter().append("path")
    .attr("d", d3.svg.chord().radius(innerRadius))
    .style("fill", function(d) { return fill(d.target.index); })
    .style("opacity", 1);

// Returns an array of tick angles and labels, given a group.
function groupTicks(d) {
  var k = (d.endAngle - d.startAngle) / d.value;
  return d3.range(0, d.value, 1000).map(function(v, i) {
    return {
      angle: v * k + d.startAngle,
      label: i % 5 ? null : v / 1000 + "k"
    };
  });
}

// Returns an event handler for fading a given chord group.
function fade(opacity) {
  return function(g, i) {
    svg.selectAll(".chord path")
        .filter(function(d) { return d.source.index != i && d.target.index != i; })
      .transition()
        .style("opacity", opacity);
  };
}


}

#) Now, save your dashboard and preview it.

#) CSS used for this dashboard in "Resources" section is

body{
    margin-top:30px;
    font: 10px sans-serif;
}

#row2Col1Table_wrapper{
          padding-top: 50px;
}
.chord path {
    fill-opacity: .67;
    stroke: #000;
    stroke-width: .5px;
}

.label{
    font : 10px sans-serif;
}  


I hope this post helps some one in the community to get start with Custom D3 charts. 

In future posts you may find interesting visualizations in this site. Stay tune for updates. 


Download this example :
Click Me

Deployment Procedure:
Upload this example using PUC and in the data sources change the postgresql url and passwords as per your requirement.


 References for this post : 

1) http://diethardsteiner.github.io/dashboards/2014/10/15/CCC-Add-Event-Info-to-your-Charts.html 
2) https://bl.ocks.org/mbostock/4062006 
3) http://bl.ocks.org/mbostock/1046712 
4) http://www.delimited.io/blog/2013/12/8/chord-diagrams-in-d3

- Sadakar Pochampalli