Skip to content

Instantly share code, notes, and snippets.

@sundlee
Last active January 3, 2016 01:31
Show Gist options
  • Save sundlee/a2cb7d4672d98d6a80ee to your computer and use it in GitHub Desktop.
Save sundlee/a2cb7d4672d98d6a80ee to your computer and use it in GitHub Desktop.
DashBoard

A simple example of creating a dashboard. This example was created for the paper Interactive HTML Reporting Using D3 at the MWSUG2014 conference.

Hovering over a bar in histogram will modify the pie chart and legend. Hovering over pie slice will update the histogram.

This is from http://bl.ocks.org/NPashaP/96447623ef4d342ee09b

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
width:1060px;
margin:50px auto;
}
path { stroke: #fff; }
path:hover { opacity:0.9; }
rect:hover { fill:blue; }
.axis { font: 10px sans-serif; }
.legend tr { border-bottom:1px solid grey; }
.legend tr:first-child { border-top:1px solid grey; }
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path { display: none; }
.legend {
margin-bottom:76px;
display:inline-block;
border-collapse: collapse;
border-spacing: 0px;
}
.legend td {
padding:4px 5px;
vertical-align:bottom;
}
.legendFreq, .legendPerc {
align:right;
width:50px;
}
</style>
<body>
<div id='dashboard'></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
function dashboard(id, fData) {
var barColor = 'steelblue';
function segColor(c) { return {low:"#807dba", mid:"#e08214",high:"#41ab5d"}[c]; }
/* compute total for each state */
fData.forEach(function(d) { d.total = d.freq.low + d.freq.mid + d.freq.high; });
/* function to handle histogram */
function histoGram(fD) {
var hG={}, hGDim = { t: 60, r: 0, b: 30, l: 0 };
hGDim.w = 500 - hGDim.l - hGDim.r,
hGDim.h = 300 - hGDim.t - hGDim.b;
/* create svg for histogram */
var hGsvg = d3.select(id).append("svg")
.attr("width", hGDim.w + hGDim.l + hGDim.r)
.attr("height", hGDim.h + hGDim.t + hGDim.b).append("g")
.attr("transform", "translate(" + hGDim.l + "," + hGDim.t + ")");
/* create function for x-axis mapping */
var x = d3.scale.ordinal().rangeRoundBands([0, hGDim.w], 0.1)
.domain(fD.map(function(d) { return d[0]; }));
/* Add x-axis to the histogram svg */
hGsvg.append("g").attr("class", "x axis")
.attr("transform", "translate(0," + hGDim.h + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
/* Create function for y-axis map */
var y = d3.scale.linear().range([hGDim.h, 0])
.domain([0, d3.max(fD, function(d) { return d[1]; })]);
/* Create bars for histogram to contain rectangles and freq labels */
var bars = hGsvg.selectAll(".bar").data(fD).enter()
.append("g").attr("class", "bar");
/* create the rectangles */
bars.append("rect")
.attr("x", function(d) { return x(d[0]); })
.attr("y", function(d) { return y(d[1]); })
.attr("width", x.rangeBand())
.attr("height", function(d) { return hGDim.h - y(d[1]); })
.attr('fill',barColor)
.on("mouseover",mouseover) /* mouseover is defined below */
.on("mouseout",mouseout); /* mouseout is defined below */
/* Create the frequency labels above the rectangles. */
bars.append("text").text(function(d) { return d3.format(",")(d[1])})
.attr("x", function(d) { return x(d[0]) + x.rangeBand() / 2; })
.attr("y", function(d) { return y(d[1]) - 5; })
.attr("text-anchor", "middle");
function mouseover(d) { /* utility function to be called on mouseover */
/* filter for selected state */
var st = fData.filter(function(s) { return s.State == d[0]; })[0],
nD = d3.keys(st.freq).map(function(s) { return {type:s, freq:st.freq[s]}; });
/* call update functions of pie-chart and legend */
pC.update(nD);
leg.update(nD);
}
function mouseout(d) { /* utility function to be called on mouseout */
/* reset the pie-chart and legend */
pC.update(tF);
leg.update(tF);
}
/* create function to update the bars. This will be used by pie-chart */
hG.update = function(nD, color) {
/* update the domain of the y-axis map to reflect change in frequencies */
y.domain([0, d3.max(nD, function(d) { return d[1]; })]);
/* Attach the new data to the bars */
var bars = hGsvg.selectAll(".bar").data(nD);
/* transition the height and color of rectangles */
bars.select("rect").transition().duration(500)
.attr("y", function(d) {return y(d[1]); })
.attr("height", function(d) { return hGDim.h - y(d[1]); })
.attr("fill", color);
/* transition the frequency labels location and change value */
bars.select("text").transition().duration(500)
.text(function(d) { return d3.format(",")(d[1])})
.attr("y", function(d) { return y(d[1]) - 5; });
}
return hG;
}
/* function to handle pieChart */
function pieChart(pD) {
var pC ={}, pieDim = { w:250, h:250 };
pieDim.r = Math.min(pieDim.w, pieDim.h) / 2;
/* create svg for pie chart */
var piesvg = d3.select(id).append("svg")
.attr("width", pieDim.w).attr("height", pieDim.h).append("g")
.attr("transform", "translate(" + pieDim.w / 2 + "," + pieDim.h / 2 +")");
/* create function to draw the arcs of the pie slices */
var arc = d3.svg.arc().outerRadius(pieDim.r - 10).innerRadius(0);
/* create a function to compute the pie slice angles */
var pie = d3.layout.pie().sort(null).value(function(d) { return d.freq; });
/* Draw the pie slices */
piesvg.selectAll("path").data(pie(pD)).enter().append("path").attr("d", arc)
.each(function(d) { this._current = d; })
.style("fill", function(d) { return segColor(d.data.type); })
.on("mouseover",mouseover).on("mouseout",mouseout);
/* create function to update pie-chart. This will be used by histogram */
pC.update = function(nD) {
piesvg.selectAll("path").data(pie(nD)).transition().duration(500)
.attrTween("d", arcTween);
}
/* Utility function to be called on mouseover a pie slice */
function mouseover(d) {
/* call the update function of histogram with new data */
hG.update(fData.map(function(v) {
return [v.State,v.freq[d.data.type]];
}),segColor(d.data.type));
}
/* Utility function to be called on mouseout a pie slice */
function mouseout(d) {
/* call the update function of histogram with all data */
hG.update(fData.map(function(v) {
return [v.State, v.total];
}), barColor);
}
/* Animating the pie-slice requiring a custom function which specifies */
/* how the intermediate paths should be drawn */
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) { return arc(i(t)); };
}
return pC;
}
/* function to handle legend */
function legend(lD) {
var leg = {};
/* create table for legend */
var legend = d3.select(id).append("table").attr('class','legend');
/* create one row per segment */
var tr = legend.append("tbody").selectAll("tr").data(lD).enter().append("tr");
/* create the first column for each segment */
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("width", '16').attr("height", '16')
.attr("fill",function(d) { return segColor(d.type); });
/* create the second column for each segment */
tr.append("td").text(function(d) { return d.type; });
/* create the third column for each segment */
tr.append("td").attr("class",'legendFreq')
.text(function(d) { return d3.format(",")(d.freq); });
/* create the fourth column for each segment */
tr.append("td").attr("class",'legendPerc')
.text(function(d) { return getLegend(d,lD); });
/* Utility function to be used to update the legend */
leg.update = function(nD) {
/* update the data attached to the row elements */
var l = legend.select("tbody").selectAll("tr").data(nD);
/* update the frequencies */
l.select(".legendFreq").text(function(d) { return d3.format(",")(d.freq); });
/* update the percentage column */
l.select(".legendPerc").text(function(d) { return getLegend(d,nD); });
}
function getLegend(d,aD) { /* Utility function to compute percentage */
return d3.format("%")(d.freq/d3.sum(aD.map(function(v) { return v.freq; })));
}
return leg;
}
/* calculate total frequency by segment for all state */
var tF = ['low','mid','high'].map(function(d) {
return {type:d, freq: d3.sum(fData.map(function(t) { return t.freq[d]; }))};
});
/* calculate total frequency by state for all segment */
var sF = fData.map(function(d){return [d.State,d.total];});
var hG = histoGram(sF), /* create the histogram */
pC = pieChart(tF), /* create the pie-chart */
leg= legend(tF); /* create the legend */
}
</script>
<script>
var freqData = [
{State:'AL',freq:{low:4786, mid:1319, high:249}}
,{State:'AZ',freq:{low:1101, mid:412, high:674}}
,{State:'CT',freq:{low:932, mid:2149, high:418}}
,{State:'DE',freq:{low:832, mid:1152, high:1862}}
,{State:'FL',freq:{low:4481, mid:3304, high:948}}
,{State:'GA',freq:{low:1619, mid:167, high:1063}}
,{State:'IA',freq:{low:1819, mid:247, high:1203}}
,{State:'IL',freq:{low:4498, mid:3852, high:942}}
,{State:'IN',freq:{low:797, mid:1849, high:1534}}
,{State:'KS',freq:{low:162, mid:379, high:471}}
];
dashboard('#dashboard', freqData);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment