|
<!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> |
Hi Naushad,
Saw your dashboard, very good and I tried to adapt it to my own use, but one last hurdle, I can't get the histogram2 (2nd single pillar histogram) to shrink and rise with different values being fed, look at the
.attr("height", function(d) { return hG2Dim.h - y(d[1]); }) statement and can't figure why it's not responding.
Any ideas?
P.S. My script is below
Many Thanks
Andy
<style> body{ width:100% auto; 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>